d2d1: Implement path_geometry_StrokeContainsPoint() for line segments.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
David White 2021-12-08 20:14:21 +01:00 committed by Alexandre Julliard
parent 1fceac2382
commit f467f6385e
2 changed files with 123 additions and 3 deletions

View File

@ -3409,11 +3409,74 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1Path
D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
float tolerance, BOOL *contains)
{
FIXME("iface %p, point %s, stroke_width %.8e, stroke_style %p, "
"transform %p, tolerance %.8e, contains %p stub!\n",
struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
D2D1_POINT_2F p, p1;
unsigned int i, j;
TRACE("iface %p, point %s, stroke_width %.8e, stroke_style %p, transform %p, tolerance %.8e, contains %p.\n",
iface, debug_d2d_point_2f(&point), stroke_width, stroke_style, transform, tolerance, contains);
return E_NOTIMPL;
if (stroke_style)
FIXME("Ignoring stroke style %p.\n", stroke_style);
if (!transform)
transform = &identity;
if (tolerance <= 0.0f)
tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
*contains = FALSE;
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];
type = figure->vertex_types[j];
break;
}
for (++j; j < figure->vertex_count; ++j)
{
if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE
|| d2d_vertex_type_is_split_bezier(figure->vertex_types[j]))
continue;
switch (type)
{
case D2D_VERTEX_TYPE_LINE:
p1 = figure->vertices[j];
*contains = d2d_point_on_line_segment(&point, &p, &p1, transform, stroke_width * 0.5f, tolerance);
p = p1;
break;
default:
FIXME("Unhandled vertex type %#x.\n", type);
p = figure->vertices[j];
break;
}
if (*contains)
return S_OK;
type = figure->vertex_types[j];
}
if (figure->flags & D2D_FIGURE_FLAG_CLOSED && (!*contains) && type == D2D_VERTEX_TYPE_LINE)
{
p1 = figure->vertices[0];
*contains = d2d_point_on_line_segment(&point, &p, &p1, transform, stroke_width * 0.5f, tolerance);
p = p1;
}
if (*contains)
return S_OK;
}
return S_OK;
}
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGeometry *iface,

View File

@ -10137,7 +10137,10 @@ static void test_effect_crop(BOOL d3d11)
static void test_stroke_contains_point(BOOL d3d11)
{
ID2D1RectangleGeometry *rectangle;
ID2D1GeometrySink *sink;
ID2D1PathGeometry *path;
ID2D1Factory *factory;
D2D1_POINT_2F point;
D2D1_RECT_F rect;
unsigned int i;
BOOL contains;
@ -10220,6 +10223,27 @@ static void test_stroke_contains_point(BOOL d3d11)
{{{{1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 21.0f}}}, {10.0f, 31.0f}, 0.0f, 1.0f, TRUE, TRUE},
{{{{1.0f, 0.0f, 0.0f, 1.0f, 11.0f, 0.0f}}}, {16.0f, 0.0f}, 0.0f, 1.0f, TRUE, TRUE},
{{{{1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -21.0f}}}, { 0.0f, -11.0f}, 0.0f, 1.0f, TRUE, TRUE},
},
path_tests[] =
{
/* 0. Stroked area hittesting. Edge. */
{{{{0.0f}}}, {160.0f, 600.0f}, 0.0f, 1.0f, FALSE, FALSE},
{{{{0.0f}}}, {239.24f, 600.0f}, 0.0f, 1.0f, FALSE, FALSE},
{{{{0.0f}}}, {239.26f, 600.0f}, 0.0f, 1.0f, FALSE, TRUE},
{{{{0.0f}}}, {240.74f, 600.0f}, 0.0f, 1.0f, FALSE, TRUE},
{{{{0.0f}}}, {240.76f, 600.0f}, 0.0f, 1.0f, FALSE, FALSE},
/* 5. Negative tolerance. */
{{{{0.0f}}}, {239.24f, 600.0f}, -1.0f, 1.0f, FALSE, FALSE},
{{{{0.0f}}}, {239.26f, 600.0f}, -1.0f, 1.0f, FALSE, TRUE},
{{{{0.0f}}}, {240.74f, 600.0f}, -1.0f, 1.0f, FALSE, TRUE},
{{{{0.0f}}}, {240.76f, 600.0f}, -1.0f, 1.0f, FALSE, FALSE},
/* 9. Less than default tolerance. */
{{{{0.0f}}}, {239.39f, 600.0f}, 0.1f, 1.0f, FALSE, FALSE},
{{{{0.0f}}}, {239.41f, 600.0f}, 0.1f, 1.0f, FALSE, TRUE},
{{{{0.0f}}}, {240.59f, 600.0f}, 0.1f, 1.0f, FALSE, TRUE},
{{{{0.0f}}}, {240.61f, 600.0f}, 0.1f, 1.0f, FALSE, FALSE},
};
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &IID_ID2D1Factory, NULL, (void **)&factory);
@ -10244,6 +10268,39 @@ static void test_stroke_contains_point(BOOL d3d11)
}
ID2D1RectangleGeometry_Release(rectangle);
hr = ID2D1Factory_CreatePathGeometry(factory, &path);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
hr = ID2D1PathGeometry_Open(path, &sink);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
set_point(&point, 160.0f, 240.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 240.0f, 240.0f);
line_to(sink, 240.0f, 720.0f);
line_to(sink, 160.0f, 720.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
hr = ID2D1GeometrySink_Close(sink);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
ID2D1GeometrySink_Release(sink);
for (i = 0; i < ARRAY_SIZE(path_tests); ++i)
{
const struct contains_point_test *test = &path_tests[i];
winetest_push_context("Test %u", i);
contains = !test->contains;
hr = ID2D1PathGeometry_StrokeContainsPoint(path, test->point, test->stroke_width,
NULL, test->matrix ? &test->transform : NULL, test->tolerance, &contains);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
ok(contains == test->contains, "Got unexpected result %#x.\n", contains);
winetest_pop_context();
}
ID2D1PathGeometry_Release(path);
ID2D1Factory_Release(factory);
}