From: Bernhard Kölbl bkoelbl@codeweavers.com
This is done by adding up the area of all triangulated faces, using Gauss's area formula for a singular triangle. --- dlls/d2d1/geometry.c | 26 +++++++++++- dlls/d2d1/tests/d2d1.c | 95 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 3dba8c7dc0d..f36e611b811 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -3858,9 +3858,31 @@ 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); + float result = 0.0f; + UINT32 i;
- return E_NOTIMPL; + TRACE("iface %p, transform %p, tolerance %.8e, area %p.\n", iface, transform, tolerance, area); + + for (i = 0; i < geometry->fill.face_count; ++i) + { + const struct d2d_face *face = &geometry->fill.faces[i]; + D2D1_POINT_2F a = geometry->fill.vertices[face->v[0]], + b = geometry->fill.vertices[face->v[1]], + c = geometry->fill.vertices[face->v[2]]; + + if (transform) + { + d2d_point_transform(&a, transform, a.x, a.y); + d2d_point_transform(&b, transform, b.x, b.y); + d2d_point_transform(&c, transform, c.x, c.y); + } + + result += fabs((a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y)); + } + + *area = result * .5f; + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_ComputeLength(ID2D1PathGeometry1 *iface, diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 14a986b019c..4b1329d293f 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15476,12 +15476,32 @@ static void test_effect_vertex_buffer(BOOL d3d11)
static void test_compute_geometry_area(BOOL d3d11) { + const D2D1_POINT_2F points_arrow[] = + { + { -200.0f, 50.0f }, + { -200.0f, 100.0f }, + { 200.0f, 100.0f }, + { 200.0f, 150.0f }, + { 300.0f, 75.0f }, + { 200.0f, 0.0f }, + { 200.0f, 50.0f }, + }; + const D2D1_POINT_2F points_square[] = + { + { -1.0f, -1.0f }, + { 1.0f, -1.0f }, + { 1.0f, 1.0f }, + { -1.0f, 1.0f }, + }; ID2D1TransformedGeometry *transformed_geometry; ID2D1RectangleGeometry *rectangle_geometry; ID2D1EllipseGeometry *ellipse_geometry; + ID2D1PathGeometry *path_geometry; struct d2d1_test_context ctx; D2D1_MATRIX_3X2_F matrix; + ID2D1GeometrySink *sink; D2D1_ELLIPSE ellipse; + D2D1_POINT_2F point; D2D1_RECT_F rect; HRESULT hr; float area; @@ -15596,6 +15616,81 @@ static void test_compute_geometry_area(BOOL d3d11) ID2D1TransformedGeometry_Release(transformed_geometry); ID2D1RectangleGeometry_Release(rectangle_geometry);
+ hr = ID2D1Factory_CreatePathGeometry(ctx.factory, &path_geometry); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1PathGeometry_Open(path_geometry, &sink); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + set_point(&point, -1.0f, -1.0f); + ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED); + ID2D1GeometrySink_AddLines(sink, points_square, ARRAY_SIZE(points_square)); + 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(path_geometry, NULL, 1.5f, &area); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(area == 4.0f, "Got area %f.\n", area); + + D2D1MakeSkewMatrix(45.0f , 45.0f, point, &matrix); + hr = ID2D1PathGeometry_ComputeArea(path_geometry, &matrix, 1.5f, &area); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(area == 0.0f, "Got area %f.\n", area); + + D2D1MakeSkewMatrix(30.0f , 30.0f, point, &matrix); + hr = ID2D1PathGeometry_ComputeArea(path_geometry, &matrix, 1.5f, &area); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(compare_float(area, 2.666667f, 3), "Got area %f.\n", area); + + ID2D1PathGeometry_Release(path_geometry); + + hr = ID2D1Factory_CreatePathGeometry(ctx.factory, &path_geometry); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1PathGeometry_Open(path_geometry, &sink); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + set_point(&point, -200.0f, 50.0f); + ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED); + ID2D1GeometrySink_AddLines(sink, points_arrow, ARRAY_SIZE(points_arrow)); + 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(path_geometry, NULL, 1.5f, &area); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(area == 27500.0f, "Got area %f.\n", area); + + D2D1MakeRotateMatrix(90.0f, point, &matrix); + hr = ID2D1PathGeometry_ComputeArea(path_geometry, NULL, 1.5f, &area); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(area == 27500.0f, "Got area %f.\n", area); + + ID2D1PathGeometry_Release(path_geometry); + + hr = ID2D1Factory_CreatePathGeometry(ctx.factory, &path_geometry); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1PathGeometry_Open(path_geometry, &sink); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + set_point(&point, -200.0f, 50.0f); + ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW); + ID2D1GeometrySink_AddLines(sink, points_arrow, ARRAY_SIZE(points_arrow)); + 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(path_geometry, NULL, 1.5f, &area); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(area == 0.0f, "Got area %f.\n", area); + + ID2D1PathGeometry_Release(path_geometry); + release_test_context(&ctx); }