[4/8] gdiplus: improved GdipGetPathWorldBounds
Evan Stade
estade at gmail.com
Thu Jul 12 21:43:03 CDT 2007
Hi,
The native version of this function behaves really weirdly, and does a
poor job of finding the smallest bounding box for a path. I've tried
to imitate windows as closely as possible, but the logic of their
approach has eluded me, and there's still some problems when both a
matrix and a pen are passed. Hopefully this isn't too important--I
doubt any programs rely on this being exactly correct beyond what the
function's description guarantees (i.e. returns a box bigger than the
path)
changelog:
* improved GdipGetPathWorldBounds handling of both matrix and pen's
effect on bounding box
* removed some todo_wines
dlls/gdiplus/graphicspath.c | 74 ++++++++++++++++++++++++++-----------
dlls/gdiplus/tests/graphicspath.c | 20 ++++------
2 files changed, 59 insertions(+), 35 deletions(-)
--
Evan Stade
-------------- next part --------------
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c
index e1342d8..c9779d4 100644
--- a/dlls/gdiplus/graphicspath.c
+++ b/dlls/gdiplus/graphicspath.c
@@ -212,12 +212,9 @@ GpStatus WINGDIPAPI GdipGetPathTypes(GpP
GpStatus WINGDIPAPI GdipGetPathWorldBounds(GpPath* path, GpRectF* bounds,
GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
{
- /* extrema[0] is upper left corner of bounding box,
- * extrema[1] is lower right corner */
- GpPointF extrema[2];
- GpPointF * points;
+ GpPointF * points, temp_pts[4];
INT count, i;
- REAL path_width;
+ REAL path_width = 1.0, width, height, temp, low_x, low_y, high_x, high_y;
/* Matrix and pen can be null. */
if(!path || !bounds)
@@ -231,33 +228,64 @@ GpStatus WINGDIPAPI GdipGetPathWorldBoun
}
points = path->pathdata.Points;
- extrema[0].X = extrema[1].X = points[0].X;
- extrema[0].Y = extrema[1].Y = points[0].Y;
+
+ low_x = high_x = points[0].X;
+ low_y = high_y = points[0].Y;
for(i = 1; i < count; i++){
- extrema[0].X = min(points[i].X, extrema[0].X);
- extrema[0].Y = min(points[i].Y, extrema[0].Y);
- extrema[1].X = max(points[i].X, extrema[1].X);
- extrema[1].Y = max(points[i].Y, extrema[1].Y);
+ low_x = min(low_x, points[i].X);
+ low_y = min(low_y, points[i].Y);
+ high_x = max(high_x, points[i].X);
+ high_y = max(high_y, points[i].Y);
}
- /* If matrix is non-null transform the points. */
+ width = high_x - low_x;
+ height = high_y - low_y;
+
+ /* This looks unusual but it's the only way I can imitate windows. */
if(matrix){
- GdipTransformMatrixPoints((GpMatrix*)matrix, extrema, 2);
+ temp_pts[0].X = low_x;
+ temp_pts[0].Y = low_y;
+ temp_pts[1].X = low_x;
+ temp_pts[1].Y = high_y;
+ temp_pts[2].X = high_x;
+ temp_pts[2].Y = high_y;
+ temp_pts[3].X = high_x;
+ temp_pts[3].Y = low_y;
+
+ GdipTransformMatrixPoints((GpMatrix*)matrix, temp_pts, 4);
+ low_x = temp_pts[0].X;
+ low_y = temp_pts[0].Y;
+
+ for(i = 1; i < 4; i++){
+ low_x = min(low_x, temp_pts[i].X);
+ low_y = min(low_y, temp_pts[i].Y);
+ }
+
+ temp = width;
+ width = height * fabs(matrix->matrix[2]) + width * fabs(matrix->matrix[0]);
+ height = height * fabs(matrix->matrix[3]) + temp * fabs(matrix->matrix[1]);
}
if(pen){
- path_width = pen->width * pen->miterlimit / 2.0;
- extrema[0].X -= path_width;
- extrema[0].Y -= path_width;
- extrema[1].X += path_width;
- extrema[1].Y += path_width;
+ path_width = pen->width / 2.0;
+
+ if(count > 2)
+ path_width = max(path_width, pen->width * pen->miterlimit / 2.0);
+ /* FIXME: this should probably also check for the startcap */
+ if(pen->endcap & LineCapNoAnchor)
+ path_width = max(path_width, pen->width * 2.2);
+
+ low_x -= path_width;
+ low_y -= path_width;
+ width += 2.0 * path_width;
+ height += 2.0 * path_width;
}
- bounds->X = extrema[0].X;
- bounds->Y = extrema[0].Y;
- bounds->Width = extrema[1].X - extrema[0].X;
- bounds->Height = extrema[1].Y - extrema[0].Y;
+ bounds->X = low_x;
+ bounds->Y = low_y;
+ bounds->Width = width;
+ bounds->Height = height;
return Ok;
}
diff --git a/dlls/gdiplus/tests/graphicspath.c b/dlls/gdiplus/tests/graphicspath.c
index 22aa882..7ee2cc3 100644
--- a/dlls/gdiplus/tests/graphicspath.c
+++ b/dlls/gdiplus/tests/graphicspath.c
@@ -315,12 +315,10 @@ static void test_worldbounds(void)
expect(Ok, status);
GdipDeletePath(path);
- todo_wine{
- expectf(156.0, bounds.X);
- expectf(156.0, bounds.Y);
- expectf(138.0, bounds.Width);
- expectf(88.0, bounds.Height);
- }
+ expectf(156.0, bounds.X);
+ expectf(156.0, bounds.Y);
+ expectf(138.0, bounds.Width);
+ expectf(88.0, bounds.Height);
line2_points[2].X = 2 * line2_points[1].X - line2_points[0].X;
line2_points[2].Y = 2 * line2_points[1].Y - line2_points[0].Y;
@@ -379,12 +377,10 @@ static void test_worldbounds(void)
expect(Ok, status);
GdipDeletePath(path);
- todo_wine{
- expectf(-209.6, bounds.X);
- expectf(-1274.8, bounds.Y);
- expectf(705.0, bounds.Width);
- expectf(945.0, bounds.Height);
- }
+ expectf(-209.6, bounds.X);
+ expectf(-1274.8, bounds.Y);
+ expectf(705.0, bounds.Width);
+ expectf(945.0, bounds.Height);
}
START_TEST(graphicspath)
--
1.4.1
More information about the wine-patches
mailing list