From: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> --- dlls/d2d1/d2d1_private.h | 1 + dlls/d2d1/geometry.c | 166 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 161 insertions(+), 6 deletions(-) diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 6faf58f9d27..ff411385bd2 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -615,6 +615,7 @@ struct d2d_geometry ID2D1Geometry **src_geometries; UINT32 geometry_count; D2D1_FILL_MODE fill_mode; + ID2D1PathGeometry *path; } group; } u; }; diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index 9566113183c..07442260502 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -4255,6 +4255,17 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Open(ID2D1PathGeometry1 *ifac return S_OK; } +static inline void d2d_arc_transform(D2D1_ARC_SEGMENT *arc, const D2D1_MATRIX_3X2_F *transform) +{ + D2D_POINT_2F point; + + d2d_point_transform(&arc->point, transform, arc->point.x, arc->point.y); + d2d_point_transform(&point, transform, arc->size.width, 0.0f); + arc->size.width = d2d_point_length(&point); + d2d_point_transform(&point, transform, 0.0f, arc->size.height); + arc->size.height = d2d_point_length(&point); +} + static void d2d_path_geometry_transformed_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { @@ -4322,11 +4333,7 @@ static void d2d_path_geometry_transformed_stream(struct d2d_geometry *geometry, { D2D1_ARC_SEGMENT arc = s.arcs->segments[k]; - d2d_point_transform(&arc.point, transform, arc.point.x, arc.point.y); - d2d_point_transform(&point, transform, arc.size.width, 0.0f); - arc.size.width = d2d_point_length(&point); - d2d_point_transform(&point, transform, 0.0f, arc.size.height); - arc.size.height = d2d_point_length(&point); + d2d_arc_transform(&arc, transform); ID2D1GeometrySink_AddArc(sink, &arc); } size = FIELD_OFFSET(struct d2d_segment_arcs, segments[s.arcs->count]); @@ -4781,6 +4788,36 @@ static const struct ID2D1EllipseGeometryVtbl d2d_ellipse_geometry_vtbl = static void d2d_ellipse_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { + const D2D1_ELLIPSE *e = &geometry->u.ellipse.ellipse; + D2D1_POINT_2F start_point; + D2D1_ARC_SEGMENT arcs[4]; + + arcs[0].size.width = e->radiusX; + arcs[0].size.height = e->radiusY; + arcs[0].rotationAngle = 90.0f; + arcs[0].sweepDirection = D2D1_SWEEP_DIRECTION_CLOCKWISE; + arcs[0].arcSize = D2D1_ARC_SIZE_SMALL; + arcs[1] = arcs[2] = arcs[3] = arcs[0]; + + d2d_point_set(&start_point, e->point.x - e->radiusX, e->point.y); + d2d_point_set(&arcs[0].point, e->point.x, e->point.y - e->radiusY); + d2d_point_set(&arcs[1].point, e->point.x + e->radiusX, e->point.y); + d2d_point_set(&arcs[2].point, e->point.x, e->point.y + e->radiusY); + d2d_point_set(&arcs[3].point, start_point.x, start_point.y); + + if (transform) + { + d2d_point_transform(&start_point, transform, start_point.x, start_point.y); + for (int i = 0; i < ARRAYSIZE(arcs); ++i) + d2d_arc_transform(&arcs[i], transform); + } + + ID2D1GeometrySink_BeginFigure(sink, start_point, D2D1_FIGURE_BEGIN_FILLED); + + for (int i = 0; i < ARRAYSIZE(arcs); ++i) + ID2D1GeometrySink_AddArc(sink, &arcs[i]); + + ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED); } static const struct d2d_geometry_ops d2d_ellipse_geometry_ops = @@ -5218,9 +5255,34 @@ static const struct ID2D1RectangleGeometryVtbl d2d_rectangle_geometry_vtbl = d2d_rectangle_geometry_GetRect, }; +static void d2d_rectangle_stream(const D2D1_RECT_F *rect, const D2D1_MATRIX_3X2_F *transform, + ID2D1GeometrySink *sink) +{ + D2D1_POINT_2F p[4]; + unsigned int i; + + d2d_point_set(&p[0], rect->left, rect->top); + d2d_point_set(&p[1], rect->right, rect->top); + d2d_point_set(&p[2], rect->right, rect->bottom); + d2d_point_set(&p[3], rect->left, rect->bottom); + + if (transform) + { + for (i = 0; i < ARRAY_SIZE(p); ++i) + { + d2d_point_transform(&p[i], transform, p[i].x, p[i].y); + } + } + + ID2D1GeometrySink_BeginFigure(sink, p[0], D2D1_FIGURE_BEGIN_FILLED); + ID2D1GeometrySink_AddLines(sink, &p[1], 3); + ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED); +} + static void d2d_rectangle_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { + d2d_rectangle_stream(&geometry->u.rectangle.rect, transform, sink); } static const struct d2d_geometry_ops d2d_rectangle_geometry_ops = @@ -5580,6 +5642,49 @@ static const struct ID2D1RoundedRectangleGeometryVtbl d2d_rounded_rectangle_geom static void d2d_rounded_rectangle_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { + const D2D1_ROUNDED_RECT *r = &geometry->u.rounded_rectangle.rounded_rect; + D2D1_ARC_SEGMENT arcs[4]; + D2D1_POINT_2F points[4]; + + if (r->radiusX == 0.0f || r->radiusY == 0.0f) + return d2d_rectangle_stream(&r->rect, transform, sink); + + arcs[0].size.width = r->radiusX; + arcs[0].size.height = r->radiusY; + arcs[0].rotationAngle = 90.0f; + arcs[0].sweepDirection = D2D1_SWEEP_DIRECTION_CLOCKWISE; + arcs[0].arcSize = D2D1_ARC_SIZE_SMALL; + arcs[1] = arcs[2] = arcs[3] = arcs[0]; + + d2d_point_set(&points[0], r->rect.left, r->rect.top - r->radiusY); + d2d_point_set(&points[1], r->rect.right - r->radiusX, r->rect.top); + d2d_point_set(&points[2], r->rect.right, r->rect.bottom - r->radiusY); + d2d_point_set(&points[3], r->rect.left - r->radiusX, r->rect.bottom); + + d2d_point_set(&arcs[0].point, r->rect.left - r->radiusX, r->rect.top); + d2d_point_set(&arcs[1].point, r->rect.right, r->rect.top - r->radiusY); + d2d_point_set(&arcs[2].point, r->rect.right - r->radiusX, r->rect.bottom); + d2d_point_set(&arcs[3].point, r->rect.left, r->rect.bottom - r->radiusY); + + if (transform) + { + for (int i = 0; i < ARRAYSIZE(points); ++i) + d2d_point_transform(&points[i], transform, points[i].x, points[i].y); + for (int i = 0; i < ARRAYSIZE(arcs); ++i) + d2d_arc_transform(&arcs[i], transform); + } + + ID2D1GeometrySink_BeginFigure(sink, points[0], D2D1_FIGURE_BEGIN_FILLED); + + ID2D1GeometrySink_AddArc(sink, &arcs[0]); + ID2D1GeometrySink_AddLine(sink, points[1]); + ID2D1GeometrySink_AddArc(sink, &arcs[1]); + ID2D1GeometrySink_AddLine(sink, points[2]); + ID2D1GeometrySink_AddArc(sink, &arcs[2]); + ID2D1GeometrySink_AddLine(sink, points[3]); + ID2D1GeometrySink_AddArc(sink, &arcs[3]); + + ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED); } static const struct d2d_geometry_ops d2d_rounded_rectangle_geometry_ops = @@ -5952,9 +6057,20 @@ static const struct ID2D1TransformedGeometryVtbl d2d_transformed_geometry_vtbl = d2d_transformed_geometry_GetTransform, }; +static void d2d_geometry_stream(ID2D1Geometry *iface, const D2D_MATRIX_3X2_F *transform, + ID2D1GeometrySink *sink) +{ + struct d2d_geometry *geometry = unsafe_impl_from_ID2D1Geometry(iface); + geometry->ops->stream(geometry, transform, sink); +} + static void d2d_transformed_geometry_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { + D2D_MATRIX_3X2_F m = geometry->transform; + + d2d_matrix_multiply(&m, transform); + d2d_geometry_stream(geometry->u.transformed.src_geometry, &m, sink); } static const struct d2d_geometry_ops d2d_transformed_geometry_ops = @@ -6028,7 +6144,10 @@ static ULONG STDMETHODCALLTYPE d2d_geometry_group_Release(ID2D1GeometryGroup *if { for (i = 0; i < geometry->u.group.geometry_count; ++i) ID2D1Geometry_Release(geometry->u.group.src_geometries[i]); + ID2D1PathGeometry_Release(geometry->u.group.path); free(geometry->u.group.src_geometries); + memset(&geometry->outline, 0, sizeof(geometry->outline)); + memset(&geometry->fill, 0, sizeof(geometry->fill)); d2d_geometry_cleanup(geometry); free(geometry); } @@ -6237,6 +6356,7 @@ static const struct ID2D1GeometryGroupVtbl d2d_geometry_group_vtbl = static void d2d_geometry_group_stream(struct d2d_geometry *geometry, const D2D_MATRIX_3X2_F *transform, ID2D1GeometrySink *sink) { + d2d_geometry_stream((ID2D1Geometry *)geometry->u.group.path, NULL, sink); } static const struct d2d_geometry_ops d2d_geometry_group_ops = @@ -6247,7 +6367,9 @@ static const struct d2d_geometry_ops d2d_geometry_group_ops = HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *factory, D2D1_FILL_MODE fill_mode, ID2D1Geometry **geometries, unsigned int geometry_count) { + ID2D1GeometrySink *sink; unsigned int i; + HRESULT hr; d2d_geometry_init(geometry, factory, &identity, (ID2D1GeometryVtbl *)&d2d_geometry_group_vtbl, &d2d_geometry_group_ops); @@ -6265,7 +6387,39 @@ HRESULT d2d_geometry_group_init(struct d2d_geometry *geometry, ID2D1Factory *fac geometry->u.group.geometry_count = geometry_count; geometry->u.group.fill_mode = fill_mode; - return S_OK; + if (FAILED(hr = ID2D1Factory_CreatePathGeometry(factory, &geometry->u.group.path))) + { + d2d_geometry_cleanup(geometry); + return hr; + } + + if (SUCCEEDED(hr = ID2D1PathGeometry_Open(geometry->u.group.path, &sink))) + { + ID2D1GeometrySink_SetFillMode(sink, fill_mode); + for (i = 0; i < geometry_count; ++i) + { + ID2D1GeometrySink_SetSegmentFlags(sink, 0); + d2d_geometry_stream(geometries[i], NULL, sink); + } + hr = ID2D1GeometrySink_Close(sink); + ID2D1GeometrySink_Release(sink); + } + + if (SUCCEEDED(hr)) + { + struct d2d_geometry *path_impl = unsafe_impl_from_ID2D1Geometry((ID2D1Geometry *)geometry->u.group.path); + + geometry->fill = path_impl->fill; + geometry->outline = path_impl->outline; + } + + if (FAILED(hr)) + { + d2d_geometry_cleanup(geometry); + ID2D1PathGeometry_Release(geometry->u.group.path); + } + + return hr; } struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10043