[PATCH 2/2] d2d1: Implement GetBounds() for path geometries
Nikolay Sivov
nsivov at codeweavers.com
Thu Sep 14 07:10:57 CDT 2017
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/d2d1/d2d1_private.h | 2 +
dlls/d2d1/geometry.c | 105 +++++++++++++++++++++++++++++++++++++++++-
dlls/d2d1/tests/d2d1.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 221 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h
index ff7927be66..f32c4d3f25 100644
--- a/dlls/d2d1/d2d1_private.h
+++ b/dlls/d2d1/d2d1_private.h
@@ -392,6 +392,8 @@ struct d2d_geometry
enum d2d_geometry_state state;
D2D1_FILL_MODE fill_mode;
UINT32 segment_count;
+
+ D2D1_RECT_F bounds;
} path;
struct
{
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c
index e38ac3444e..637078ea69 100644
--- a/dlls/d2d1/geometry.c
+++ b/dlls/d2d1/geometry.c
@@ -3079,9 +3079,106 @@ static void STDMETHODCALLTYPE d2d_path_geometry_GetFactory(ID2D1PathGeometry *if
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *iface,
const D2D1_MATRIX_3X2_F *transform, D2D1_RECT_F *bounds)
{
- FIXME("iface %p, transform %p, bounds %p stub!\n", iface, transform, bounds);
+ struct d2d_geometry *geometry = impl_from_ID2D1PathGeometry(iface);
+ size_t i;
- return E_NOTIMPL;
+ TRACE("iface %p, transform %p, bounds %p.\n", iface, transform, bounds);
+
+ if (geometry->u.path.state != D2D_GEOMETRY_STATE_CLOSED)
+ return D2DERR_WRONG_STATE;
+
+ bounds->left = FLT_MAX;
+ bounds->top = FLT_MAX;
+ bounds->right = -FLT_MAX;
+ bounds->bottom = -FLT_MAX;
+
+ if (!transform)
+ {
+ if (geometry->u.path.bounds.left > geometry->u.path.bounds.right)
+ {
+ for (i = 0; i < geometry->u.path.figure_count; ++i)
+ d2d_rect_union(&geometry->u.path.bounds, &geometry->u.path.figures[i].bounds);
+ }
+
+ *bounds = geometry->u.path.bounds;
+ return S_OK;
+ }
+
+ for (i = 0; i < geometry->u.path.figure_count; ++i)
+ {
+ const struct d2d_figure *figure = &geometry->u.path.figures[i];
+ enum d2d_vertex_type type = D2D_VERTEX_TYPE_NONE;
+ D2D1_RECT_F bezier_bounds;
+ D2D1_POINT_2F p, p1, p2;
+ size_t j, bezier_idx;
+
+ /* Single vertex figures are reduced by CloseFigure(). */
+ if (figure->vertex_count == 0)
+ {
+ d2d_point_transform(&p, transform, figure->bounds.left, figure->bounds.top);
+ d2d_rect_expand(bounds, &p);
+ continue;
+ }
+
+ 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];
+ d2d_point_transform(&p, transform, p.x, p.y);
+ d2d_rect_expand(bounds, &p);
+ break;
+ }
+
+ for (bezier_idx = 0, ++j; j < figure->vertex_count; ++j)
+ {
+ if (figure->vertex_types[j] == D2D_VERTEX_TYPE_NONE
+ || figure->vertex_types[j] == D2D_VERTEX_TYPE_SPLIT_BEZIER)
+ continue;
+
+ switch (type)
+ {
+ case D2D_VERTEX_TYPE_LINE:
+ p = figure->vertices[j];
+ d2d_point_transform(&p, transform, p.x, p.y);
+ d2d_rect_expand(bounds, &p);
+ break;
+
+ case D2D_VERTEX_TYPE_BEZIER:
+ p1 = figure->original_bezier_controls[bezier_idx++];
+ d2d_point_transform(&p1, transform, p1.x, p1.y);
+ p2 = figure->vertices[j];
+ d2d_point_transform(&p2, transform, p2.x, p2.y);
+ d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
+ d2d_rect_union(bounds, &bezier_bounds);
+ p = p2;
+ break;
+
+ default:
+ FIXME("Unhandled vertex type %#x.\n", type);
+ p = figure->vertices[j];
+ d2d_point_transform(&p, transform, p.x, p.y);
+ d2d_rect_expand(bounds, &p);
+ break;
+ }
+
+ type = figure->vertex_types[j];
+ }
+
+ if (type == D2D_VERTEX_TYPE_BEZIER)
+ {
+ p1 = figure->original_bezier_controls[bezier_idx++];
+ d2d_point_transform(&p1, transform, p1.x, p1.y);
+ p2 = figure->vertices[0];
+ d2d_point_transform(&p2, transform, p2.x, p2.y);
+ d2d_rect_get_bezier_bounds(&bezier_bounds, &p, &p1, &p2);
+ d2d_rect_union(bounds, &bezier_bounds);
+ }
+ }
+
+ return S_OK;
}
static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetWidenedBounds(ID2D1PathGeometry *iface, float stroke_width,
@@ -3428,6 +3525,10 @@ void d2d_path_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *factory
{
d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_path_geometry_vtbl);
geometry->u.path.ID2D1GeometrySink_iface.lpVtbl = &d2d_geometry_sink_vtbl;
+ geometry->u.path.bounds.left = FLT_MAX;
+ geometry->u.path.bounds.right = -FLT_MAX;
+ geometry->u.path.bounds.top = FLT_MAX;
+ geometry->u.path.bounds.bottom = -FLT_MAX;
}
static inline struct d2d_geometry *impl_from_ID2D1RectangleGeometry(ID2D1RectangleGeometry *iface)
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index f6261295b6..13d4bc88f7 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -1739,6 +1739,7 @@ static void test_path_geometry(void)
ID2D1Factory *factory;
BOOL match, contains;
D2D1_COLOR_F color;
+ D2D1_RECT_F rect;
ULONG refcount;
UINT32 count;
HWND window;
@@ -2216,6 +2217,7 @@ static void test_path_geometry(void)
ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
hr = ID2D1PathGeometry_Open(geometry, &sink);
ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr);
+ set_point(&point, 123.0f, 456.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
hr = ID2D1GeometrySink_Close(sink);
@@ -2227,6 +2229,102 @@ static void test_path_geometry(void)
hr = ID2D1PathGeometry_GetSegmentCount(geometry, &count);
ok(SUCCEEDED(hr), "Failed to get segment count, hr %#x.\n", hr);
ok(count == 1, "Got unexpected segment count %u.\n", count);
+
+ set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
+ hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
+ ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
+ match = compare_rect(&rect, 123.0f, 456.0f, 123.0f, 456.0f, 0);
+ ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
+ rect.left, rect.top, rect.right, rect.bottom);
+
+ set_matrix_identity(&matrix);
+ translate_matrix(&matrix, 80.0f, 640.0f);
+ scale_matrix(&matrix, 2.0f, 0.5f);
+ hr = ID2D1PathGeometry_GetBounds(geometry, &matrix, &rect);
+ ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
+ match = compare_rect(&rect, 326.0f, 868.0f, 326.0f, 868.0f, 0);
+ ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
+ rect.left, rect.top, rect.right, rect.bottom);
+
+ ID2D1PathGeometry_Release(geometry);
+
+ /* Close right after Open(). */
+ hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
+ ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
+
+ /* Not open yet. */
+ set_rect(&rect, 1.0f, 2.0f, 3.0f, 4.0f);
+ hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
+ ok(hr == D2DERR_WRONG_STATE, "Unexpected hr %#x.\n", hr);
+ match = compare_rect(&rect, 1.0f, 2.0f, 3.0f, 4.0f, 0);
+ ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
+ rect.left, rect.top, rect.right, rect.bottom);
+
+ hr = ID2D1PathGeometry_Open(geometry, &sink);
+ ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr);
+
+ /* Open, not closed. */
+ set_rect(&rect, 1.0f, 2.0f, 3.0f, 4.0f);
+ hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
+ ok(hr == D2DERR_WRONG_STATE, "Unexpected hr %#x.\n", hr);
+ match = compare_rect(&rect, 1.0f, 2.0f, 3.0f, 4.0f, 0);
+ ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
+ rect.left, rect.top, rect.right, rect.bottom);
+
+ hr = ID2D1GeometrySink_Close(sink);
+ ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr);
+ ID2D1GeometrySink_Release(sink);
+ hr = ID2D1PathGeometry_GetFigureCount(geometry, &count);
+ ok(SUCCEEDED(hr), "Failed to get figure count, hr %#x.\n", hr);
+ ok(count == 0, "Got unexpected figure count %u.\n", count);
+ hr = ID2D1PathGeometry_GetSegmentCount(geometry, &count);
+ ok(SUCCEEDED(hr), "Failed to get segment count, hr %#x.\n", hr);
+ ok(count == 0, "Got unexpected segment count %u.\n", count);
+
+ set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
+ hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
+ ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
+ ok(rect.left > rect.right && rect.top > rect.bottom,
+ "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n", rect.left, rect.top, rect.right, rect.bottom);
+
+ set_matrix_identity(&matrix);
+ translate_matrix(&matrix, 10.0f, 20.0f);
+ scale_matrix(&matrix, 10.0f, 20.0f);
+ set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
+ hr = ID2D1PathGeometry_GetBounds(geometry, &matrix, &rect);
+ ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
+ ok(rect.left > rect.right && rect.top > rect.bottom,
+ "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n", rect.left, rect.top, rect.right, rect.bottom);
+
+ ID2D1PathGeometry_Release(geometry);
+
+ /* GetBounds() with bezier segments. */
+ hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
+ ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
+ hr = ID2D1PathGeometry_Open(geometry, &sink);
+ ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr);
+ fill_geometry_sink_bezier(sink);
+ hr = ID2D1GeometrySink_Close(sink);
+ ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr);
+ ID2D1GeometrySink_Release(sink);
+
+ set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
+ hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
+ ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
+ match = compare_rect(&rect, 5.0f, 20.0f, 75.0f, 752.0f, 0);
+ ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
+ rect.left, rect.top, rect.right, rect.bottom);
+
+ set_matrix_identity(&matrix);
+ translate_matrix(&matrix, 80.0f, 640.0f);
+ scale_matrix(&matrix, 2.0f, 0.5f);
+ set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
+ hr = ID2D1PathGeometry_GetBounds(geometry, &matrix, &rect);
+ ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
+ match = compare_rect(&rect, 90.0f, 650.0f, 230.0f, 1016.0f, 0);
+ ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
+ rect.left, rect.top, rect.right, rect.bottom);
+
ID2D1PathGeometry_Release(geometry);
hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
@@ -2342,6 +2440,24 @@ static void test_path_geometry(void)
ok(count == 44, "Got unexpected segment count %u.\n", count);
ID2D1GeometrySink_Release(sink);
+ set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
+ hr = ID2D1PathGeometry_GetBounds(geometry, NULL, &rect);
+ ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
+ match = compare_rect(&rect, 5.0f, 20.0f, 235.0f, 300.0f, 0);
+ ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
+ rect.left, rect.top, rect.right, rect.bottom);
+
+ set_matrix_identity(&matrix);
+ translate_matrix(&matrix, 100.0f, 50.0f);
+ scale_matrix(&matrix, 2.0f, 1.5f);
+ rotate_matrix(&matrix, M_PI / 4.0f);
+ set_rect(&rect, 0.0f, 0.0f, 0.0f, 0.0f);
+ hr = ID2D1PathGeometry_GetBounds(geometry, &matrix, &rect);
+ ok(SUCCEEDED(hr), "Failed to get geometry bounds, hr %#x.\n", hr);
+ match = compare_rect(&rect, -3.17192993e+02f, 8.71231079e+01f, 4.04055908e+02f, 6.17453125e+02f, 1);
+ ok(match, "Got unexpected rectangle {%.8e, %.8e, %.8e, %.8e}.\n",
+ rect.left, rect.top, rect.right, rect.bottom);
+
geometry_sink_init(&simplify_sink);
hr = ID2D1PathGeometry_Simplify(geometry, D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, 0.0f, &simplify_sink.ID2D1SimplifiedGeometrySink_iface);
--
2.14.1
More information about the wine-patches
mailing list