[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