dwrite: Implement outline mode for DrawGlyphRun().

oldstable
Nikolay Sivov 2015-08-13 18:55:52 +03:00 committed by Alexandre Julliard
parent 76c321d5e6
commit 204d46c674
2 changed files with 159 additions and 10 deletions

View File

@ -45,6 +45,7 @@ struct dib_data {
struct rendertarget {
IDWriteBitmapRenderTarget1 IDWriteBitmapRenderTarget1_iface;
ID2D1SimplifiedGeometrySink ID2D1SimplifiedGeometrySink_iface;
LONG ref;
IDWriteFactory *factory;
@ -99,11 +100,111 @@ static inline struct rendertarget *impl_from_IDWriteBitmapRenderTarget1(IDWriteB
return CONTAINING_RECORD(iface, struct rendertarget, IDWriteBitmapRenderTarget1_iface);
}
static inline struct rendertarget *impl_from_ID2D1SimplifiedGeometrySink(ID2D1SimplifiedGeometrySink *iface)
{
return CONTAINING_RECORD(iface, struct rendertarget, ID2D1SimplifiedGeometrySink_iface);
}
static inline struct gdiinterop *impl_from_IDWriteGdiInterop(IDWriteGdiInterop *iface)
{
return CONTAINING_RECORD(iface, struct gdiinterop, IDWriteGdiInterop_iface);
}
static HRESULT WINAPI rendertarget_sink_QueryInterface(ID2D1SimplifiedGeometrySink *iface, REFIID riid, void **obj)
{
if (IsEqualIID(riid, &IID_ID2D1SimplifiedGeometrySink) ||
IsEqualIID(riid, &IID_IUnknown))
{
*obj = iface;
ID2D1SimplifiedGeometrySink_AddRef(iface);
return S_OK;
}
*obj = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI rendertarget_sink_AddRef(ID2D1SimplifiedGeometrySink *iface)
{
struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
return IDWriteBitmapRenderTarget1_AddRef(&This->IDWriteBitmapRenderTarget1_iface);
}
static ULONG WINAPI rendertarget_sink_Release(ID2D1SimplifiedGeometrySink *iface)
{
struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
return IDWriteBitmapRenderTarget1_Release(&This->IDWriteBitmapRenderTarget1_iface);
}
static void WINAPI rendertarget_sink_SetFillMode(ID2D1SimplifiedGeometrySink *iface, D2D1_FILL_MODE mode)
{
struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
SetPolyFillMode(This->hdc, mode == D2D1_FILL_MODE_ALTERNATE ? ALTERNATE : WINDING);
}
static void WINAPI rendertarget_sink_SetSegmentFlags(ID2D1SimplifiedGeometrySink *iface, D2D1_PATH_SEGMENT vertexFlags)
{
}
static void WINAPI rendertarget_sink_BeginFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
{
struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
MoveToEx(This->hdc, startPoint.x, startPoint.y, NULL);
}
static void WINAPI rendertarget_sink_AddLines(ID2D1SimplifiedGeometrySink *iface, const D2D1_POINT_2F *points, UINT32 count)
{
struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
while (count--) {
LineTo(This->hdc, points->x, points->y);
points++;
}
}
static void WINAPI rendertarget_sink_AddBeziers(ID2D1SimplifiedGeometrySink *iface, const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
{
struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
POINT points[3];
while (count--) {
points[0].x = beziers->point1.x;
points[0].y = beziers->point1.y;
points[1].x = beziers->point2.x;
points[1].y = beziers->point2.y;
points[2].x = beziers->point3.x;
points[2].y = beziers->point3.y;
PolyBezierTo(This->hdc, points, 3);
beziers++;
}
}
static void WINAPI rendertarget_sink_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
{
struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
CloseFigure(This->hdc);
}
static HRESULT WINAPI rendertarget_sink_Close(ID2D1SimplifiedGeometrySink *iface)
{
return S_OK;
}
static const ID2D1SimplifiedGeometrySinkVtbl rendertargetsinkvtbl = {
rendertarget_sink_QueryInterface,
rendertarget_sink_AddRef,
rendertarget_sink_Release,
rendertarget_sink_SetFillMode,
rendertarget_sink_SetSegmentFlags,
rendertarget_sink_BeginFigure,
rendertarget_sink_AddLines,
rendertarget_sink_AddBeziers,
rendertarget_sink_EndFigure,
rendertarget_sink_Close
};
static HRESULT WINAPI rendertarget_QueryInterface(IDWriteBitmapRenderTarget1 *iface, REFIID riid, void **obj)
{
struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
@ -213,6 +314,8 @@ static HRESULT WINAPI rendertarget_DrawGlyphRun(IDWriteBitmapRenderTarget1 *ifac
TRACE("(%p)->(%.2f %.2f %d %p %p 0x%08x %p)\n", This, originX, originY,
measuring_mode, run, params, color, bbox_ret);
SetRectEmpty(bbox_ret);
if (!This->dib.ptr)
return S_OK;
@ -221,9 +324,59 @@ static HRESULT WINAPI rendertarget_DrawGlyphRun(IDWriteBitmapRenderTarget1 *ifac
if (FAILED(hr))
return hr;
/* FIXME: outline mode rendering is not supported for this target yet */
if (rendermode == DWRITE_RENDERING_MODE_OUTLINE)
rendermode = DWRITE_RENDERING_MODE_ALIASED;
target.left = target.top = 0;
target.right = This->size.cx;
target.bottom = This->size.cy;
if (rendermode == DWRITE_RENDERING_MODE_OUTLINE) {
static const XFORM identity = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f };
const DWRITE_MATRIX *m = &This->m;
XFORM xform;
/* target allows any transform to be set, filter it here */
if (m->m11 * m->m22 == m->m12 * m->m21) {
xform.eM11 = 1.0f;
xform.eM12 = 0.0f;
xform.eM21 = 0.0f;
xform.eM22 = 1.0f;
xform.eDx = originX;
xform.eDy = originY;
} else {
xform.eM11 = m->m11;
xform.eM12 = m->m12;
xform.eM21 = m->m21;
xform.eM22 = m->m22;
xform.eDx = m->m11 * originX + m->m21 * originY + m->dx;
xform.eDy = m->m12 * originX + m->m22 * originY + m->dy;
}
SetWorldTransform(This->hdc, &xform);
BeginPath(This->hdc);
hr = IDWriteFontFace_GetGlyphRunOutline(run->fontFace, run->fontEmSize * This->ppdip,
run->glyphIndices, run->glyphAdvances, run->glyphOffsets, run->glyphCount,
run->isSideways, run->bidiLevel & 1, &This->ID2D1SimplifiedGeometrySink_iface);
EndPath(This->hdc);
if (hr == S_OK) {
HBRUSH brush = CreateSolidBrush(color);
SelectObject(This->hdc, brush);
FillPath(This->hdc);
/* FIXME: one way to get affected rectangle bounds is to use region fill */
if (bbox_ret)
*bbox_ret = target;
DeleteObject(brush);
}
SetWorldTransform(This->hdc, &identity);
return hr;
}
hr = IDWriteFactory_CreateGlyphRunAnalysis(This->factory,
run, This->ppdip, &This->m, rendermode, measuring_mode,
@ -241,11 +394,6 @@ static HRESULT WINAPI rendertarget_DrawGlyphRun(IDWriteBitmapRenderTarget1 *ifac
texturetype = DWRITE_TEXTURE_CLEARTYPE_3x1;
}
target.left = target.top = 0;
target.right = This->size.cx;
target.bottom = This->size.cy;
SetRectEmpty(bbox_ret);
if (IntersectRect(&target, &target, &bounds)) {
UINT32 size = (target.right - target.left) * (target.bottom - target.top);
BYTE *bitmap;
@ -261,7 +409,7 @@ static HRESULT WINAPI rendertarget_DrawGlyphRun(IDWriteBitmapRenderTarget1 *ifac
else
blit_subpixel_888(&This->dib, This->size.cx, bitmap, &target, color);
*bbox_ret = target;
if (bbox_ret) *bbox_ret = target;
}
heap_free(bitmap);
@ -387,9 +535,11 @@ static HRESULT create_rendertarget(IDWriteFactory *factory, HDC hdc, UINT32 widt
if (!target) return E_OUTOFMEMORY;
target->IDWriteBitmapRenderTarget1_iface.lpVtbl = &rendertargetvtbl;
target->ID2D1SimplifiedGeometrySink_iface.lpVtbl = &rendertargetsinkvtbl;
target->ref = 1;
target->hdc = CreateCompatibleDC(hdc);
SetGraphicsMode(target->hdc, GM_ADVANCED);
hr = create_target_dibsection(target, width, height);
if (FAILED(hr)) {
IDWriteBitmapRenderTarget1_Release(&target->IDWriteBitmapRenderTarget1_iface);

View File

@ -794,7 +794,6 @@ if (0) /* crashes on native */
/* test mode */
ret = GetGraphicsMode(hdc);
todo_wine
ok(ret == GM_ADVANCED, "got %d\n", ret);
hbm = GetCurrentObject(hdc, OBJ_BITMAP);