Switched to a custom IDWriteTextRenderer, which will be necessary for some of our text attributes. More TODO.
This commit is contained in:
parent
efb7d5b21d
commit
9cc8b03516
|
@ -202,8 +202,9 @@ if(BUILD_SHARED_LIBS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
macro(_add_exec _name)
|
macro(_add_exec _name)
|
||||||
|
# TODOTODO re-add WIN32 when merging back
|
||||||
add_executable(${_name}
|
add_executable(${_name}
|
||||||
WIN32 EXCLUDE_FROM_ALL
|
EXCLUDE_FROM_ALL
|
||||||
${ARGN})
|
${ARGN})
|
||||||
target_link_libraries(${_name} libui ${_LIBUI_STATIC_RES})
|
target_link_libraries(${_name} libui ${_LIBUI_STATIC_RES})
|
||||||
_target_link_options_private(${_name}
|
_target_link_options_private(${_name}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
// 20 january 2017
|
// 20 january 2017
|
||||||
#include "drawtext.h"
|
#include "drawtext.h"
|
||||||
|
|
||||||
// TODO double-check ligatures
|
// TODO double-check ligatures on all platforms to make sure we can place the cursor at the right place
|
||||||
// TODO the hiding and showing does not work properly on GTK+
|
// TODO the hiding and showing does not work properly on GTK+
|
||||||
// TODO using the arrow keys allows us to walk back to the end of the line; IIRC arrow keys shouldn't do that
|
// TODO using the arrow keys allows us to walk back to the end of the line on some platforms (TODO which?); IIRC arrow keys shouldn't do that
|
||||||
|
// TODO make sure to check the cursor positions of RTL on all platforms
|
||||||
|
|
||||||
static const char *text =
|
static const char *text =
|
||||||
"Each of the glyphs an end user interacts with are called graphemes. "
|
"Each of the glyphs an end user interacts with are called graphemes. "
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
// - 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?
|
||||||
|
|
||||||
|
// TODO verify our renderer is correct, especially with regards to snapping
|
||||||
|
|
||||||
struct uiDrawTextLayout {
|
struct uiDrawTextLayout {
|
||||||
IDWriteTextFormat *format;
|
IDWriteTextFormat *format;
|
||||||
IDWriteTextLayout *layout;
|
IDWriteTextLayout *layout;
|
||||||
|
@ -240,23 +242,161 @@ static ID2D1SolidColorBrush *mkSolidBrush(ID2D1RenderTarget *rt, double r, doubl
|
||||||
return brush;
|
return brush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// some of the stuff we want to do isn't possible with what DirectWrite provides itself; we need to do it ourselves
|
||||||
|
// this is based on http://www.charlespetzold.com/blog/2014/01/Character-Formatting-Extensions-with-DirectWrite.html
|
||||||
|
class textRenderer : public IDWriteTextRenderer {
|
||||||
|
ULONG refcount;
|
||||||
|
ID2D1RenderTarget *rt;
|
||||||
|
BOOL snap;
|
||||||
|
IUnknown *black;
|
||||||
|
public:
|
||||||
|
textRenderer(ID2D1RenderTarget *rt, BOOL snap, IUnknown *black)
|
||||||
|
{
|
||||||
|
this->refcount = 1;
|
||||||
|
this->rt = rt;
|
||||||
|
this->snap = snap;
|
||||||
|
this->black = black;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IUnknown
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
|
||||||
|
{
|
||||||
|
if (ppvObject == NULL)
|
||||||
|
return E_POINTER;
|
||||||
|
if (riid == IID_IUnknown ||
|
||||||
|
riid == __uuidof (IDWritePixelSnapping) ||
|
||||||
|
riid == __uuidof (IDWriteTextRenderer)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDWritePixelSnapping
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform(void *clientDrawingContext, DWRITE_MATRIX *transform)
|
||||||
|
{
|
||||||
|
D2D1_MATRIX_3X2_F d2dtf;
|
||||||
|
|
||||||
|
if (transform == NULL)
|
||||||
|
return E_POINTER;
|
||||||
|
this->rt->GetTransform(&d2dtf);
|
||||||
|
transform->m11 = d2dtf._11;
|
||||||
|
transform->m12 = d2dtf._12;
|
||||||
|
transform->m21 = d2dtf._21;
|
||||||
|
transform->m22 = d2dtf._22;
|
||||||
|
transform->dx = d2dtf._31;
|
||||||
|
transform->dy = d2dtf._32;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip(void *clientDrawingContext, FLOAT *pixelsPerDip)
|
||||||
|
{
|
||||||
|
FLOAT dpix, dpiy;
|
||||||
|
|
||||||
|
if (pixelsPerDip == NULL)
|
||||||
|
return E_POINTER;
|
||||||
|
this->rt->GetDpi(&dpix, &dpiy);
|
||||||
|
*pixelsPerDip = dpix / 96;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(void *clientDrawingContext, BOOL *isDisabled)
|
||||||
|
{
|
||||||
|
if (isDisabled == NULL)
|
||||||
|
return E_POINTER;
|
||||||
|
*isDisabled = !this->snap;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDWriteTextRenderer
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, const DWRITE_GLYPH_RUN *glyphRun, const DWRITE_GLYPH_RUN_DESCRIPTION *glyphRunDescription, IUnknown *clientDrawingEffect)
|
||||||
|
{
|
||||||
|
D2D1_POINT_2F baseline;
|
||||||
|
|
||||||
|
baseline.x = baselineOriginX;
|
||||||
|
baseline.y = baselineOriginY;
|
||||||
|
if (clientDrawingEffect == NULL)
|
||||||
|
clientDrawingEffect = black;
|
||||||
|
this->rt->DrawGlyphRun(
|
||||||
|
baseline,
|
||||||
|
glyphRun,
|
||||||
|
(ID2D1Brush *) clientDrawingEffect,
|
||||||
|
measuringMode);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE DrawInlineObject(void *clientDrawingContext, FLOAT originX, FLOAT originY, IDWriteInlineObject *inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown *clientDrawingEffect)
|
||||||
|
{
|
||||||
|
if (inlineObject == NULL)
|
||||||
|
return E_POINTER;
|
||||||
|
return inlineObject->Draw(clientDrawingContext, this,
|
||||||
|
originX, originY,
|
||||||
|
isSideways, isRightToLeft,
|
||||||
|
clientDrawingEffect);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *clientDrawingEffect)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual HRESULT DrawUnderline(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_UNDERLINE *underline, IUnknown *clientDrawingEffect)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
D2D1_POINT_2F pt;
|
D2D1_POINT_2F pt;
|
||||||
ID2D1Brush *black;
|
ID2D1Brush *black;
|
||||||
|
textRenderer *renderer;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
// 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 = mkSolidBrush(c->rt, 0.0, 0.0, 0.0, 1.0);
|
black = mkSolidBrush(c->rt, 0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
#if 0
|
||||||
pt.x = x;
|
pt.x = x;
|
||||||
pt.y = y;
|
pt.y = y;
|
||||||
// TODO D2D1_DRAW_TEXT_OPTIONS_NO_SNAP?
|
// TODO D2D1_DRAW_TEXT_OPTIONS_NO_SNAP?
|
||||||
// TODO D2D1_DRAW_TEXT_OPTIONS_CLIP?
|
// TODO D2D1_DRAW_TEXT_OPTIONS_CLIP?
|
||||||
// TODO when setting 8.1 as minimum (TODO verify), D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT?
|
// TODO LONGTERM when setting 8.1 as minimum (TODO verify), D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT?
|
||||||
// TODO what is our pixel snapping setting related to the OPTIONS enum values?
|
// TODO what is our pixel snapping setting related to the OPTIONS enum values?
|
||||||
c->rt->DrawTextLayout(pt, tl->layout, black, D2D1_DRAW_TEXT_OPTIONS_NONE);
|
c->rt->DrawTextLayout(pt, tl->layout, black, D2D1_DRAW_TEXT_OPTIONS_NONE);
|
||||||
|
#else
|
||||||
|
renderer = new textRenderer(c->rt,
|
||||||
|
TRUE, // TODO FALSE for no-snap?
|
||||||
|
black);
|
||||||
|
hr = tl->layout->Draw(NULL,
|
||||||
|
renderer,
|
||||||
|
x, y);
|
||||||
|
if (hr != S_OK)
|
||||||
|
logHRESULT(L"error drawing IDWriteTextLayout", hr);
|
||||||
|
renderer->Release();
|
||||||
|
#endif
|
||||||
|
|
||||||
black->Release();
|
black->Release();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue