[PATCH 2/4] d2d1: Take the recommended rendering mode into account in d2d_d3d_render_target_DrawGlyphRun().

Henri Verbeet hverbeet at codeweavers.com
Wed Nov 18 15:23:23 CST 2015


Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/d2d1/d2d1_private.h  |   1 +
 dlls/d2d1/render_target.c | 272 +++++++++++++++++++++++++++++++++++++---------
 2 files changed, 223 insertions(+), 50 deletions(-)

diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h
index 89872e5..7834e0a 100644
--- a/dlls/d2d1/d2d1_private.h
+++ b/dlls/d2d1/d2d1_private.h
@@ -85,6 +85,7 @@ struct d2d_d3d_render_target
     struct d2d_error_state error;
     D2D1_DRAWING_STATE_DESCRIPTION drawing_state;
     IDWriteRenderingParams *text_rendering_params;
+    IDWriteRenderingParams *default_text_rendering_params;
 
     D2D1_PIXEL_FORMAT format;
     D2D1_SIZE_U pixel_size;
diff --git a/dlls/d2d1/render_target.c b/dlls/d2d1/render_target.c
index 9142bf1..bd20d5d 100644
--- a/dlls/d2d1/render_target.c
+++ b/dlls/d2d1/render_target.c
@@ -76,6 +76,12 @@ static void d2d_rect_set(D2D1_RECT_F *dst, float left, float top, float right, f
     dst->bottom = bottom;
 }
 
+static void d2d_size_set(D2D1_SIZE_U *dst, float width, float height)
+{
+    dst->width = width;
+    dst->height = height;
+}
+
 static BOOL d2d_clip_stack_init(struct d2d_clip_stack *stack)
 {
     if (!(stack->stack = HeapAlloc(GetProcessHeap(), 0, INITIAL_CLIP_STACK_SIZE * sizeof(*stack->stack))))
@@ -242,6 +248,7 @@ static ULONG STDMETHODCALLTYPE d2d_d3d_render_target_Release(ID2D1RenderTarget *
         unsigned int i, j, k;
 
         d2d_clip_stack_cleanup(&render_target->clip_stack);
+        IDWriteRenderingParams_Release(render_target->default_text_rendering_params);
         if (render_target->text_rendering_params)
             IDWriteRenderingParams_Release(render_target->text_rendering_params);
         ID3D10BlendState_Release(render_target->bs);
@@ -665,13 +672,9 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGeometry(ID2D1RenderTarg
             iface, geometry, brush, stroke_width, stroke_style);
 }
 
-static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarget *iface,
-        ID2D1Geometry *geometry, ID2D1Brush *brush, ID2D1Brush *opacity_brush)
+static void STDMETHODCALLTYPE d2d_rt_fill_geometry(struct d2d_d3d_render_target *render_target,
+        const struct d2d_geometry *geometry, struct d2d_brush *brush, struct d2d_brush *opacity_brush)
 {
-    struct d2d_brush *opacity_brush_impl = unsafe_impl_from_ID2D1Brush(opacity_brush);
-    struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
-    struct d2d_brush *brush_impl = unsafe_impl_from_ID2D1Brush(brush);
-    const struct d2d_geometry *geometry_impl;
     ID3D10Buffer *ib, *vb, *vs_cb, *ps_cb;
     D3D10_SUBRESOURCE_DATA buffer_data;
     D3D10_BUFFER_DESC buffer_desc;
@@ -684,21 +687,6 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarg
         float _12, _22, _32, pad1;
     } transform;
 
-    TRACE("iface %p, geometry %p, brush %p, opacity_brush %p.\n", iface, geometry, brush, opacity_brush);
-
-    if (FAILED(render_target->error.code))
-        return;
-
-    if (opacity_brush && brush_impl->type != D2D_BRUSH_TYPE_BITMAP)
-    {
-        render_target->error.code = D2DERR_INCOMPATIBLE_BRUSH_TYPES;
-        render_target->error.tag1 = render_target->drawing_state.tag1;
-        render_target->error.tag2 = render_target->drawing_state.tag2;
-        return;
-    }
-
-    geometry_impl = unsafe_impl_from_ID2D1Geometry(geometry);
-
     tmp_x =  (2.0f * render_target->dpi_x) / (96.0f * render_target->pixel_size.width);
     tmp_y = -(2.0f * render_target->dpi_y) / (96.0f * render_target->pixel_size.height);
     w = render_target->drawing_state.transform;
@@ -709,7 +697,7 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarg
     w._22 *= tmp_y;
     w._32 = w._32 * tmp_y + 1.0f;
 
-    g = geometry_impl->transform;
+    g = geometry->transform;
     d2d_matrix_multiply(&g, &w);
 
     transform._11 = g._11;
@@ -737,18 +725,18 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarg
         return;
     }
 
-    if (FAILED(hr = d2d_brush_get_ps_cb(brush_impl, opacity_brush_impl, render_target, &ps_cb)))
+    if (FAILED(hr = d2d_brush_get_ps_cb(brush, opacity_brush, render_target, &ps_cb)))
     {
         WARN("Failed to get ps constant buffer, hr %#x.\n", hr);
         ID3D10Buffer_Release(vs_cb);
         return;
     }
 
-    if (geometry_impl->face_count)
+    if (geometry->face_count)
     {
-        buffer_desc.ByteWidth = geometry_impl->face_count * sizeof(*geometry_impl->faces);
+        buffer_desc.ByteWidth = geometry->face_count * sizeof(*geometry->faces);
         buffer_desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
-        buffer_data.pSysMem = geometry_impl->faces;
+        buffer_data.pSysMem = geometry->faces;
 
         if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ib)))
         {
@@ -756,9 +744,9 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarg
             goto done;
         }
 
-        buffer_desc.ByteWidth = geometry_impl->vertex_count * sizeof(*geometry_impl->vertices);
+        buffer_desc.ByteWidth = geometry->vertex_count * sizeof(*geometry->vertices);
         buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
-        buffer_data.pSysMem = geometry_impl->vertices;
+        buffer_data.pSysMem = geometry->vertices;
 
         if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vb)))
         {
@@ -767,17 +755,17 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarg
             goto done;
         }
 
-        d2d_rt_draw(render_target, D2D_SHAPE_TYPE_TRIANGLE, ib, 3 * geometry_impl->face_count, vb,
-                sizeof(*geometry_impl->vertices), vs_cb, ps_cb, brush_impl, opacity_brush_impl);
+        d2d_rt_draw(render_target, D2D_SHAPE_TYPE_TRIANGLE, ib, 3 * geometry->face_count, vb,
+                sizeof(*geometry->vertices), vs_cb, ps_cb, brush, opacity_brush);
 
         ID3D10Buffer_Release(vb);
         ID3D10Buffer_Release(ib);
     }
 
-    if (geometry_impl->bezier_count)
+    if (geometry->bezier_count)
     {
-        buffer_desc.ByteWidth = geometry_impl->bezier_count * sizeof(*geometry_impl->beziers);
-        buffer_data.pSysMem = geometry_impl->beziers;
+        buffer_desc.ByteWidth = geometry->bezier_count * sizeof(*geometry->beziers);
+        buffer_data.pSysMem = geometry->beziers;
 
         if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vb)))
         {
@@ -785,8 +773,8 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarg
             goto done;
         }
 
-        d2d_rt_draw(render_target, D2D_SHAPE_TYPE_BEZIER, NULL, 3 * geometry_impl->bezier_count, vb,
-                sizeof(*geometry_impl->beziers->v), vs_cb, ps_cb, brush_impl, opacity_brush_impl);
+        d2d_rt_draw(render_target, D2D_SHAPE_TYPE_BEZIER, NULL, 3 * geometry->bezier_count, vb,
+                sizeof(*geometry->beziers->v), vs_cb, ps_cb, brush, opacity_brush);
 
         ID3D10Buffer_Release(vb);
     }
@@ -796,6 +784,30 @@ done:
     ID3D10Buffer_Release(vs_cb);
 }
 
+static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarget *iface,
+        ID2D1Geometry *geometry, ID2D1Brush *brush, ID2D1Brush *opacity_brush)
+{
+    const struct d2d_geometry *geometry_impl = unsafe_impl_from_ID2D1Geometry(geometry);
+    struct d2d_brush *opacity_brush_impl = unsafe_impl_from_ID2D1Brush(opacity_brush);
+    struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
+    struct d2d_brush *brush_impl = unsafe_impl_from_ID2D1Brush(brush);
+
+    TRACE("iface %p, geometry %p, brush %p, opacity_brush %p.\n", iface, geometry, brush, opacity_brush);
+
+    if (FAILED(render_target->error.code))
+        return;
+
+    if (opacity_brush && brush_impl->type != D2D_BRUSH_TYPE_BITMAP)
+    {
+        render_target->error.code = D2DERR_INCOMPATIBLE_BRUSH_TYPES;
+        render_target->error.tag1 = render_target->drawing_state.tag1;
+        render_target->error.tag2 = render_target->drawing_state.tag2;
+        return;
+    }
+
+    d2d_rt_fill_geometry(render_target, geometry_impl, brush_impl, opacity_brush_impl);
+}
+
 static void STDMETHODCALLTYPE d2d_d3d_render_target_FillMesh(ID2D1RenderTarget *iface,
         ID2D1Mesh *mesh, ID2D1Brush *brush)
 {
@@ -928,26 +940,14 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawTextLayout(ID2D1RenderTa
         FIXME("Failed to draw text layout, hr %#x.\n", hr);
 }
 
-static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGlyphRun(ID2D1RenderTarget *iface,
-        D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush,
-        DWRITE_MEASURING_MODE measuring_mode)
+static void d2d_rt_draw_glyph_run_outline(struct d2d_d3d_render_target *render_target,
+        D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush)
 {
-    struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
     D2D1_MATRIX_3X2_F *transform, prev_transform;
     ID2D1PathGeometry *geometry;
     ID2D1GeometrySink *sink;
     HRESULT hr;
 
-    TRACE("iface %p, baseline_origin {%.8e, %.8e}, glyph_run %p, brush %p, measuring_mode %#x.\n",
-            iface, baseline_origin.x, baseline_origin.y, glyph_run, brush, measuring_mode);
-
-    if (measuring_mode)
-        FIXME("Ignoring measuring mode %#x.\n", measuring_mode);
-    if (render_target->text_rendering_params)
-        FIXME("Ignoring text rendering parameters %p.\n", render_target->text_rendering_params);
-    if (render_target->drawing_state.textAntialiasMode != D2D1_TEXT_ANTIALIAS_MODE_ALIASED)
-        FIXME("Ignoring text antialiasing mode %#x.\n", render_target->drawing_state.textAntialiasMode);
-
     if (FAILED(hr = ID2D1Factory_CreatePathGeometry(render_target->factory, &geometry)))
     {
         ERR("Failed to create geometry, hr %#x.\n", hr);
@@ -979,12 +979,166 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGlyphRun(ID2D1RenderTarg
     prev_transform = *transform;
     transform->_31 += baseline_origin.x * transform->_11 + baseline_origin.y * transform->_21;
     transform->_32 += baseline_origin.x * transform->_12 + baseline_origin.y * transform->_22;
-    ID2D1RenderTarget_FillGeometry(iface, (ID2D1Geometry *)geometry, brush, NULL);
+    d2d_rt_fill_geometry(render_target, unsafe_impl_from_ID2D1Geometry((ID2D1Geometry *)geometry),
+            unsafe_impl_from_ID2D1Brush(brush), NULL);
     *transform = prev_transform;
 
     ID2D1PathGeometry_Release(geometry);
 }
 
+static void d2d_rt_draw_glyph_run_bitmap(struct d2d_d3d_render_target *render_target,
+        D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush,
+        float ppd, DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode)
+{
+    ID2D1RectangleGeometry *geometry = NULL;
+    ID2D1BitmapBrush *opacity_brush = NULL;
+    D2D1_BITMAP_PROPERTIES bitmap_desc;
+    ID2D1Bitmap *opacity_bitmap = NULL;
+    IDWriteGlyphRunAnalysis *analysis;
+    DWRITE_TEXTURE_TYPE texture_type;
+    D2D1_BRUSH_PROPERTIES brush_desc;
+    IDWriteFactory *dwrite_factory;
+    void *opacity_values = NULL;
+    size_t opacity_values_size;
+    D2D1_SIZE_U bitmap_size;
+    D2D1_RECT_F run_rect;
+    RECT bounds;
+    HRESULT hr;
+
+    if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
+            &IID_IDWriteFactory, (IUnknown **)&dwrite_factory)))
+    {
+        ERR("Failed to create dwrite factory, hr %#x.\n", hr);
+        return;
+    }
+
+    hr = IDWriteFactory_CreateGlyphRunAnalysis(dwrite_factory, glyph_run, ppd, NULL,
+            rendering_mode, measuring_mode, baseline_origin.x, baseline_origin.y, &analysis);
+    IDWriteFactory_Release(dwrite_factory);
+    if (FAILED(hr))
+    {
+        ERR("Failed to create glyph run analysis, hr %#x.\n", hr);
+        return;
+    }
+
+    if (rendering_mode == DWRITE_RENDERING_MODE_ALIASED)
+        texture_type = DWRITE_TEXTURE_ALIASED_1x1;
+    else
+        texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
+
+    if (FAILED(hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, texture_type, &bounds)))
+    {
+        ERR("Failed to get alpha texture bounds, hr %#x.\n", hr);
+        goto done;
+    }
+
+    d2d_size_set(&bitmap_size, bounds.right - bounds.left, bounds.bottom - bounds.top);
+    if (!bitmap_size.width || !bitmap_size.height)
+    {
+        /* Empty run, nothing to do. */
+        goto done;
+    }
+
+    if (texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
+        bitmap_size.width *= 3;
+    opacity_values_size = bitmap_size.width * bitmap_size.height;
+    if (!(opacity_values = HeapAlloc(GetProcessHeap(), 0, opacity_values_size)))
+    {
+        ERR("Failed to allocate opacity values.\n");
+        goto done;
+    }
+
+    if (FAILED(hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis,
+            texture_type, &bounds, opacity_values, opacity_values_size)))
+    {
+        ERR("Failed to create alpha texture, hr %#x.\n", hr);
+        goto done;
+    }
+
+    bitmap_desc.pixelFormat.format = DXGI_FORMAT_A8_UNORM;
+    bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
+    bitmap_desc.dpiX = render_target->dpi_x;
+    if (texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
+        bitmap_desc.dpiX *= 3.0f;
+    bitmap_desc.dpiY = render_target->dpi_y;
+    if (FAILED(hr = d2d_d3d_render_target_CreateBitmap(&render_target->ID2D1RenderTarget_iface,
+            bitmap_size, opacity_values, bitmap_size.width, &bitmap_desc, &opacity_bitmap)))
+    {
+        ERR("Failed to create opacity bitmap, hr %#x.\n", hr);
+        goto done;
+    }
+
+    brush_desc.opacity = 1.0f;
+    brush_desc.transform._11 = 1.0f;
+    brush_desc.transform._12 = 0.0f;
+    brush_desc.transform._21 = 0.0f;
+    brush_desc.transform._22 = 1.0f;
+    brush_desc.transform._31 = bounds.left;
+    brush_desc.transform._32 = bounds.top;
+    if (FAILED(hr = d2d_d3d_render_target_CreateBitmapBrush(&render_target->ID2D1RenderTarget_iface,
+            opacity_bitmap, NULL, &brush_desc, &opacity_brush)))
+    {
+        ERR("Failed to create opacity bitmap brush, hr %#x.\n", hr);
+        goto done;
+    }
+
+    d2d_rect_set(&run_rect, bounds.left, bounds.top, bounds.right, bounds.bottom);
+    if (FAILED(hr = ID2D1Factory_CreateRectangleGeometry(render_target->factory, &run_rect, &geometry)))
+    {
+        ERR("Failed to create geometry, hr %#x.\n", hr);
+        goto done;
+    }
+
+    d2d_rt_fill_geometry(render_target, unsafe_impl_from_ID2D1Geometry((ID2D1Geometry *)geometry),
+            unsafe_impl_from_ID2D1Brush(brush), unsafe_impl_from_ID2D1Brush((ID2D1Brush *)opacity_brush));
+
+done:
+    if (geometry)
+        ID2D1RectangleGeometry_Release(geometry);
+    if (opacity_brush)
+        ID2D1BitmapBrush_Release(opacity_brush);
+    if (opacity_bitmap)
+        ID2D1Bitmap_Release(opacity_bitmap);
+    HeapFree(GetProcessHeap(), 0, opacity_values);
+    IDWriteGlyphRunAnalysis_Release(analysis);
+}
+
+static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGlyphRun(ID2D1RenderTarget *iface,
+        D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush,
+        DWRITE_MEASURING_MODE measuring_mode)
+{
+    struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
+    IDWriteRenderingParams *rendering_params;
+    DWRITE_RENDERING_MODE rendering_mode;
+    HRESULT hr;
+    float ppd;
+
+    TRACE("iface %p, baseline_origin {%.8e, %.8e}, glyph_run %p, brush %p, measuring_mode %#x.\n",
+            iface, baseline_origin.x, baseline_origin.y, glyph_run, brush, measuring_mode);
+
+    if (FAILED(render_target->error.code))
+        return;
+
+    if (render_target->drawing_state.textAntialiasMode != D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
+        FIXME("Ignoring text antialiasing mode %#x.\n", render_target->drawing_state.textAntialiasMode);
+
+    ppd = max(render_target->dpi_x, render_target->dpi_y) / 96.0f;
+    rendering_params = render_target->text_rendering_params ? render_target->text_rendering_params
+            : render_target->default_text_rendering_params;
+    if (FAILED(hr = IDWriteFontFace_GetRecommendedRenderingMode(glyph_run->fontFace, glyph_run->fontEmSize,
+            ppd, measuring_mode, rendering_params, &rendering_mode)))
+    {
+        ERR("Failed to get recommended rendering mode, hr %#x.\n", hr);
+        rendering_mode = DWRITE_RENDERING_MODE_OUTLINE;
+    }
+
+    if (rendering_mode == DWRITE_RENDERING_MODE_OUTLINE)
+        d2d_rt_draw_glyph_run_outline(render_target, baseline_origin, glyph_run, brush);
+    else
+        d2d_rt_draw_glyph_run_bitmap(render_target, baseline_origin, glyph_run, brush,
+                ppd, rendering_mode, measuring_mode);
+}
+
 static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTransform(ID2D1RenderTarget *iface,
         const D2D1_MATRIX_3X2_F *transform)
 {
@@ -1546,6 +1700,7 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
     D3D10_SUBRESOURCE_DATA buffer_data;
     D3D10_STATE_BLOCK_MASK state_mask;
     DXGI_SURFACE_DESC surface_desc;
+    IDWriteFactory *dwrite_factory;
     D3D10_RASTERIZER_DESC rs_desc;
     D3D10_BUFFER_DESC buffer_desc;
     D3D10_BLEND_DESC blend_desc;
@@ -2035,6 +2190,21 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
         goto err;
     }
 
+    if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
+            &IID_IDWriteFactory, (IUnknown **)&dwrite_factory)))
+    {
+        ERR("Failed to create dwrite factory, hr %#x.\n", hr);
+        goto err;
+    }
+
+    hr = IDWriteFactory_CreateRenderingParams(dwrite_factory, &render_target->default_text_rendering_params);
+    IDWriteFactory_Release(dwrite_factory);
+    if (FAILED(hr))
+    {
+        ERR("Failed to create default text rendering parameters, hr %#x.\n", hr);
+        goto err;
+    }
+
     if (FAILED(hr = IDXGISurface_GetDesc(surface, &surface_desc)))
     {
         WARN("Failed to get surface desc, hr %#x.\n", hr);
@@ -2065,6 +2235,8 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
     return S_OK;
 
 err:
+    if (render_target->default_text_rendering_params)
+        IDWriteRenderingParams_Release(render_target->default_text_rendering_params);
     if (render_target->bs)
         ID3D10BlendState_Release(render_target->bs);
     if (render_target->rs)
-- 
2.1.4




More information about the wine-patches mailing list