d2d1: Implement d2d_path_geometry_Simplify().

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2017-06-07 21:31:52 +02:00 committed by Alexandre Julliard
parent 208eb09e3c
commit 09ff685aa0
2 changed files with 660 additions and 82 deletions

View File

@ -26,6 +26,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(d2d);
#define D2D_FIGURE_FLAG_CLOSED 0x00000001u
#define D2D_FIGURE_FLAG_HOLLOW 0x00000002u
#define D2D_CDT_EDGE_FLAG_FREED 0x80000000u
#define D2D_CDT_EDGE_FLAG_VISITED(r) (1u << (r))
@ -66,6 +69,7 @@ struct d2d_figure
size_t bezier_control_count;
D2D1_RECT_F bounds;
unsigned int flags;
};
struct d2d_cdt_edge_ref
@ -2054,6 +2058,8 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_SetFillMode(ID2D1GeometrySink *i
TRACE("iface %p, mode %#x.\n", iface, mode);
if (geometry->u.path.state == D2D_GEOMETRY_STATE_CLOSED)
return;
geometry->u.path.fill_mode = mode;
}
@ -2066,6 +2072,7 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *i
D2D1_POINT_2F start_point, D2D1_FIGURE_BEGIN figure_begin)
{
struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
struct d2d_figure *figure;
TRACE("iface %p, start_point {%.8e, %.8e}, figure_begin %#x.\n",
iface, start_point.x, start_point.y, figure_begin);
@ -2086,7 +2093,11 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_BeginFigure(ID2D1GeometrySink *i
return;
}
if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], start_point))
figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
if (figure_begin == D2D1_FIGURE_BEGIN_HOLLOW)
figure->flags |= D2D_FIGURE_FLAG_HOLLOW;
if (!d2d_figure_add_vertex(figure, start_point))
{
ERR("Failed to add vertex.\n");
geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
@ -2183,9 +2194,12 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *ifa
figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_LINE;
if (figure_end == D2D1_FIGURE_END_CLOSED && !memcmp(&figure->vertices[0],
&figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices)))
--figure->vertex_count;
if (figure_end == D2D1_FIGURE_END_CLOSED)
{
figure->flags |= D2D_FIGURE_FLAG_CLOSED;
if (!memcmp(&figure->vertices[0], &figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices)))
--figure->vertex_count;
}
if (!d2d_geometry_add_figure_outline(geometry, figure, figure_end))
{
@ -2526,14 +2540,153 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CompareWithGeometry(ID2D1Path
return E_NOTIMPL;
}
static void d2d_geometry_flatten_cubic(ID2D1SimplifiedGeometrySink *sink, const D2D1_POINT_2F *p0,
const D2D1_BEZIER_SEGMENT *b, float tolerance)
{
D2D1_BEZIER_SEGMENT b0, b1;
D2D1_POINT_2F q;
float d;
/* It's certainly possible to calculate the maximum deviation of the
* approximation from the curve, but it's a little involved. Instead, note
* that if the control points were evenly spaced and collinear, p1 would
* be exactly between p0 and p2, and p2 would be exactly between p1 and
* p3. The deviation is a decent enough approximation, and much easier to
* calculate.
*
* p1' = (p0 + p2) / 2
* p2' = (p1 + p3) / 2
* d = p1 - p1' + p2 - p2' */
d2d_point_lerp(&q, p0, &b->point2, 0.5f);
d2d_point_subtract(&q, &b->point1, &q);
d = fabsf(q.x) + fabsf(q.y);
d2d_point_lerp(&q, &b->point1, &b->point3, 0.5f);
d2d_point_subtract(&q, &b->point2, &q);
d += fabsf(q.x) + fabsf(q.y);
if (d < tolerance)
{
ID2D1SimplifiedGeometrySink_AddLines(sink, &b->point3, 1);
return;
}
d2d_point_lerp(&q, &b->point1, &b->point2, 0.5f);
b1.point3 = b->point3;
d2d_point_lerp(&b1.point2, &b1.point3, &b->point2, 0.5f);
d2d_point_lerp(&b1.point1, &b1.point2, &q, 0.5f);
d2d_point_lerp(&b0.point1, p0, &b->point1, 0.5f);
d2d_point_lerp(&b0.point2, &b0.point1, &q, 0.5f);
d2d_point_lerp(&b0.point3, &b0.point2, &b1.point1, 0.5f);
d2d_geometry_flatten_cubic(sink, p0, &b0, tolerance);
ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN);
d2d_geometry_flatten_cubic(sink, &b0.point3, &b1, tolerance);
ID2D1SimplifiedGeometrySink_SetSegmentFlags(sink, D2D1_PATH_SEGMENT_NONE);
}
static void d2d_geometry_simplify_quadratic(ID2D1SimplifiedGeometrySink *sink,
D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_POINT_2F *p0,
const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2, float tolerance)
{
D2D1_BEZIER_SEGMENT b;
d2d_point_lerp(&b.point1, p0, p1, 2.0f / 3.0f);
d2d_point_lerp(&b.point2, p2, p1, 2.0f / 3.0f);
b.point3 = *p2;
if (option == D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES)
d2d_geometry_flatten_cubic(sink, p0, &b, tolerance);
else
ID2D1SimplifiedGeometrySink_AddBeziers(sink, &b, 1);
}
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *iface,
D2D1_GEOMETRY_SIMPLIFICATION_OPTION option, const D2D1_MATRIX_3X2_F *transform, float tolerance,
ID2D1SimplifiedGeometrySink *sink)
{
FIXME("iface %p, option %#x, transform %p, tolerance %.8e, sink %p stub!\n",
struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
unsigned int i, j, bezier_idx;
D2D1_FIGURE_BEGIN begin;
D2D1_POINT_2F p, p1, p2;
D2D1_FIGURE_END end;
TRACE("iface %p, option %#x, transform %p, tolerance %.8e, sink %p.\n",
iface, option, transform, tolerance, sink);
return E_NOTIMPL;
ID2D1SimplifiedGeometrySink_SetFillMode(sink, geometry->u.path.fill_mode);
for (i = 0; i < geometry->u.path.figure_count; ++i)
{
const struct d2d_figure *figure = &geometry->u.path.figures[i];
for (j = 0; j < figure->vertex_count; ++j)
{
if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
continue;
p = figure->vertices[j];
if (transform)
d2d_point_transform(&p, transform, p.x, p.y);
begin = figure->flags & D2D_FIGURE_FLAG_HOLLOW ? D2D1_FIGURE_BEGIN_HOLLOW : D2D1_FIGURE_BEGIN_FILLED;
ID2D1SimplifiedGeometrySink_BeginFigure(sink, p, begin);
type = figure->vertex_types[j];
break;
}
for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
{
if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE)
continue;
switch (type)
{
case D2D_VERTEX_TYPE_LINE:
p = figure->vertices[j];
if (transform)
d2d_point_transform(&p, transform, p.x, p.y);
ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
break;
case D2D_VERTEX_TYPE_BEZIER:
p1 = figure->bezier_controls[bezier_idx++];
if (transform)
d2d_point_transform(&p1, transform, p1.x, p1.y);
p2 = figure->vertices[j];
if (transform)
d2d_point_transform(&p2, transform, p2.x, p2.y);
d2d_geometry_simplify_quadratic(sink, option, &p, &p1, &p2, tolerance);
p = p2;
break;
default:
FIXME("Unhandled vertex type %#x.\n", type);
p = figure->vertices[j];
if (transform)
d2d_point_transform(&p, transform, p.x, p.y);
ID2D1SimplifiedGeometrySink_AddLines(sink, &p, 1);
break;
}
type = figure->vertex_types[j];
}
if (type == D2D_VERTEX_TYPE_BEZIER)
{
p1 = figure->bezier_controls[bezier_idx++];
if (transform)
d2d_point_transform(&p1, transform, p1.x, p1.y);
p2 = figure->vertices[0];
if (transform)
d2d_point_transform(&p2, transform, p2.x, p2.y);
d2d_geometry_simplify_quadratic(sink, option, &p, &p1, &p2, tolerance);
}
end = figure->flags & D2D_FIGURE_FLAG_CLOSED ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN;
ID2D1SimplifiedGeometrySink_EndFigure(sink, end);
}
return S_OK;
}
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry *iface,

View File

@ -54,6 +54,7 @@ struct geometry_sink
D2D1_BEZIER_SEGMENT bezier;
D2D1_POINT_2F line;
} u;
DWORD flags;
} *segments;
unsigned int segments_size;
unsigned int segment_count;
@ -62,6 +63,7 @@ struct geometry_sink
unsigned int figure_count;
D2D1_FILL_MODE fill_mode;
DWORD segment_flags;
BOOL closed;
};
@ -709,7 +711,9 @@ static void STDMETHODCALLTYPE geometry_sink_SetFillMode(ID2D1SimplifiedGeometryS
static void STDMETHODCALLTYPE geometry_sink_SetSegmentFlags(ID2D1SimplifiedGeometrySink *iface,
D2D1_PATH_SEGMENT flags)
{
ok(0, "Got unexpected segment flags %#x.\n", flags);
struct geometry_sink *sink = impl_from_ID2D1SimplifiedGeometrySink(iface);
sink->segment_flags = flags;
}
static void STDMETHODCALLTYPE geometry_sink_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
@ -757,6 +761,7 @@ static void STDMETHODCALLTYPE geometry_sink_AddLines(ID2D1SimplifiedGeometrySink
segment = geometry_figure_add_segment(figure);
segment->type = SEGMENT_LINE;
segment->u.line = points[i];
segment->flags = sink->segment_flags;
}
}
@ -773,6 +778,7 @@ static void STDMETHODCALLTYPE geometry_sink_AddBeziers(ID2D1SimplifiedGeometrySi
segment = geometry_figure_add_segment(figure);
segment->type = SEGMENT_BEZIER;
segment->u.bezier = beziers[i];
segment->flags = sink->segment_flags;
}
}
@ -828,6 +834,84 @@ static void geometry_sink_cleanup(struct geometry_sink *sink)
HeapFree(GetProcessHeap(), 0, sink->figures);
}
#define geometry_sink_check(a, b, c, d, e) geometry_sink_check_(__LINE__, a, b, c, d, e)
static void geometry_sink_check_(unsigned int line, const struct geometry_sink *sink, D2D1_FILL_MODE fill_mode,
unsigned int figure_count, const struct expected_geometry_figure *expected_figures, unsigned int ulps)
{
const struct geometry_segment *segment, *expected_segment;
const struct expected_geometry_figure *expected_figure;
const struct geometry_figure *figure;
unsigned int i, j;
BOOL match;
ok_(__FILE__, line)(sink->fill_mode == fill_mode,
"Got unexpected fill mode %#x.\n", sink->fill_mode);
ok_(__FILE__, line)(sink->figure_count == figure_count,
"Got unexpected figure count %u, expected %u.\n", sink->figure_count, figure_count);
ok_(__FILE__, line)(!sink->closed, "Sink is closed.\n");
for (i = 0; i < figure_count; ++i)
{
expected_figure = &expected_figures[i];
figure = &sink->figures[i];
ok_(__FILE__, line)(figure->begin == expected_figure->begin,
"Got unexpected figure %u begin %#x, expected %#x.\n",
i, figure->begin, expected_figure->begin);
ok_(__FILE__, line)(figure->end == expected_figure->end,
"Got unexpected figure %u end %#x, expected %#x.\n",
i, figure->end, expected_figure->end);
match = compare_point(&figure->start_point,
expected_figure->start_point.x, expected_figure->start_point.y, ulps);
ok_(__FILE__, line)(match, "Got unexpected figure %u start point {%.8e, %.8e}, expected {%.8e, %.8e}.\n",
i, figure->start_point.x, figure->start_point.y,
expected_figure->start_point.x, expected_figure->start_point.y);
ok_(__FILE__, line)(figure->segment_count == expected_figure->segment_count,
"Got unexpected figure %u segment count %u, expected %u.\n",
i, figure->segment_count, expected_figure->segment_count);
for (j = 0; j < figure->segment_count; ++j)
{
expected_segment = &expected_figure->segments[j];
segment = &figure->segments[j];
ok_(__FILE__, line)(segment->type == expected_segment->type,
"Got unexpected figure %u, segment %u type %#x, expected %#x.\n",
i, j, segment->type, expected_segment->type);
ok_(__FILE__, line)(segment->flags == expected_segment->flags,
"Got unexpected figure %u, segment %u flags %#x, expected %#x.\n",
i, j, segment->flags, expected_segment->flags);
switch (segment->type)
{
case SEGMENT_LINE:
match = compare_point(&segment->u.line,
expected_segment->u.line.x, expected_segment->u.line.y, ulps);
ok_(__FILE__, line)(match, "Got unexpected figure %u segment %u {%.8e, %.8e}, "
"expected {%.8e, %.8e}.\n",
i, j, segment->u.line.x, segment->u.line.y,
expected_segment->u.line.x, expected_segment->u.line.y);
break;
case SEGMENT_BEZIER:
match = compare_bezier_segment(&segment->u.bezier,
expected_segment->u.bezier.point1.x, expected_segment->u.bezier.point1.y,
expected_segment->u.bezier.point2.x, expected_segment->u.bezier.point2.y,
expected_segment->u.bezier.point3.x, expected_segment->u.bezier.point3.y,
ulps);
ok_(__FILE__, line)(match, "Got unexpected figure %u segment %u "
"{%.8e, %.8e, %.8e, %.8e, %.8e, %.8e}, "
"expected {%.8e, %.8e, %.8e, %.8e, %.8e, %.8e}.\n",
i, j, segment->u.bezier.point1.x, segment->u.bezier.point1.y,
segment->u.bezier.point2.x, segment->u.bezier.point2.y,
segment->u.bezier.point3.x, segment->u.bezier.point3.y,
expected_segment->u.bezier.point1.x, expected_segment->u.bezier.point1.y,
expected_segment->u.bezier.point2.x, expected_segment->u.bezier.point2.y,
expected_segment->u.bezier.point3.x, expected_segment->u.bezier.point3.y);
break;
}
}
}
}
static void test_clip(void)
{
IDXGISwapChain *swapchain;
@ -1571,6 +1655,7 @@ static void test_path_geometry(void)
ID2D1TransformedGeometry *transformed_geometry;
D2D1_MATRIX_3X2_F matrix, tmp_matrix;
ID2D1GeometrySink *sink, *tmp_sink;
struct geometry_sink simplify_sink;
D2D1_POINT_2F point = {0.0f, 0.0f};
ID2D1SolidColorBrush *brush;
ID2D1PathGeometry *geometry;
@ -1587,6 +1672,320 @@ static void test_path_geometry(void)
HWND window;
HRESULT hr;
static const struct geometry_segment expected_segments[] =
{
/* Figure 0. */
{SEGMENT_LINE, {{{ 55.0f, 20.0f}}}},
{SEGMENT_LINE, {{{ 55.0f, 220.0f}}}},
{SEGMENT_LINE, {{{ 25.0f, 220.0f}}}},
{SEGMENT_LINE, {{{ 25.0f, 100.0f}}}},
{SEGMENT_LINE, {{{ 75.0f, 100.0f}}}},
{SEGMENT_LINE, {{{ 75.0f, 300.0f}}}},
{SEGMENT_LINE, {{{ 5.0f, 300.0f}}}},
{SEGMENT_LINE, {{{ 5.0f, 60.0f}}}},
{SEGMENT_LINE, {{{ 45.0f, 60.0f}}}},
{SEGMENT_LINE, {{{ 45.0f, 180.0f}}}},
{SEGMENT_LINE, {{{ 35.0f, 180.0f}}}},
{SEGMENT_LINE, {{{ 35.0f, 140.0f}}}},
{SEGMENT_LINE, {{{ 65.0f, 140.0f}}}},
{SEGMENT_LINE, {{{ 65.0f, 260.0f}}}},
{SEGMENT_LINE, {{{ 15.0f, 260.0f}}}},
/* Figure 1. */
{SEGMENT_LINE, {{{155.0f, 160.0f}}}},
{SEGMENT_LINE, {{{ 85.0f, 160.0f}}}},
{SEGMENT_LINE, {{{ 85.0f, 300.0f}}}},
{SEGMENT_LINE, {{{120.0f, 300.0f}}}},
{SEGMENT_LINE, {{{120.0f, 20.0f}}}},
{SEGMENT_LINE, {{{155.0f, 20.0f}}}},
{SEGMENT_LINE, {{{155.0f, 160.0f}}}},
{SEGMENT_LINE, {{{ 85.0f, 160.0f}}}},
{SEGMENT_LINE, {{{ 85.0f, 20.0f}}}},
{SEGMENT_LINE, {{{120.0f, 20.0f}}}},
{SEGMENT_LINE, {{{120.0f, 300.0f}}}},
/* Figure 2. */
{SEGMENT_LINE, {{{165.0f, 300.0f}}}},
{SEGMENT_LINE, {{{235.0f, 300.0f}}}},
{SEGMENT_LINE, {{{235.0f, 20.0f}}}},
/* Figure 3. */
{SEGMENT_LINE, {{{225.0f, 260.0f}}}},
{SEGMENT_LINE, {{{175.0f, 260.0f}}}},
{SEGMENT_LINE, {{{175.0f, 60.0f}}}},
/* Figure 4. */
{SEGMENT_LINE, {{{185.0f, 220.0f}}}},
{SEGMENT_LINE, {{{185.0f, 100.0f}}}},
{SEGMENT_LINE, {{{215.0f, 100.0f}}}},
/* Figure 5. */
{SEGMENT_LINE, {{{205.0f, 180.0f}}}},
{SEGMENT_LINE, {{{205.0f, 140.0f}}}},
{SEGMENT_LINE, {{{195.0f, 140.0f}}}},
/* Figure 6. */
{SEGMENT_LINE, {{{135.0f, 620.0f}}}},
{SEGMENT_LINE, {{{135.0f, 420.0f}}}},
{SEGMENT_LINE, {{{105.0f, 420.0f}}}},
{SEGMENT_LINE, {{{105.0f, 540.0f}}}},
{SEGMENT_LINE, {{{155.0f, 540.0f}}}},
{SEGMENT_LINE, {{{155.0f, 340.0f}}}},
{SEGMENT_LINE, {{{ 85.0f, 340.0f}}}},
{SEGMENT_LINE, {{{ 85.0f, 580.0f}}}},
{SEGMENT_LINE, {{{125.0f, 580.0f}}}},
{SEGMENT_LINE, {{{125.0f, 460.0f}}}},
{SEGMENT_LINE, {{{115.0f, 460.0f}}}},
{SEGMENT_LINE, {{{115.0f, 500.0f}}}},
{SEGMENT_LINE, {{{145.0f, 500.0f}}}},
{SEGMENT_LINE, {{{145.0f, 380.0f}}}},
{SEGMENT_LINE, {{{ 95.0f, 380.0f}}}},
/* Figure 7. */
{SEGMENT_LINE, {{{235.0f, 480.0f}}}},
{SEGMENT_LINE, {{{165.0f, 480.0f}}}},
{SEGMENT_LINE, {{{165.0f, 340.0f}}}},
{SEGMENT_LINE, {{{200.0f, 340.0f}}}},
{SEGMENT_LINE, {{{200.0f, 620.0f}}}},
{SEGMENT_LINE, {{{235.0f, 620.0f}}}},
{SEGMENT_LINE, {{{235.0f, 480.0f}}}},
{SEGMENT_LINE, {{{165.0f, 480.0f}}}},
{SEGMENT_LINE, {{{165.0f, 620.0f}}}},
{SEGMENT_LINE, {{{200.0f, 620.0f}}}},
{SEGMENT_LINE, {{{200.0f, 340.0f}}}},
/* Figure 8. */
{SEGMENT_LINE, {{{245.0f, 340.0f}}}},
{SEGMENT_LINE, {{{315.0f, 340.0f}}}},
{SEGMENT_LINE, {{{315.0f, 620.0f}}}},
/* Figure 9. */
{SEGMENT_LINE, {{{305.0f, 380.0f}}}},
{SEGMENT_LINE, {{{255.0f, 380.0f}}}},
{SEGMENT_LINE, {{{255.0f, 580.0f}}}},
/* Figure 10. */
{SEGMENT_LINE, {{{265.0f, 420.0f}}}},
{SEGMENT_LINE, {{{265.0f, 540.0f}}}},
{SEGMENT_LINE, {{{295.0f, 540.0f}}}},
/* Figure 11. */
{SEGMENT_LINE, {{{285.0f, 460.0f}}}},
{SEGMENT_LINE, {{{285.0f, 500.0f}}}},
{SEGMENT_LINE, {{{275.0f, 500.0f}}}},
/* Figure 12. */
{SEGMENT_BEZIER, {{{2.83333340e+01f, 1.60000000e+02f},
{4.00000000e+01f, 1.13333336e+02f},
{4.00000000e+01f, 2.00000000e+01f}}}},
{SEGMENT_BEZIER, {{{4.00000000e+01f, 1.13333336e+02f},
{5.16666641e+01f, 1.60000000e+02f},
{7.50000000e+01f, 1.60000000e+02f}}}},
{SEGMENT_BEZIER, {{{5.16666641e+01f, 1.60000000e+02f},
{4.00000000e+01f, 2.06666656e+02f},
{4.00000000e+01f, 3.00000000e+02f}}}},
{SEGMENT_BEZIER, {{{4.00000000e+01f, 2.06666656e+02f},
{2.83333340e+01f, 1.60000000e+02f},
{5.00000000e+00f, 1.60000000e+02f}}}},
/* Figure 13. */
{SEGMENT_BEZIER, {{{2.00000000e+01f, 1.06666664e+02f},
{2.66666660e+01f, 8.00000000e+01f},
{4.00000000e+01f, 8.00000000e+01f}}}},
{SEGMENT_BEZIER, {{{5.33333321e+01f, 8.00000000e+01f},
{6.00000000e+01f, 1.06666664e+02f},
{6.00000000e+01f, 1.60000000e+02f}}}},
{SEGMENT_BEZIER, {{{6.00000000e+01f, 2.13333328e+02f},
{5.33333321e+01f, 2.40000000e+02f},
{4.00000000e+01f, 2.40000000e+02f}}}},
{SEGMENT_BEZIER, {{{2.66666660e+01f, 2.40000000e+02f},
{2.00000000e+01f, 2.13333328e+02f},
{2.00000000e+01f, 1.60000000e+02f}}}},
/* Figure 14. */
{SEGMENT_BEZIER, {{{2.83333340e+01f, 6.12000000e+02f},
{4.00000000e+01f, 6.58666687e+02f},
{4.00000000e+01f, 7.52000000e+02f}}}},
{SEGMENT_BEZIER, {{{4.00000000e+01f, 6.58666687e+02f},
{5.16666641e+01f, 6.12000000e+02f},
{7.50000000e+01f, 6.12000000e+02f}}}},
{SEGMENT_BEZIER, {{{5.16666641e+01f, 6.12000000e+02f},
{4.00000000e+01f, 5.65333313e+02f},
{4.00000000e+01f, 4.72000000e+02f}}}},
{SEGMENT_BEZIER, {{{4.00000000e+01f, 5.65333313e+02f},
{2.83333340e+01f, 6.12000000e+02f},
{5.00000000e+00f, 6.12000000e+02f}}}},
/* Figure 15. */
{SEGMENT_BEZIER, {{{2.00000000e+01f, 6.65333313e+02f},
{2.66666660e+01f, 6.92000000e+02f},
{4.00000000e+01f, 6.92000000e+02f}}}},
{SEGMENT_BEZIER, {{{5.33333321e+01f, 6.92000000e+02f},
{6.00000000e+01f, 6.65333313e+02f},
{6.00000000e+01f, 6.12000000e+02f}}}},
{SEGMENT_BEZIER, {{{6.00000000e+01f, 5.58666687e+02f},
{5.33333321e+01f, 5.32000000e+02f},
{4.00000000e+01f, 5.32000000e+02f}}}},
{SEGMENT_BEZIER, {{{2.66666660e+01f, 5.32000000e+02f},
{2.00000000e+01f, 5.58666687e+02f},
{2.00000000e+01f, 6.12000000e+02f}}}},
/* Figure 16. */
{SEGMENT_BEZIER, {{{1.91750427e+02f, 1.27275856e+02f},
{2.08249573e+02f, 1.27275856e+02f},
{2.24748734e+02f, 6.12792168e+01f}}}},
{SEGMENT_BEZIER, {{{2.08249573e+02f, 1.27275856e+02f},
{2.08249573e+02f, 1.93272476e+02f},
{2.24748734e+02f, 2.59269104e+02f}}}},
{SEGMENT_BEZIER, {{{2.08249573e+02f, 1.93272476e+02f},
{1.91750427e+02f, 1.93272476e+02f},
{1.75251266e+02f, 2.59269104e+02f}}}},
{SEGMENT_BEZIER, {{{1.91750427e+02f, 1.93272476e+02f},
{1.91750427e+02f, 1.27275856e+02f},
{1.75251266e+02f, 6.12792168e+01f}}}},
/* Figure 17. */
{SEGMENT_BEZIER, {{{1.95285950e+02f, 6.59932632e+01f},
{2.04714050e+02f, 6.59932632e+01f},
{2.14142136e+02f, 1.03705627e+02f}}}},
{SEGMENT_BEZIER, {{{2.23570221e+02f, 1.41417984e+02f},
{2.23570221e+02f, 1.79130356e+02f},
{2.14142136e+02f, 2.16842712e+02f}}}},
{SEGMENT_BEZIER, {{{2.04714050e+02f, 2.54555069e+02f},
{1.95285950e+02f, 2.54555069e+02f},
{1.85857864e+02f, 2.16842712e+02f}}}},
{SEGMENT_BEZIER, {{{1.76429779e+02f, 1.79130356e+02f},
{1.76429779e+02f, 1.41417984e+02f},
{1.85857864e+02f, 1.03705627e+02f}}}},
/* Figure 18. */
{SEGMENT_BEZIER, {{{1.11847351e+02f, 4.46888092e+02f},
{1.11847351e+02f, 5.12884705e+02f},
{9.53481979e+01f, 5.78881348e+02f}}}},
{SEGMENT_BEZIER, {{{1.11847351e+02f, 5.12884705e+02f},
{1.28346512e+02f, 5.12884705e+02f},
{1.44845673e+02f, 5.78881348e+02f}}}},
{SEGMENT_BEZIER, {{{1.28346512e+02f, 5.12884705e+02f},
{1.28346512e+02f, 4.46888092e+02f},
{1.44845673e+02f, 3.80891479e+02f}}}},
{SEGMENT_BEZIER, {{{1.28346512e+02f, 4.46888092e+02f},
{1.11847351e+02f, 4.46888092e+02f},
{9.53481979e+01f, 3.80891479e+02f}}}},
/* Figure 19. */
{SEGMENT_BEZIER, {{{9.65267105e+01f, 4.61030243e+02f},
{9.65267105e+01f, 4.98742584e+02f},
{1.05954803e+02f, 5.36454956e+02f}}}},
{SEGMENT_BEZIER, {{{1.15382889e+02f, 5.74167297e+02f},
{1.24810982e+02f, 5.74167297e+02f},
{1.34239075e+02f, 5.36454956e+02f}}}},
{SEGMENT_BEZIER, {{{1.43667160e+02f, 4.98742584e+02f},
{1.43667160e+02f, 4.61030243e+02f},
{1.34239075e+02f, 4.23317871e+02f}}}},
{SEGMENT_BEZIER, {{{1.24810982e+02f, 3.85605499e+02f},
{1.15382889e+02f, 3.85605499e+02f},
{1.05954803e+02f, 4.23317871e+02f}}}},
/* Figure 20. */
{SEGMENT_LINE, {{{ 40.0f, 20.0f}}}},
{SEGMENT_LINE, {{{ 75.0f, 160.0f}}}},
{SEGMENT_LINE, {{{ 40.0f, 300.0f}}}},
{SEGMENT_LINE, {{{ 5.0f, 160.0f}}}},
/* Figure 21. */
{SEGMENT_LINE, {{{ 40.0f, 80.0f}}}},
{SEGMENT_LINE, {{{ 60.0f, 160.0f}}}},
{SEGMENT_LINE, {{{ 40.0f, 240.0f}}}},
{SEGMENT_LINE, {{{ 20.0f, 160.0f}}}},
/* Figure 22. */
{SEGMENT_LINE, {{{ 40.0f, 752.0f}}}},
{SEGMENT_LINE, {{{ 75.0f, 612.0f}}}},
{SEGMENT_LINE, {{{ 40.0f, 472.0f}}}},
{SEGMENT_LINE, {{{ 5.0f, 612.0f}}}},
/* Figure 23. */
{SEGMENT_LINE, {{{ 40.0f, 692.0f}}}},
{SEGMENT_LINE, {{{ 60.0f, 612.0f}}}},
{SEGMENT_LINE, {{{ 40.0f, 532.0f}}}},
{SEGMENT_LINE, {{{ 20.0f, 612.0f}}}},
/* Figure 24. */
{SEGMENT_LINE, {{{2.03125019e+01f, 1.51250000e+02f}}}},
{SEGMENT_LINE, {{{3.12500019e+01f, 1.25000008e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{3.78125000e+01f, 8.12500076e+01f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{4.00000000e+01f, 2.00000000e+01f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{4.21875000e+01f, 8.12500076e+01f}}}},
{SEGMENT_LINE, {{{4.87500000e+01f, 1.25000008e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{5.96875000e+01f, 1.51250000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{7.50000000e+01f, 1.60000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{5.96875000e+01f, 1.68750000e+02f}}}},
{SEGMENT_LINE, {{{4.87500000e+01f, 1.95000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{4.21875000e+01f, 2.38750000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{4.00000000e+01f, 3.00000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{3.78125000e+01f, 2.38750000e+02f}}}},
{SEGMENT_LINE, {{{3.12500019e+01f, 1.95000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{2.03125019e+01f, 1.68750000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{5.00000000e+00f, 1.60000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
/* Figure 25. */
{SEGMENT_LINE, {{{2.50000000e+01f, 1.00000000e+02f}}}},
{SEGMENT_LINE, {{{4.00000000e+01f, 8.00000000e+01f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{5.50000000e+01f, 1.00000000e+02f}}}},
{SEGMENT_LINE, {{{6.00000000e+01f, 1.60000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{5.50000000e+01f, 2.20000000e+02f}}}},
{SEGMENT_LINE, {{{4.00000000e+01f, 2.40000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{2.50000000e+01f, 2.20000000e+02f}}}},
{SEGMENT_LINE, {{{2.00000000e+01f, 1.60000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
/* Figure 26. */
{SEGMENT_LINE, {{{2.03125019e+01f, 6.20750000e+02f}}}},
{SEGMENT_LINE, {{{3.12500019e+01f, 6.47000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{3.78125000e+01f, 6.90750000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{4.00000000e+01f, 7.52000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{4.21875000e+01f, 6.90750000e+02f}}}},
{SEGMENT_LINE, {{{4.87500000e+01f, 6.47000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{5.96875000e+01f, 6.20750000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{7.50000000e+01f, 6.12000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{5.96875000e+01f, 6.03250000e+02f}}}},
{SEGMENT_LINE, {{{4.87500000e+01f, 5.77000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{4.21875000e+01f, 5.33250000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{4.00000000e+01f, 4.72000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{3.78125000e+01f, 5.33250000e+02f}}}},
{SEGMENT_LINE, {{{3.12500019e+01f, 5.77000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{2.03125019e+01f, 6.03250000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{5.00000000e+00f, 6.12000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
/* Figure 27. */
{SEGMENT_LINE, {{{2.50000000e+01f, 6.72000000e+02f}}}},
{SEGMENT_LINE, {{{4.00000000e+01f, 6.92000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{5.50000000e+01f, 6.72000000e+02f}}}},
{SEGMENT_LINE, {{{6.00000000e+01f, 6.12000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{5.50000000e+01f, 5.52000000e+02f}}}},
{SEGMENT_LINE, {{{4.00000000e+01f, 5.32000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
{SEGMENT_LINE, {{{2.50000000e+01f, 5.52000000e+02f}}}},
{SEGMENT_LINE, {{{2.00000000e+01f, 6.12000000e+02f}}}, D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN},
/* Figure 28. */
{SEGMENT_LINE, {{{ 75.0f, 300.0f}}}},
{SEGMENT_LINE, {{{ 5.0f, 300.0f}}}},
};
static const struct expected_geometry_figure expected_figures[] =
{
/* 0 */
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 15.0f, 20.0f}, 15, &expected_segments[0]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, {155.0f, 300.0f}, 11, &expected_segments[15]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, {165.0f, 20.0f}, 3, &expected_segments[26]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, {225.0f, 60.0f}, 3, &expected_segments[29]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, {215.0f, 220.0f}, 3, &expected_segments[32]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, {195.0f, 180.0f}, 3, &expected_segments[35]},
/* 6 */
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 95.0f, 620.0f}, 15, &expected_segments[38]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, {235.0f, 340.0f}, 11, &expected_segments[53]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, {245.0f, 620.0f}, 3, &expected_segments[64]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, {305.0f, 580.0f}, 3, &expected_segments[67]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, {295.0f, 420.0f}, 3, &expected_segments[70]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, {275.0f, 460.0f}, 3, &expected_segments[73]},
/* 12 */
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 5.0f, 160.0f}, 4, &expected_segments[76]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 20.0f, 160.0f}, 4, &expected_segments[80]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 5.0f, 612.0f}, 4, &expected_segments[84]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 20.0f, 612.0f}, 4, &expected_segments[88]},
/* 16 */
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED,
{1.75251266e+02f, 6.12792168e+01f}, 4, &expected_segments[92]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED,
{1.85857864e+02f, 1.03705627e+02f}, 4, &expected_segments[96]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED,
{9.53481979e+01f, 3.80891479e+02f}, 4, &expected_segments[100]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED,
{1.05954803e+02f, 4.23317871e+02f}, 4, &expected_segments[104]},
/* 20 */
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 5.0f, 160.0f}, 4, &expected_segments[108]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 20.0f, 160.0f}, 4, &expected_segments[112]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 5.0f, 612.0f}, 4, &expected_segments[116]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 20.0f, 612.0f}, 4, &expected_segments[120]},
/* 24 */
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 5.0f, 160.0f}, 16, &expected_segments[124]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 20.0f, 160.0f}, 8, &expected_segments[140]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 5.0f, 612.0f}, 16, &expected_segments[148]},
{D2D1_FIGURE_BEGIN_FILLED, D2D1_FIGURE_END_CLOSED, { 20.0f, 612.0f}, 8, &expected_segments[164]},
/* 28 */
{D2D1_FIGURE_BEGIN_HOLLOW, D2D1_FIGURE_END_OPEN, { 40.0f, 20.0f}, 2, &expected_segments[172]},
};
if (!(device = create_device()))
{
skip("Failed to create device, skipping tests.\n");
@ -1778,21 +2177,47 @@ static void test_path_geometry(void)
ID2D1GeometrySink_SetFillMode(sink, D2D1_FILL_MODE_WINDING);
ID2D1GeometrySink_Release(sink);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_ALTERNATE, 6, &expected_figures[0], 0);
geometry_sink_cleanup(&simplify_sink);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
NULL, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_ALTERNATE, 6, &expected_figures[0], 0);
geometry_sink_cleanup(&simplify_sink);
set_matrix_identity(&matrix);
translate_matrix(&matrix, 80.0f, 640.0f);
scale_matrix(&matrix, 1.0f, -1.0f);
hr = ID2D1Factory_CreateTransformedGeometry(factory, (ID2D1Geometry *)geometry, &matrix, &transformed_geometry);
ok(SUCCEEDED(hr), "Failed to create transformed geometry, hr %#x.\n", hr);
geometry_sink_init(&simplify_sink);
hr = ID2D1TransformedGeometry_Simplify(transformed_geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_ALTERNATE, 6, &expected_figures[6], 0);
geometry_sink_cleanup(&simplify_sink);
ID2D1TransformedGeometry_GetSourceGeometry(transformed_geometry, &tmp_geometry);
ok(tmp_geometry == (ID2D1Geometry *)geometry,
"Got unexpected source geometry %p, expected %p.\n", tmp_geometry, geometry);
ID2D1Geometry_Release(tmp_geometry);
ID2D1TransformedGeometry_GetTransform(transformed_geometry, &tmp_matrix);
ok(!memcmp(&tmp_matrix, &matrix, sizeof(matrix)),
"Got unexpected matrix {%.8e, %.8e, %.8e, %.8e, %.8e, %.8e}.\n",
tmp_matrix._11, tmp_matrix._12, tmp_matrix._21,
tmp_matrix._22, tmp_matrix._31, tmp_matrix._32);
geometry_sink_init(&simplify_sink);
hr = ID2D1Geometry_Simplify(tmp_geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
&tmp_matrix, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_ALTERNATE, 6, &expected_figures[6], 0);
geometry_sink_cleanup(&simplify_sink);
ID2D1Geometry_Release(tmp_geometry);
ID2D1RenderTarget_BeginDraw(rt);
set_color(&color, 0.396f, 0.180f, 0.537f, 1.0f);
@ -1845,6 +2270,13 @@ static void test_path_geometry(void)
ok(count == 44, "Got unexpected segment count %u.\n", count);
ID2D1GeometrySink_Release(sink);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_WINDING, 6, &expected_figures[0], 0);
geometry_sink_cleanup(&simplify_sink);
set_matrix_identity(&matrix);
translate_matrix(&matrix, 320.0f, 320.0f);
scale_matrix(&matrix, -1.0f, 1.0f);
@ -1877,6 +2309,25 @@ static void test_path_geometry(void)
ok(count == 20, "Got unexpected segment count %u.\n", count);
ID2D1GeometrySink_Release(sink);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
NULL, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_ALTERNATE, 4, &expected_figures[12], 1);
geometry_sink_cleanup(&simplify_sink);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, 100.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_ALTERNATE, 4, &expected_figures[20], 1);
geometry_sink_cleanup(&simplify_sink);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, 10.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_ALTERNATE, 4, &expected_figures[24], 1);
geometry_sink_cleanup(&simplify_sink);
set_matrix_identity(&matrix);
scale_matrix(&matrix, 0.5f, 2.0f);
translate_matrix(&matrix, 400.0f, -33.0f);
@ -1885,6 +2336,13 @@ static void test_path_geometry(void)
hr = ID2D1Factory_CreateTransformedGeometry(factory, (ID2D1Geometry *)geometry, &matrix, &transformed_geometry);
ok(SUCCEEDED(hr), "Failed to create transformed geometry, hr %#x.\n", hr);
geometry_sink_init(&simplify_sink);
hr = ID2D1TransformedGeometry_Simplify(transformed_geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
NULL, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_ALTERNATE, 4, &expected_figures[16], 4);
geometry_sink_cleanup(&simplify_sink);
ID2D1RenderTarget_BeginDraw(rt);
ID2D1RenderTarget_Clear(rt, &color);
ID2D1RenderTarget_FillGeometry(rt, (ID2D1Geometry *)geometry, (ID2D1Brush *)brush, NULL);
@ -1954,6 +2412,25 @@ static void test_path_geometry(void)
ok(count == 20, "Got unexpected segment count %u.\n", count);
ID2D1GeometrySink_Release(sink);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
NULL, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_WINDING, 4, &expected_figures[12], 1);
geometry_sink_cleanup(&simplify_sink);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, 100.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_WINDING, 4, &expected_figures[20], 1);
geometry_sink_cleanup(&simplify_sink);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, 10.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_WINDING, 4, &expected_figures[24], 1);
geometry_sink_cleanup(&simplify_sink);
set_matrix_identity(&matrix);
scale_matrix(&matrix, 0.5f, 2.0f);
translate_matrix(&matrix, 127.0f, 80.0f);
@ -2039,6 +2516,28 @@ static void test_path_geometry(void)
ok(match, "Surface does not match.\n");
ID2D1PathGeometry_Release(geometry);
hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
hr = ID2D1PathGeometry_Open(geometry, &sink);
ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr);
set_point(&point, 40.0f, 20.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
line_to(sink, 75.0f, 300.0f);
line_to(sink, 5.0f, 300.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
hr = ID2D1GeometrySink_Close(sink);
ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr);
ID2D1GeometrySink_Release(sink);
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
ok(SUCCEEDED(hr), "Failed to simplify geometry, hr %#x.\n", hr);
geometry_sink_check(&simplify_sink, D2D1_FILL_MODE_ALTERNATE, 1, &expected_figures[28], 1);
geometry_sink_cleanup(&simplify_sink);
ID2D1PathGeometry_Release(geometry);
ID2D1SolidColorBrush_Release(brush);
ID2D1RenderTarget_Release(rt);
refcount = ID2D1Factory_Release(factory);
@ -2049,80 +2548,6 @@ static void test_path_geometry(void)
DestroyWindow(window);
}
#define geometry_sink_check(a, b, c, d, e) geometry_sink_check_(__LINE__, a, b, c, d, e)
static void geometry_sink_check_(unsigned int line, const struct geometry_sink *sink, D2D1_FILL_MODE fill_mode,
unsigned int figure_count, const struct expected_geometry_figure *expected_figures, unsigned int ulps)
{
const struct geometry_segment *segment, *expected_segment;
const struct expected_geometry_figure *expected_figure;
const struct geometry_figure *figure;
unsigned int i, j;
BOOL match;
ok_(__FILE__, line)(sink->fill_mode == D2D1_FILL_MODE_ALTERNATE,
"Got unexpected fill mode %#x.\n", sink->fill_mode);
ok_(__FILE__, line)(sink->figure_count == 1, "Got unexpected figure count %u.\n", sink->figure_count);
ok_(__FILE__, line)(!sink->closed, "Sink is closed.\n");
for (i = 0; i < figure_count; ++i)
{
expected_figure = &expected_figures[i];
figure = &sink->figures[i];
ok_(__FILE__, line)(figure->begin == expected_figure->begin,
"Got unexpected figure %u begin %#x, expected %#x.\n",
i, figure->begin, expected_figure->begin);
ok_(__FILE__, line)(figure->end == expected_figure->end,
"Got unexpected figure %u end %#x, expected %#x.\n",
i, figure->end, expected_figure->end);
match = compare_point(&figure->start_point,
expected_figure->start_point.x, expected_figure->start_point.y, ulps);
ok_(__FILE__, line)(match, "Got unexpected figure %u start point {%.8e, %.8e}, expected {%.8e, %.8e}.\n",
i, figure->start_point.x, figure->start_point.y,
expected_figure->start_point.x, expected_figure->start_point.y);
ok_(__FILE__, line)(figure->segment_count == expected_figure->segment_count,
"Got unexpected figure %u segment count %u, expected %u.\n",
i, figure->segment_count, expected_figure->segment_count);
for (j = 0; j < figure->segment_count; ++j)
{
expected_segment = &expected_figure->segments[j];
segment = &figure->segments[j];
ok_(__FILE__, line)(segment->type == expected_segment->type,
"Got unexpected figure %u, segment %u type %#x, expected %#x.\n",
i, j, segment->type, expected_segment->type);
switch (segment->type)
{
case SEGMENT_LINE:
match = compare_point(&segment->u.line,
expected_segment->u.line.x, expected_segment->u.line.y, ulps);
ok_(__FILE__, line)(match, "Got unexpected figure %u segment %u {%.8e, %.8e}, "
"expected {%.8e, %.8e}.\n",
i, j, segment->u.line.x, segment->u.line.y,
expected_segment->u.line.x, expected_segment->u.line.y);
break;
case SEGMENT_BEZIER:
match = compare_bezier_segment(&segment->u.bezier,
expected_segment->u.bezier.point1.x, expected_segment->u.bezier.point1.y,
expected_segment->u.bezier.point2.x, expected_segment->u.bezier.point2.y,
expected_segment->u.bezier.point3.x, expected_segment->u.bezier.point3.y,
ulps);
ok_(__FILE__, line)(match, "Got unexpected figure %u segment %u "
"{%.8e, %.8e, %.8e, %.8e, %.8e, %.8e}, "
"expected {%.8e, %.8e, %.8e, %.8e, %.8e, %.8e}.\n",
i, j, segment->u.bezier.point1.x, segment->u.bezier.point1.y,
segment->u.bezier.point2.x, segment->u.bezier.point2.y,
segment->u.bezier.point3.x, segment->u.bezier.point3.y,
expected_segment->u.bezier.point1.x, expected_segment->u.bezier.point1.y,
expected_segment->u.bezier.point2.x, expected_segment->u.bezier.point2.y,
expected_segment->u.bezier.point3.x, expected_segment->u.bezier.point3.y);
break;
}
}
}
}
static void test_rectangle_geometry(void)
{
ID2D1TransformedGeometry *transformed_geometry;