d2d1: Take the recommended rendering mode into account in d2d_d3d_render_target_DrawGlyphRun().

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2015-11-18 22:23:23 +01:00 committed by Alexandre Julliard
parent b5685efc80
commit 55d403deb9
2 changed files with 223 additions and 50 deletions

View file

@ -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;

View file

@ -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)