[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