pref: separate text outline rendering
This commit is contained in:
parent
494a4d05f9
commit
a7c4e9402b
|
|
@ -37,6 +37,13 @@ public:
|
|||
STDMETHOD(CreateOutlineGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppOutlineGeo, _In_ DWRITE_GLYPH_RUN const* glyphRun, float fOriginX, float fOriginY);
|
||||
|
||||
STDMETHOD(CreateStrikethroughGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppStrikethroughGeo, _In_ DWRITE_STRIKETHROUGH const* strikethrough, float fOriginX,
|
||||
float fOriginY);
|
||||
|
||||
STDMETHOD(CreateUnderlineGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppUnderlineGeo, _In_ DWRITE_UNDERLINE const* underline, float fOriginX, float fOriginY);
|
||||
|
||||
// IUnknown methods
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef();
|
||||
|
|
@ -46,8 +53,9 @@ private:
|
|||
unsigned long cRefCount_;
|
||||
ComPtr<ID2D1Factory> pFactory_;
|
||||
|
||||
// Outline geometry cache
|
||||
Map<std::tuple<const DWRITE_GLYPH_RUN*, float, float>, ComPtr<ID2D1Geometry>> outlineCache_;
|
||||
Map<std::tuple<const DWRITE_GLYPH_RUN*, float, float>, ComPtr<ID2D1Geometry>> outlineCache_;
|
||||
Map<std::tuple<const DWRITE_STRIKETHROUGH*, float, float>, ComPtr<ID2D1Geometry>> strikethroughCache_;
|
||||
Map<std::tuple<const DWRITE_UNDERLINE*, float, float>, ComPtr<ID2D1Geometry>> underlineCache_;
|
||||
};
|
||||
|
||||
HRESULT ITextDrawingEffect::Create(_Out_ ITextDrawingEffect** ppTextDrawingEffect, _In_ ID2D1Factory* pFactory)
|
||||
|
|
@ -160,6 +168,115 @@ STDMETHODIMP TextDrawingEffect::CreateOutlineGeomerty(_Out_ ID2D1Geometry**
|
|||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP TextDrawingEffect::CreateStrikethroughGeomerty(_Out_ ID2D1Geometry** ppStrikethroughGeo,
|
||||
_In_ DWRITE_STRIKETHROUGH const* strikethrough,
|
||||
float fOriginX, float fOriginY)
|
||||
{
|
||||
auto cache = strikethroughCache_.find(std::make_tuple(strikethrough, fOriginX, fOriginY));
|
||||
if (cache != strikethroughCache_.end())
|
||||
{
|
||||
auto& pStrikethroughGeo = cache->second;
|
||||
if (pStrikethroughGeo)
|
||||
{
|
||||
// Use cached geometry
|
||||
pStrikethroughGeo->AddRef();
|
||||
DX::SafeRelease(*ppStrikethroughGeo);
|
||||
(*ppStrikethroughGeo) = pStrikethroughGeo.Get();
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
ComPtr<ID2D1Geometry> pStrikethroughGeo;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<ID2D1RectangleGeometry> pRectangleGeometry;
|
||||
|
||||
D2D1_RECT_F rect = D2D1::RectF(0, strikethrough->offset, strikethrough->width,
|
||||
strikethrough->offset + strikethrough->thickness);
|
||||
hr = pFactory_->CreateRectangleGeometry(&rect, &pRectangleGeometry);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
const auto matrix = D2D1::Matrix3x2F(1.0f, 0.0f, 0.0f, 1.0f, fOriginX, fOriginY);
|
||||
|
||||
ComPtr<ID2D1TransformedGeometry> pTransformedGeometry;
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pStrikethroughGeo = pTransformedGeometry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pStrikethroughGeo->AddRef();
|
||||
DX::SafeRelease(*ppStrikethroughGeo);
|
||||
(*ppStrikethroughGeo) = pStrikethroughGeo.Get();
|
||||
|
||||
strikethroughCache_.insert(
|
||||
std::make_pair(std::make_tuple(strikethrough, fOriginX, fOriginY), pStrikethroughGeo));
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP TextDrawingEffect::CreateUnderlineGeomerty(_Out_ ID2D1Geometry** ppUnderlineGeo,
|
||||
_In_ DWRITE_UNDERLINE const* underline, float fOriginX,
|
||||
float fOriginY)
|
||||
{
|
||||
auto cache = underlineCache_.find(std::make_tuple(underline, fOriginX, fOriginY));
|
||||
if (cache != underlineCache_.end())
|
||||
{
|
||||
auto& pUnderlineGeo = cache->second;
|
||||
if (pUnderlineGeo)
|
||||
{
|
||||
// Use cached geometry
|
||||
pUnderlineGeo->AddRef();
|
||||
DX::SafeRelease(*ppUnderlineGeo);
|
||||
(*ppUnderlineGeo) = pUnderlineGeo.Get();
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
ComPtr<ID2D1Geometry> pUnderlineGeo;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<ID2D1RectangleGeometry> pRectangleGeometry;
|
||||
|
||||
D2D1_RECT_F rect =
|
||||
D2D1::RectF(0, underline->offset, underline->width, underline->offset + underline->thickness);
|
||||
hr = pFactory_->CreateRectangleGeometry(&rect, &pRectangleGeometry);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
const auto matrix = D2D1::Matrix3x2F(1.0f, 0.0f, 0.0f, 1.0f, fOriginX, fOriginY);
|
||||
|
||||
ComPtr<ID2D1TransformedGeometry> pTransformedGeometry;
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pUnderlineGeo = pTransformedGeometry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pUnderlineGeo->AddRef();
|
||||
DX::SafeRelease(*ppUnderlineGeo);
|
||||
(*ppUnderlineGeo) = pUnderlineGeo.Get();
|
||||
|
||||
underlineCache_.insert(std::make_pair(std::make_tuple(underline, fOriginX, fOriginY), pUnderlineGeo));
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(unsigned long) TextDrawingEffect::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&cRefCount_);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,13 @@ public:
|
|||
|
||||
STDMETHOD(CreateOutlineGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppOutlineGeo, _In_ DWRITE_GLYPH_RUN const* glyphRun, float fOriginX, float fOriginY) PURE;
|
||||
|
||||
STDMETHOD(CreateStrikethroughGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppStrikethroughGeo, _In_ DWRITE_STRIKETHROUGH const* strikethrough, float fOriginX,
|
||||
float fOriginY) PURE;
|
||||
|
||||
STDMETHOD(CreateUnderlineGeomerty)
|
||||
(_Out_ ID2D1Geometry** ppUnderlineGeo, _In_ DWRITE_UNDERLINE const* underline, float fOriginX, float fOriginY) PURE;
|
||||
};
|
||||
} // namespace directx
|
||||
} // namespace graphics
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ public:
|
|||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
private:
|
||||
bool bOutlineRendering_;
|
||||
unsigned long cRefCount_;
|
||||
uint32_t cPrimitivesCount_;
|
||||
float fDefaultOutlineWidth_;
|
||||
|
|
@ -111,7 +112,8 @@ HRESULT ITextRenderer::Create(_Out_ ITextRenderer** ppTextRenderer, _In_ ID2D1De
|
|||
}
|
||||
|
||||
TextRenderer::TextRenderer()
|
||||
: cRefCount_(0)
|
||||
: bOutlineRendering_(false)
|
||||
, cRefCount_(0)
|
||||
, cPrimitivesCount_(0)
|
||||
, fDefaultOutlineWidth_(1)
|
||||
{
|
||||
|
|
@ -150,8 +152,16 @@ STDMETHODIMP TextRenderer::DrawTextLayout(_In_ IDWriteTextLayout* pTextLayout, f
|
|||
pDefaultOutlineBrush_ = pDefaultOutlineBrush;
|
||||
fDefaultOutlineWidth_ = fDefaultOutlineWidth;
|
||||
pDefaultStrokeStyle_ = pDefaultStrokeStyle;
|
||||
bOutlineRendering_ = pDefaultOutlineBrush_ != nullptr;
|
||||
|
||||
return pTextLayout->Draw(nullptr, this, fOriginX, fOriginY);
|
||||
HRESULT hr = pTextLayout->Draw(nullptr, this, fOriginX, fOriginY);
|
||||
if (SUCCEEDED(hr) && bOutlineRendering_)
|
||||
{
|
||||
bOutlineRendering_ = false;
|
||||
|
||||
hr = pTextLayout->Draw(nullptr, this, fOriginX, fOriginY);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP TextRenderer::DrawGlyphRun(__maybenull void* clientDrawingContext, float baselineOriginX,
|
||||
|
|
@ -164,37 +174,41 @@ STDMETHODIMP TextRenderer::DrawGlyphRun(__maybenull void* clientDrawingContext,
|
|||
KGE_NOT_USED(measuringMode);
|
||||
KGE_NOT_USED(glyphRunDescription);
|
||||
|
||||
ComPtr<ITextDrawingEffect> pTextDrawingEffect;
|
||||
|
||||
HRESULT hr = clientDrawingEffect->QueryInterface(&pTextDrawingEffect);
|
||||
|
||||
if (pDefaultOutlineBrush_)
|
||||
HRESULT hr = S_OK;
|
||||
if (!bOutlineRendering_)
|
||||
{
|
||||
ComPtr<ID2D1Geometry> pOutlineGeometry;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
if (pDefaultFillBrush_)
|
||||
{
|
||||
hr = pTextDrawingEffect->CreateOutlineGeomerty(&pOutlineGeometry, glyphRun, baselineOriginX,
|
||||
baselineOriginY);
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pContext_->DrawGlyphRun(D2D1::Point2F(baselineOriginX, baselineOriginY), glyphRun,
|
||||
pDefaultFillBrush_.Get());
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pContext_->DrawGeometry(pOutlineGeometry.Get(), pDefaultOutlineBrush_.Get(), fDefaultOutlineWidth_,
|
||||
pDefaultStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pDefaultFillBrush_)
|
||||
else
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
if (pDefaultOutlineBrush_)
|
||||
{
|
||||
pContext_->DrawGlyphRun(D2D1::Point2F(baselineOriginX, baselineOriginY), glyphRun,
|
||||
pDefaultFillBrush_.Get());
|
||||
ComPtr<ITextDrawingEffect> pTextDrawingEffect;
|
||||
hr = clientDrawingEffect->QueryInterface(&pTextDrawingEffect);
|
||||
|
||||
++cPrimitivesCount_;
|
||||
ComPtr<ID2D1Geometry> pOutlineGeometry;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pTextDrawingEffect->CreateOutlineGeomerty(&pOutlineGeometry, glyphRun, baselineOriginX,
|
||||
baselineOriginY);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pContext_->DrawGeometry(pOutlineGeometry.Get(), pDefaultOutlineBrush_.Get(), fDefaultOutlineWidth_,
|
||||
pDefaultStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
|
|
@ -208,51 +222,37 @@ STDMETHODIMP TextRenderer::DrawUnderline(__maybenull void* clientDrawingContext,
|
|||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
ComPtr<ID2D1RectangleGeometry> pRectangleGeometry;
|
||||
ComPtr<ID2D1TransformedGeometry> pTransformedGeometry;
|
||||
ComPtr<ID2D1Brush> pCurrentFillBrush;
|
||||
ComPtr<ITextDrawingEffect> pTextDrawingEffect;
|
||||
hr = clientDrawingEffect->QueryInterface(&pTextDrawingEffect);
|
||||
|
||||
if (clientDrawingEffect)
|
||||
ComPtr<ID2D1Geometry> pUnderlineGeometry;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = clientDrawingEffect->QueryInterface<ID2D1Brush>(&pCurrentFillBrush);
|
||||
}
|
||||
else
|
||||
{
|
||||
pCurrentFillBrush = pDefaultFillBrush_;
|
||||
hr = pTextDrawingEffect->CreateUnderlineGeomerty(&pUnderlineGeometry, underline, baselineOriginX,
|
||||
baselineOriginY);
|
||||
}
|
||||
|
||||
if (pCurrentFillBrush || pDefaultOutlineBrush_)
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
if (!bOutlineRendering_)
|
||||
{
|
||||
D2D1_RECT_F rect =
|
||||
D2D1::RectF(0, underline->offset, underline->width, underline->offset + underline->thickness);
|
||||
|
||||
hr = pFactory_->CreateRectangleGeometry(&rect, &pRectangleGeometry);
|
||||
if (pDefaultFillBrush_)
|
||||
{
|
||||
pContext_->FillGeometry(pUnderlineGeometry.Get(), pDefaultFillBrush_.Get());
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
else
|
||||
{
|
||||
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY);
|
||||
if (pDefaultOutlineBrush_)
|
||||
{
|
||||
pContext_->DrawGeometry(pUnderlineGeometry.Get(), pDefaultOutlineBrush_.Get(),
|
||||
fDefaultOutlineWidth_, pDefaultStrokeStyle_.Get());
|
||||
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pDefaultOutlineBrush_)
|
||||
{
|
||||
pContext_->DrawGeometry(pTransformedGeometry.Get(), pDefaultOutlineBrush_.Get(), fDefaultOutlineWidth_,
|
||||
pDefaultStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pCurrentFillBrush)
|
||||
{
|
||||
pContext_->FillGeometry(pTransformedGeometry.Get(), pCurrentFillBrush.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
|
@ -264,51 +264,37 @@ STDMETHODIMP TextRenderer::DrawStrikethrough(__maybenull void* clientDrawingCont
|
|||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
ComPtr<ID2D1RectangleGeometry> pRectangleGeometry;
|
||||
ComPtr<ID2D1TransformedGeometry> pTransformedGeometry;
|
||||
ComPtr<ID2D1Brush> pCurrentFillBrush;
|
||||
ComPtr<ITextDrawingEffect> pTextDrawingEffect;
|
||||
hr = clientDrawingEffect->QueryInterface(&pTextDrawingEffect);
|
||||
|
||||
if (clientDrawingEffect)
|
||||
ComPtr<ID2D1Geometry> pStrikethroughGeometry;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = clientDrawingEffect->QueryInterface<ID2D1Brush>(&pCurrentFillBrush);
|
||||
}
|
||||
else
|
||||
{
|
||||
pCurrentFillBrush = pDefaultFillBrush_;
|
||||
hr = pTextDrawingEffect->CreateStrikethroughGeomerty(&pStrikethroughGeometry, strikethrough, baselineOriginX,
|
||||
baselineOriginY);
|
||||
}
|
||||
|
||||
if (pCurrentFillBrush || pDefaultOutlineBrush_)
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
if (!bOutlineRendering_)
|
||||
{
|
||||
D2D1_RECT_F rect = D2D1::RectF(0, strikethrough->offset, strikethrough->width,
|
||||
strikethrough->offset + strikethrough->thickness);
|
||||
|
||||
hr = pFactory_->CreateRectangleGeometry(&rect, &pRectangleGeometry);
|
||||
if (pDefaultFillBrush_)
|
||||
{
|
||||
pContext_->FillGeometry(pStrikethroughGeometry.Get(), pDefaultFillBrush_.Get());
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
else
|
||||
{
|
||||
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY);
|
||||
if (pDefaultOutlineBrush_)
|
||||
{
|
||||
pContext_->DrawGeometry(pStrikethroughGeometry.Get(), pDefaultOutlineBrush_.Get(),
|
||||
fDefaultOutlineWidth_, pDefaultStrokeStyle_.Get());
|
||||
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pDefaultOutlineBrush_)
|
||||
{
|
||||
pContext_->DrawGeometry(pTransformedGeometry.Get(), pDefaultOutlineBrush_.Get(), fDefaultOutlineWidth_,
|
||||
pDefaultStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pCurrentFillBrush)
|
||||
{
|
||||
pContext_->FillGeometry(pTransformedGeometry.Get(), pCurrentFillBrush.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue