[PATCH] d2d1: Partially implement StrokeContainsPoint() for rectangle geometry
Nikolay Sivov
nsivov at codeweavers.com
Thu Aug 31 07:00:54 CDT 2017
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/d2d1/geometry.c | 79 ++++++++++++++++++++++++++++++++++++++------------
dlls/d2d1/tests/d2d1.c | 55 ++++++++++++++++++++++++++++++++++-
2 files changed, 115 insertions(+), 19 deletions(-)
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c
index 8c6688176f..9a520aec32 100644
--- a/dlls/d2d1/geometry.c
+++ b/dlls/d2d1/geometry.c
@@ -3078,6 +3078,21 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeo
return E_NOTIMPL;
}
+static HRESULT geometry_inv_transform_point(const D2D1_MATRIX_3X2_F *transform, D2D1_POINT_2F *point)
+{
+ D2D1_MATRIX_3X2_F inv;
+
+ if (!transform)
+ return S_OK;
+
+ if (!d2d_matrix_invert(&inv, transform))
+ return D2DERR_UNSUPPORTED_OPERATION;
+
+ d2d_point_transform(point, &inv, point->x, point->y);
+
+ return S_OK;
+}
+
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_StrokeContainsPoint(ID2D1PathGeometry *iface,
D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
float tolerance, BOOL *contains)
@@ -3093,17 +3108,13 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_FillContainsPoint(ID2D1PathGe
D2D1_POINT_2F point, const D2D1_MATRIX_3X2_F *transform, float tolerance, BOOL *contains)
{
struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
- D2D1_MATRIX_3X2_F g_i;
+ HRESULT hr;
TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
iface, point.x, point.y, transform, tolerance, contains);
- if (transform)
- {
- if (!d2d_matrix_invert(&g_i, transform))
- return D2DERR_UNSUPPORTED_OPERATION;
- d2d_point_transform(&point, &g_i, point.x, point.y);
- }
+ if (FAILED(hr = geometry_inv_transform_point(transform, &point)))
+ return hr;
*contains = !!d2d_path_geometry_point_inside(geometry, &point, FALSE);
@@ -3523,11 +3534,48 @@ static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_StrokeContainsPoint(ID2D
D2D1_POINT_2F point, float stroke_width, ID2D1StrokeStyle *stroke_style, const D2D1_MATRIX_3X2_F *transform,
float tolerance, BOOL *contains)
{
- FIXME("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
- "transform %p, tolerance %.8e, contains %p stub!\n",
+ struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
+ D2D1_RECT_F rect = geometry->u.rectangle.rect;
+ float dx, dy;
+ HRESULT hr;
+
+ TRACE("iface %p, point {%.8e, %.8e}, stroke_width %.8e, stroke_style %p, "
+ "transform %p, tolerance %.8e, contains %p.\n",
iface, point.x, point.y, stroke_width, stroke_style, transform, tolerance, contains);
- return E_NOTIMPL;
+ if (stroke_style)
+ FIXME("Stroke style ignored.\n");
+
+ if (FAILED(hr = geometry_inv_transform_point(transform, &point)))
+ return hr;
+
+ if (tolerance == 0.0f)
+ tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
+
+ stroke_width /= 2.0f;
+
+ rect = geometry->u.rectangle.rect;
+ rect.left -= stroke_width;
+ rect.right += stroke_width;
+ rect.top -= stroke_width;
+ rect.bottom += stroke_width;
+
+ dx = max(fabsf((rect.right + rect.left) / 2.0f - point.x) - (rect.right - rect.left) / 2.0f, 0.0f);
+ dy = max(fabsf((rect.bottom + rect.top) / 2.0f - point.y) - (rect.bottom - rect.top) / 2.0f, 0.0f);
+
+ if ((*contains = tolerance * tolerance > (dx * dx + dy * dy)))
+ {
+ rect = geometry->u.rectangle.rect;
+ stroke_width += tolerance;
+ rect.left += stroke_width;
+ rect.right -= stroke_width;
+ rect.top += stroke_width;
+ rect.bottom -= stroke_width;
+
+ *contains = rect.left >= point.x || rect.right <= point.x || rect.top >= point.y || rect.bottom <= point.y;
+ }
+
+ return S_OK;
}
static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1RectangleGeometry *iface,
@@ -3536,18 +3584,13 @@ static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_FillContainsPoint(ID2D1R
struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
D2D1_RECT_F *rect = &geometry->u.rectangle.rect;
float dx, dy;
+ HRESULT hr;
TRACE("iface %p, point {%.8e, %.8e}, transform %p, tolerance %.8e, contains %p.\n",
iface, point.x, point.y, transform, tolerance, contains);
- if (transform)
- {
- D2D1_MATRIX_3X2_F g_i;
-
- if (!d2d_matrix_invert(&g_i, transform))
- return D2DERR_UNSUPPORTED_OPERATION;
- d2d_point_transform(&point, &g_i, point.x, point.y);
- }
+ if (FAILED(hr = geometry_inv_transform_point(transform, &point)))
+ return hr;
if (tolerance == 0.0f)
tolerance = D2D1_DEFAULT_FLATTENING_TOLERANCE;
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index f6261295b6..3f18951913 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -2727,7 +2727,7 @@ static void test_rectangle_geometry(void)
hr = ID2D1Factory_CreateRectangleGeometry(factory, &rect, &geometry);
ok(SUCCEEDED(hr), "Failed to create geometry, hr %#x.\n", hr);
- /* Edge. */
+ /* Filled area hittesting. Edge. */
contains = FALSE;
set_point(&point, 0.0f, 0.0f);
hr = ID2D1RectangleGeometry_FillContainsPoint(geometry, point, NULL, 0.0f, &contains);
@@ -2766,6 +2766,59 @@ static void test_rectangle_geometry(void)
ok(SUCCEEDED(hr), "FillContainsPoint() failed, hr %#x.\n", hr);
ok(!!contains, "Got wrong hit test result %d.\n", contains);
+ /* Stroked area hittesting. Edge. */
+ contains = FALSE;
+ set_point(&point, 0.0f, 0.0f);
+ hr = ID2D1RectangleGeometry_StrokeContainsPoint(geometry, point, 1.0f, NULL, NULL, 0.0f, &contains);
+ ok(SUCCEEDED(hr), "StrokeContainsPoint() failed, hr %#x.\n", hr);
+ ok(!!contains, "Got wrong hit test result %d.\n", contains);
+
+ /* Within tolerance limit around corner. */
+ contains = TRUE;
+ set_point(&point, -D2D1_DEFAULT_FLATTENING_TOLERANCE - 1.0f, 0.0f);
+ hr = ID2D1RectangleGeometry_StrokeContainsPoint(geometry, point, 2.0f, NULL, NULL, 0.0f, &contains);
+ ok(SUCCEEDED(hr), "StrokeContainsPoint() failed, hr %#x.\n", hr);
+ ok(!contains, "Got wrong hit test result %d.\n", contains);
+
+ contains = TRUE;
+ set_point(&point, -D2D1_DEFAULT_FLATTENING_TOLERANCE - 1.01f, 0.0f);
+ hr = ID2D1RectangleGeometry_StrokeContainsPoint(geometry, point, 2.0f, NULL, NULL, 0.0f, &contains);
+ ok(SUCCEEDED(hr), "StrokeContainsPoint() failed, hr %#x.\n", hr);
+ ok(!contains, "Got wrong hit test result %d.\n", contains);
+
+ contains = FALSE;
+ set_point(&point, -D2D1_DEFAULT_FLATTENING_TOLERANCE, -D2D1_DEFAULT_FLATTENING_TOLERANCE);
+ hr = ID2D1RectangleGeometry_StrokeContainsPoint(geometry, point, 2.0f, NULL, NULL, 0.0f, &contains);
+ ok(SUCCEEDED(hr), "StrokeContainsPoint() failed, hr %#x.\n", hr);
+ ok(!!contains, "Got wrong hit test result %d.\n", contains);
+
+ contains = TRUE;
+ set_point(&point, -D2D1_DEFAULT_FLATTENING_TOLERANCE, -D2D1_DEFAULT_FLATTENING_TOLERANCE - 1.01f);
+ hr = ID2D1RectangleGeometry_StrokeContainsPoint(geometry, point, 2.0f, NULL, NULL, 0.0f, &contains);
+ ok(SUCCEEDED(hr), "StrokeContainsPoint() failed, hr %#x.\n", hr);
+ ok(!contains, "Got wrong hit test result %d.\n", contains);
+
+ /* Center point. */
+ contains = TRUE;
+ set_point(&point, 5.0f, 10.0f);
+ hr = ID2D1RectangleGeometry_StrokeContainsPoint(geometry, point, 1.0f, NULL, NULL, 0.0f, &contains);
+ ok(SUCCEEDED(hr), "StrokeContainsPoint() failed, hr %#x.\n", hr);
+ ok(!contains, "Got wrong hit test result %d.\n", contains);
+
+ /* Center point, large stroke width. */
+ contains = FALSE;
+ set_point(&point, 5.0f, 10.0f);
+ hr = ID2D1RectangleGeometry_StrokeContainsPoint(geometry, point, 100.0f, NULL, NULL, 0.0f, &contains);
+ ok(SUCCEEDED(hr), "StrokeContainsPoint() failed, hr %#x.\n", hr);
+ ok(!!contains, "Got wrong hit test result %d.\n", contains);
+
+ /* Center point, large tolerance. */
+ contains = FALSE;
+ set_point(&point, 5.0f, 10.0f);
+ hr = ID2D1RectangleGeometry_StrokeContainsPoint(geometry, point, 1.0f, NULL, NULL, 50.0f, &contains);
+ ok(SUCCEEDED(hr), "StrokeContainsPoint() failed, hr %#x.\n", hr);
+ ok(!!contains, "Got wrong hit test result %d.\n", contains);
+
/* Test GetBounds() and Simplify(). */
hr = ID2D1RectangleGeometry_GetBounds(geometry, NULL, &rect);
ok(SUCCEEDED(hr), "Failed to get bounds.\n");
--
2.14.1
More information about the wine-patches
mailing list