[PATCH 1/2] dwrite: Implement outline mode for DrawGlyphRun()

Nikolay Sivov nsivov at codeweavers.com
Thu Aug 13 10:55:52 CDT 2015


---

-------------- next part --------------
From ab3f3b14435e0b8f52190eb96d21f56b215c2f2a Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov at codeweavers.com>
Date: Thu, 13 Aug 2015 18:41:36 +0300
Subject: [PATCH 1/2] dwrite: Implement outline mode for DrawGlyphRun()

---
 dlls/dwrite/gdiinterop.c | 168 ++++++++++++++++++++++++++++++++++++++++++++---
 dlls/dwrite/tests/font.c |   1 -
 2 files changed, 159 insertions(+), 10 deletions(-)

diff --git a/dlls/dwrite/gdiinterop.c b/dlls/dwrite/gdiinterop.c
index 8c0aa43..da4fc5f 100644
--- a/dlls/dwrite/gdiinterop.c
+++ b/dlls/dwrite/gdiinterop.c
@@ -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);
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index b132749..9ba0d18 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -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);
-- 
2.1.4



More information about the wine-patches mailing list