From 548673a248b88210472da2d1562c71e0fa946844 Mon Sep 17 00:00:00 2001 From: Cameron White Date: Sat, 21 Feb 2015 14:07:42 -0500 Subject: [PATCH] Fix the Crop to Selection tool. The StrokeExtents method used to return an incorrect rectangle (fixed upstream by https://github.com/mono/gtk-sharp/pull/56), and parts of Pinta attempted to compensate for this. To allow Pinta to work correctly regardless of what version of Mono.Cairo is being used, the FixedStrokeExtents method directly calls the cairo_stroke_extents method. --- Pinta.Core/Extensions/CairoExtensions.cs | 62 +++++++++++++++++++++++--------- Pinta.Tools/Brushes/PlainBrush.cs | 2 +- Pinta.Tools/Brushes/SplatterBrush.cs | 2 +- Pinta.Tools/Brushes/SquaresBrush.cs | 2 +- 4 files changed, 49 insertions(+), 19 deletions(-) diff --git a/Pinta.Core/Extensions/CairoExtensions.cs b/Pinta.Core/Extensions/CairoExtensions.cs index 62a5522..229ba28 100644 --- a/Pinta.Core/Extensions/CairoExtensions.cs +++ b/Pinta.Core/Extensions/CairoExtensions.cs @@ -36,6 +36,7 @@ using System; using Cairo; using System.Collections.Generic; +using System.Runtime.InteropServices; namespace Pinta.Core { @@ -63,7 +64,7 @@ namespace Pinta.Core g.LineWidth = lineWidth; g.LineCap = LineCap.Square; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Stroke (); g.Restore (); @@ -99,7 +100,7 @@ namespace Pinta.Core g.Color = color; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Fill (); g.Restore (); @@ -119,7 +120,7 @@ namespace Pinta.Core g.Pattern = pattern; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Fill (); g.Restore (); @@ -140,7 +141,7 @@ namespace Pinta.Core g.Color = color; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Stroke (); g.Restore (); @@ -158,7 +159,7 @@ namespace Pinta.Core g.Color = color; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Fill (); g.Restore (); @@ -192,7 +193,7 @@ namespace Pinta.Core g.LineWidth = lineWidth; g.LineCap = LineCap.Square; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Stroke (); g.Restore (); @@ -222,7 +223,7 @@ namespace Pinta.Core g.Color = color; g.LineWidth = lineWidth; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Stroke (); g.Restore (); @@ -251,7 +252,7 @@ namespace Pinta.Core g.Color = color; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Fill (); g.Restore (); @@ -310,7 +311,7 @@ namespace Pinta.Core g.Color = stroke; g.LineWidth = lineWidth; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Stroke (); g.Restore (); @@ -341,7 +342,7 @@ namespace Pinta.Core g.Color = stroke; g.LineWidth = lineWidth; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Stroke (); g.Restore (); @@ -368,7 +369,7 @@ namespace Pinta.Core g.Color = fill; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Fill (); g.Restore (); @@ -391,7 +392,7 @@ namespace Pinta.Core g.Color = color; - g.StrokeExtents (); + g.FixedStrokeExtents (); g.Fill (); } @@ -409,7 +410,7 @@ namespace Pinta.Core g.Color = stroke; g.LineWidth = lineWidth; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Stroke (); g.Restore (); @@ -468,7 +469,7 @@ namespace Pinta.Core g.LineWidth = lineWidth; g.LineCap = LineCap.Square; - Rectangle dirty = g.StrokeExtents (); + Rectangle dirty = g.FixedStrokeExtents (); g.Stroke (); g.Restore (); @@ -860,7 +861,7 @@ namespace Pinta.Core // of 1, but setting it to 0 returns an empty rectangle. Set // it to a sufficiently small width and rounding takes care of it g.LineWidth = .01; - rect = g.StrokeExtents (); + rect = g.FixedStrokeExtents (); } int x = (int)Math.Round (rect.X); @@ -868,7 +869,7 @@ namespace Pinta.Core int w = (int)Math.Round (rect.Width); int h = (int)Math.Round (rect.Height); - return new Gdk.Rectangle (x, y, w - x, h - y); + return new Gdk.Rectangle (x, y, w, h); } public static Gdk.Color ToGdkColor (this Cairo.Color color) @@ -1406,5 +1407,34 @@ namespace Pinta.Core { return new Gdk.Point ((int)point.X, (int)point.Y); } + + /// + /// Computes a bounding box in user coordinates covering the + /// area that would be affected by a call to Context.Stroke() + /// using the current stroke parameters. + /// + /// The rectangle returned by Cairo.Context.StrokeExtents() + /// incorrectly specifies the X and Y coordinates of the + /// bottom-right corner of the Rectangle in the width and + /// height members. This method corrects the rectangle to + /// contain the width and height in the width and height members. + /// + /// This can be removed once we port to GTK3. + /// + /// + /// The rectangle describing the area that would be + /// affected. + /// + public static Rectangle FixedStrokeExtents (this Context g) + { + double x1, y1, x2, y2; + cairo_stroke_extents (g.Handle, out x1, out y1, out x2, out y2); + return new Rectangle (x1, y1, x2 - x1, y2 - y1); + } + + private const string CairoLib = "libcairo-2.dll"; + + [DllImport (CairoLib, CallingConvention=CallingConvention.Cdecl)] + private static extern void cairo_stroke_extents (IntPtr cr, out double x1, out double y1, out double x2, out double y2); } } diff --git a/Pinta.Tools/Brushes/PlainBrush.cs b/Pinta.Tools/Brushes/PlainBrush.cs index 1546b19..11a1316 100644 --- a/Pinta.Tools/Brushes/PlainBrush.cs +++ b/Pinta.Tools/Brushes/PlainBrush.cs @@ -59,7 +59,7 @@ namespace Pinta.Tools.Brushes G.LineTo (x + 0.5, y + 0.5); G.StrokePreserve (); - return G.StrokeExtents ().ToGdkRectangle (); + return G.FixedStrokeExtents ().ToGdkRectangle (); } } } diff --git a/Pinta.Tools/Brushes/SplatterBrush.cs b/Pinta.Tools/Brushes/SplatterBrush.cs index d75e0d8..94c9742 100644 --- a/Pinta.Tools/Brushes/SplatterBrush.cs +++ b/Pinta.Tools/Brushes/SplatterBrush.cs @@ -75,7 +75,7 @@ namespace Pinta.Tools.Brushes G.ClosePath (); - Rectangle dirty = G.StrokeExtents (); + Rectangle dirty = G.FixedStrokeExtents (); G.Fill (); G.Restore (); diff --git a/Pinta.Tools/Brushes/SquaresBrush.cs b/Pinta.Tools/Brushes/SquaresBrush.cs index 8eb3504..b4804f0 100644 --- a/Pinta.Tools/Brushes/SquaresBrush.cs +++ b/Pinta.Tools/Brushes/SquaresBrush.cs @@ -54,7 +54,7 @@ namespace Pinta.Tools.Brushes G.StrokePreserve (); - return G.StrokeExtents ().ToGdkRectangle (); + return G.FixedStrokeExtents ().ToGdkRectangle (); } } } -- 1.9.1