 
            Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v2: d2d1: Implement ComputeArea() for path geometries. d2d1/tests: Add a ComputeArea() test for the path geometry. d2d1: Implement Tessellate() for rounded rectangle geometries. d2d1: Implement Tessellate() for rectangle geometries. d2d1: Implement Tessellate() for ellipse geometries. d2d1: Implement Tessellate() for path geometries.
 
            From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d2d1/geometry.c | 71 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 3dba8c7dc0d..c63e1d66fb7 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -3829,12 +3829,79 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry1 * return S_OK; }
+static HRESULT d2d_geometry_get_simplified(ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, + float tolerance, ID2D1PathGeometry **ret) +{ + ID2D1PathGeometry *path_geometry = NULL; + ID2D1GeometrySink *geometry_sink = NULL; + ID2D1Factory *factory; + HRESULT hr; + + *ret = NULL; + + ID2D1Geometry_GetFactory(geometry, &factory); + + hr = ID2D1Factory_CreatePathGeometry(factory, &path_geometry); + if (SUCCEEDED(hr)) + hr = ID2D1PathGeometry_Open(path_geometry, &geometry_sink); + if (SUCCEEDED(hr)) + { + hr = ID2D1Geometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES, + transform, tolerance, (ID2D1SimplifiedGeometrySink *)geometry_sink); + } + if (SUCCEEDED(hr)) + hr = ID2D1GeometrySink_Close(geometry_sink); + if (geometry_sink) + ID2D1GeometrySink_Release(geometry_sink); + + if (SUCCEEDED(hr)) + { + *ret = path_geometry; + ID2D1PathGeometry_AddRef(*ret); + } + + if (path_geometry) + ID2D1PathGeometry_Release(path_geometry); + ID2D1Factory_Release(factory); + + return hr; +} + +static HRESULT d2d_geometry_tessellate(ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, + float tolerance, ID2D1TessellationSink *sink) +{ + ID2D1PathGeometry *path_geometry; + HRESULT hr; + + if (SUCCEEDED(hr = d2d_geometry_get_simplified(geometry, transform, tolerance, &path_geometry))) + { + struct d2d_geometry *path_impl = unsafe_impl_from_ID2D1Geometry((ID2D1Geometry *)path_geometry); + D2D1_TRIANGLE t; + + for (size_t i = 0; i < path_impl->fill.face_count; ++i) + { + const struct d2d_face *face = &path_impl->fill.faces[i]; + + t.point1 = path_impl->fill.vertices[face->v[0]]; + t.point2 = path_impl->fill.vertices[face->v[1]]; + t.point3 = path_impl->fill.vertices[face->v[2]]; + ID2D1TessellationSink_AddTriangles(sink, &t, 1); + } + + ID2D1PathGeometry_Release(path_geometry); + } + + return hr; +} + static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry1 *iface, const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink) { - FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink); + struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
- return E_NOTIMPL; + TRACE("iface %p, transform %p, tolerance %.8e, sink %p.\n", iface, transform, tolerance, sink); + + return d2d_geometry_tessellate(&geometry->ID2D1Geometry_iface, transform, tolerance, sink); }
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_CombineWithGeometry(ID2D1PathGeometry1 *iface,
 
            From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d2d1/geometry.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index c63e1d66fb7..712c23f478c 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -4239,9 +4239,11 @@ static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Simplify(ID2D1EllipseGeome static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_Tessellate(ID2D1EllipseGeometry *iface, const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink) { - FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink); + struct d2d_geometry *geometry = impl_from_ID2D1EllipseGeometry(iface);
- return E_NOTIMPL; + TRACE("iface %p, transform %p, tolerance %.8e, sink %p.\n", iface, transform, tolerance, sink); + + return d2d_geometry_tessellate(&geometry->ID2D1Geometry_iface, transform, tolerance, sink); }
static HRESULT STDMETHODCALLTYPE d2d_ellipse_geometry_CombineWithGeometry(ID2D1EllipseGeometry *iface,
 
            From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d2d1/geometry.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 712c23f478c..c2d4152e052 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -4647,9 +4647,11 @@ static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Simplify(ID2D1RectangleG static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Tessellate(ID2D1RectangleGeometry *iface, const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink) { - FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink); + struct d2d_geometry *geometry = impl_from_ID2D1RectangleGeometry(iface);
- return E_NOTIMPL; + TRACE("iface %p, transform %p, tolerance %.8e, sink %p.\n", iface, transform, tolerance, sink); + + return d2d_geometry_tessellate(&geometry->ID2D1Geometry_iface, transform, tolerance, sink); }
static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_CombineWithGeometry(ID2D1RectangleGeometry *iface,
 
            From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d2d1/geometry.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index c2d4152e052..62dcea2827d 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -5026,9 +5026,11 @@ static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Simplify(ID2D1Ro static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_Tessellate(ID2D1RoundedRectangleGeometry *iface, const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink) { - FIXME("iface %p, transform %p, tolerance %.8e, sink %p stub!\n", iface, transform, tolerance, sink); + struct d2d_geometry *geometry = impl_from_ID2D1RoundedRectangleGeometry(iface);
- return E_NOTIMPL; + TRACE("iface %p, transform %p, tolerance %.8e, sink %p.\n", iface, transform, tolerance, sink); + + return d2d_geometry_tessellate(&geometry->ID2D1Geometry_iface, transform, tolerance, sink); }
static HRESULT STDMETHODCALLTYPE d2d_rounded_rectangle_geometry_CombineWithGeometry(
 
            From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d2d1/tests/d2d1.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 7b897d1265b..7506e6a9668 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -3308,6 +3308,7 @@ static void test_path_geometry(BOOL d3d11) D2D1_COLOR_F color; D2D1_RECT_F rect; UINT32 count; + float area; HRESULT hr;
static const struct geometry_segment expected_segments[] = @@ -4439,6 +4440,40 @@ static void test_path_geometry(BOOL d3d11) ID2D1PathGeometry_Release(geometry);
ID2D1SolidColorBrush_Release(brush); + + /* ComputeArea */ + hr = ID2D1Factory_CreatePathGeometry(factory, &geometry); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1PathGeometry_Open(geometry, &sink); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + set_point(&point, 0.0f, 0.0f); + ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED); + line_to(sink, 100.0f, 0.0f); + line_to(sink, 100.0f, 100.0f); + line_to(sink, 0.0f, 100.0f); + line_to(sink, 50.0f, 50.0f); + ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED); + + set_point(&point, -100.0f, -100.0f); + ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED); + line_to(sink, 60.0f, 40.0f); + line_to(sink, -100.0f, 100.0f); + line_to(sink, -50.0f, 0.0f); + ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED); + + hr = ID2D1GeometrySink_Close(sink); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID2D1GeometrySink_Release(sink); + + hr = ID2D1PathGeometry_ComputeArea(geometry, NULL, 1.0f, &area); + todo_wine + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ok(compare_float(area, 1.701948e4, 1), "Unexpected area value %.8e.\n", area); + + ID2D1PathGeometry_Release(geometry); + release_test_context(&ctx); }
 
            From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d2d1/geometry.c | 62 ++++++++++++++++++++++++++++++++---------- dlls/d2d1/tests/d2d1.c | 4 +-- 2 files changed, 48 insertions(+), 18 deletions(-)
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 62dcea2827d..4aaecda84e3 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -3894,6 +3894,49 @@ static HRESULT d2d_geometry_tessellate(ID2D1Geometry *geometry, const D2D1_MATRI return hr; }
+static float d2d_triangle_area(const D2D1_TRIANGLE *triangle) +{ + D2D1_POINT_2F point2, point3; + + /* Translate one vertex to origin */ + point2.x = triangle->point2.x - triangle->point1.x; + point2.y = triangle->point2.y - triangle->point1.y; + point3.x = triangle->point3.x - triangle->point1.x; + point3.y = triangle->point3.y - triangle->point1.y; + + return 0.5f * fabsf(point2.x * point3.y - point3.x * point2.y); +} + +static HRESULT d2d_geometry_compute_area(ID2D1Geometry *geometry, const D2D1_MATRIX_3X2_F *transform, + float tolerance, float *ret) +{ + ID2D1PathGeometry *path_geometry; + float area = 0.0f; + HRESULT hr; + + if (SUCCEEDED(hr = d2d_geometry_get_simplified(geometry, transform, tolerance, &path_geometry))) + { + struct d2d_geometry *path_impl = unsafe_impl_from_ID2D1Geometry((ID2D1Geometry *)path_geometry); + D2D1_TRIANGLE t; + + for (size_t i = 0; i < path_impl->fill.face_count; ++i) + { + const struct d2d_face *face = &path_impl->fill.faces[i]; + + t.point1 = path_impl->fill.vertices[face->v[0]]; + t.point2 = path_impl->fill.vertices[face->v[1]]; + t.point3 = path_impl->fill.vertices[face->v[2]]; + area += d2d_triangle_area(&t); + } + + *ret = area; + + ID2D1PathGeometry_Release(path_geometry); + } + + return hr; +} + static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Tessellate(ID2D1PathGeometry1 *iface, const D2D1_MATRIX_3X2_F *transform, float tolerance, ID2D1TessellationSink *sink) { @@ -3925,9 +3968,11 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Outline(ID2D1PathGeometry1 *i static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeArea(ID2D1PathGeometry1 *iface, const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area) { - FIXME("iface %p, transform %p, tolerance %.8e, area %p stub!\n", iface, transform, tolerance, area); + struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry1(iface);
- return E_NOTIMPL; + TRACE("iface %p, transform %p, tolerance %.8e, area %p.\n", iface, transform, tolerance, area); + + return d2d_geometry_compute_area(&geometry->ID2D1Geometry_iface, transform, tolerance, area); }
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry1 *iface, @@ -4672,19 +4717,6 @@ static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_Outline(ID2D1RectangleGe return E_NOTIMPL; }
-static float d2d_triangle_area(const D2D1_TRIANGLE *triangle) -{ - D2D1_POINT_2F point2, point3; - - /* Translate one vertex to origin */ - point2.x = triangle->point2.x - triangle->point1.x; - point2.y = triangle->point2.y - triangle->point1.y; - point3.x = triangle->point3.x - triangle->point1.x; - point3.y = triangle->point3.y - triangle->point1.y; - - return 0.5f * fabsf(point2.x * point3.y - point3.x * point2.y); -} - static HRESULT STDMETHODCALLTYPE d2d_rectangle_geometry_ComputeArea(ID2D1RectangleGeometry *iface, const D2D1_MATRIX_3X2_F *transform, float tolerance, float *area) { diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 7506e6a9668..b516974a21c 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -4467,10 +4467,8 @@ static void test_path_geometry(BOOL d3d11) ID2D1GeometrySink_Release(sink);
hr = ID2D1PathGeometry_ComputeArea(geometry, NULL, 1.0f, &area); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - ok(compare_float(area, 1.701948e4, 1), "Unexpected area value %.8e.\n", area); + ok(compare_float(area, 1.701948e4, 1), "Unexpected area value %.8e.\n", area);
ID2D1PathGeometry_Release(geometry);

