fixing visible window for containers
[mono.git] / mcs / class / System.Drawing / System.Drawing.Drawing2D / ExtendedGeneralPath.jvm.cs
index 2ce4d614a21f0538260e994b327723c796ef9105..993857cf724d6a01e566a33b23f184005cf0266d 100644 (file)
@@ -1,3 +1,31 @@
+//
+// System.Drawing.Drawing2D.ExtendedGeneralPath.cs
+//
+// Author:
+// Bors Kirzner <boris@mainsoft.com>   
+//
+// Copyright (C) 2005 Mainsoft Corporation, (http://www.mainsoft.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//\r
+\r
 using System;\r
 \r
 using java.awt;\r
@@ -32,6 +60,9 @@ namespace System.Drawing.Drawing2D
                private int _coordsCount;\r
                private int _windingRule;\r
 \r
+               private PathData _pathData;\r
+               private GeneralPath _generalPath;\r
+\r
                const int INIT_SIZE = 20;\r
                const int EXPAND_MAX = 500;\r
 \r
@@ -61,8 +92,7 @@ namespace System.Drawing.Drawing2D
                private ExtendedGeneralPath(int rule, int initialTypes, int initialCoords) \r
                {\r
                        setWindingRule(rule);\r
-                       _types = new sbyte [initialTypes];\r
-                       _coords = new float [initialCoords * 2];\r
+                       Reset (initialTypes, initialCoords);\r
                }\r
 \r
                #endregion // Constructors\r
@@ -72,10 +102,10 @@ namespace System.Drawing.Drawing2D
                private GeneralPath GeneralPath\r
                {\r
                        get {\r
-                               PathIterator iter = getPathIterator (null);\r
-                               GeneralPath path = new GeneralPath ();\r
-                               path.append (iter, false);\r
-                               return path;\r
+                               if (_generalPath == null) {                             \r
+                                       _generalPath = GetGeneralPath ();\r
+                               }\r
+                               return _generalPath;\r
                        }\r
                }\r
 \r
@@ -108,12 +138,95 @@ namespace System.Drawing.Drawing2D
                        }\r
                }\r
 \r
+               public int PointCount\r
+               {\r
+                       get {\r
+                               return CoordsCount / 2;\r
+                       }\r
+               }\r
 \r
+               public PathData PathData \r
+               {\r
+                       get \r
+                       {\r
+                               if (_pathData == null)\r
+                                       _pathData = GetPathData ();\r
+                               \r
+                               return _pathData;\r
+                       }\r
+               }\r
 \r
                #endregion // Properties\r
 \r
                #region Methods\r
 \r
+               #region CachedData\r
+\r
+               private void ClearCache ()\r
+               {\r
+                       _pathData = null;\r
+                       _generalPath = null;\r
+               }\r
+\r
+               private GeneralPath GetGeneralPath ()\r
+               {\r
+                       PathIterator iter = getPathIterator (null);\r
+                       GeneralPath path = new GeneralPath ();\r
+                       path.append (iter, false);\r
+                       return path;\r
+               }\r
+\r
+               private PathData GetPathData ()\r
+               {\r
+                       PathData pathData = new PathData();\r
+                       pathData.Types = new byte [PointCount];\r
+                       pathData.Points = new PointF [PointCount];\r
+                       int tpos = 0;\r
+                       int ppos = 0;\r
+                       int cpos = 0;\r
+                       byte marker;\r
+                       bool start;\r
+                       for (int i = 0; i < TypesCount; i++) {\r
+                               sbyte segmentType = (sbyte)(Types [i] & SEG_MASK);\r
+\r
+                               // set the masks and the markers\r
+                               marker = ((Types [i] & SEG_MARKER) != 0) ? (byte)PathPointType.PathMarker : (byte)0;\r
+                               start = ((Types [i] & SEG_START) != 0);\r
+                               \r
+                               switch (segmentType) {\r
+                                       case SEG_CLOSE:\r
+                                               pathData.InternalTypes [tpos - 1] = (byte) (pathData.InternalTypes [tpos - 1] | (byte) PathPointType.CloseSubpath | marker);\r
+                                               break;\r
+                                       case SEG_MOVETO:\r
+                                               pathData.InternalTypes [tpos++] = (byte)((byte) PathPointType.Start | marker);\r
+                                               pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+                                               break;\r
+                                       case SEG_LINETO:\r
+                                               pathData.InternalTypes [tpos++] = (byte) ((byte) PathPointType.Line | marker);\r
+                                               pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+                                               break;\r
+                                       case SEG_QUADTO:\r
+                                               // FIXME : use 4 cp , two of which \r
+                                               pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier;\r
+                                               pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+                                               pathData.InternalTypes [tpos++] = (byte) ((byte)PathPointType.Bezier | marker);\r
+                                               pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+                                               break;\r
+                                       case SEG_CUBICTO:\r
+                                               pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier3;\r
+                                               pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+                                               pathData.InternalTypes [tpos++] = (byte) PathPointType.Bezier3;\r
+                                               pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+                                               pathData.InternalTypes [tpos++] = (byte) ((byte)PathPointType.Bezier3 | marker);\r
+                                               pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);\r
+                                               break;\r
+                               }\r
+                       }\r
+                       return pathData;\r
+               }\r
+\r
+               #endregion // CachedData\r
+\r
                public void append(Shape s)\r
                {\r
                        append (s, !LastFigureClosed);\r
@@ -123,6 +236,7 @@ namespace System.Drawing.Drawing2D
 \r
                public void append(PathIterator pi, bool connect) \r
                {\r
+                       ClearCache ();\r
                        float [] coords = new float [6];\r
                        while (!pi.isDone ()) {\r
                                switch (pi.currentSegment (coords)) {\r
@@ -162,7 +276,7 @@ namespace System.Drawing.Drawing2D
 \r
                public object Clone() \r
                {\r
-                       ExtendedGeneralPath copy = new ExtendedGeneralPath ();\r
+                       ExtendedGeneralPath copy = (ExtendedGeneralPath)MemberwiseClone ();\r
                        copy._types = (sbyte []) _types.Clone ();\r
                        copy._coords = (float []) _coords.Clone ();\r
                        return copy;\r
@@ -170,6 +284,7 @@ namespace System.Drawing.Drawing2D
 \r
                public void closePath() \r
                {\r
+                       ClearCache ();\r
                        if (_typesCount == 0 || _types[_typesCount - 1] != SEG_CLOSE) {\r
                                needRoom (1, 0, true);\r
                                _types [_typesCount++] = SEG_CLOSE;\r
@@ -207,6 +322,7 @@ namespace System.Drawing.Drawing2D
 \r
                public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) \r
                {\r
+                       ClearCache ();\r
                        needRoom (1, 6, true);\r
                        _types [_typesCount++] = SEG_CUBICTO;\r
                        _coords [_coordsCount++] = x1;\r
@@ -299,6 +415,7 @@ namespace System.Drawing.Drawing2D
 \r
                public void lineTo(float x, float y) \r
                {\r
+                       ClearCache ();\r
                        needRoom (1, 2, true);\r
                        _types [_typesCount++] = SEG_LINETO;\r
                        _coords [_coordsCount++] = x;\r
@@ -307,6 +424,7 @@ namespace System.Drawing.Drawing2D
 \r
                public void moveTo(float x, float y) \r
                {\r
+                       ClearCache ();\r
                        if (_typesCount > 0 && _types [_typesCount - 1] == SEG_MOVETO) {\r
                                _coords [_coordsCount - 2] = x;\r
                                _coords [_coordsCount - 1] = y;\r
@@ -321,6 +439,7 @@ namespace System.Drawing.Drawing2D
 \r
                public void quadTo(float x1, float y1, float x2, float y2) \r
                {\r
+                       ClearCache ();\r
                        needRoom (1, 4, true);\r
                        _types [_typesCount++] = SEG_QUADTO;\r
                        _coords [_coordsCount++] = x1;\r
@@ -331,6 +450,7 @@ namespace System.Drawing.Drawing2D
 \r
                public void reset() \r
                {\r
+                       ClearCache ();\r
                        _typesCount = 0;\r
                        _coordsCount = 0;\r
                }\r
@@ -345,6 +465,7 @@ namespace System.Drawing.Drawing2D
 \r
                public void transform(AffineTransform at) \r
                {\r
+                       ClearCache ();\r
                        at.transform (_coords, 0, _coords, 0, _coordsCount/2);\r
                }\r
 \r
@@ -385,17 +506,159 @@ namespace System.Drawing.Drawing2D
 \r
                public void SetMarkers()\r
                {\r
-                       Types [ TypesCount - 1] |= SEG_MARKER;\r
+                       ClearCache ();\r
+                       if (TypesCount > 0)\r
+                               Types [ TypesCount - 1] |= SEG_MARKER;\r
                }\r
 \r
                public void ClearMarkers()\r
                {\r
+                       ClearCache ();\r
                        for (int i = 0; i < TypesCount; i++)\r
                                Types [i] &= ~SEG_MARKER;\r
                }\r
 \r
+               public void StartFigure ()\r
+               {\r
+                       ClearCache ();\r
+                       if (TypesCount > 0)\r
+                               Types [TypesCount - 1] |= ExtendedGeneralPath.SEG_START;\r
+               }\r
+\r
+               private void Reset (int initialTypes, int initialCoords)\r
+               {\r
+                       ClearCache ();\r
+                       _types = new sbyte [initialTypes];\r
+                       _coords = new float [initialCoords * 2];\r
+                       _typesCount = 0;\r
+                       _coordsCount = 0;\r
+               }\r
+\r
+               internal void Clear ()\r
+               {\r
+                       Reset (INIT_SIZE, INIT_SIZE);\r
+               }\r
+\r
+               internal void Reverse ()\r
+               {\r
+                       ClearCache ();\r
+                       // revert coordinates\r
+                       for (int i=0, max = CoordsCount / 2; i < max;) {\r
+                               int ix = i++;\r
+                               int iy = i++;\r
+                               int rix = CoordsCount - i;\r
+                               int riy = rix + 1;\r
+                               float tmpx = Coords [ix];\r
+                               float tmpy = Coords [iy];\r
+                               Coords [ix] = Coords [rix];\r
+                               Coords [iy] = Coords [riy];\r
+                               Coords [rix] = tmpx;\r
+                               Coords [riy] = tmpy;\r
+                       }\r
+\r
+                       // revert types\r
+                       sbyte [] newTypes = new sbyte [TypesCount];\r
+                       int oldIdx = 0;\r
+                       int newIdx = TypesCount - 1;\r
+                       int copyStart;\r
+                       int copyEnd;\r
+                       sbyte mask1 = 0;\r
+                       sbyte mask2 = 0;\r
+                       sbyte closeMask = 0;\r
+                       bool closedFigure = false;\r
+                       \r
+                       while (oldIdx < TypesCount) {\r
+                               // start copying after moveto\r
+                               copyStart = ++oldIdx;\r
+                               // continue to the next figure start\r
+                               while ((Types [oldIdx] != SEG_MOVETO) && (oldIdx < TypesCount))\r
+                                       oldIdx++;\r
+\r
+                               copyEnd = oldIdx - 1;\r
+                               // check whenever current figure is closed\r
+                               if ((Types [oldIdx - 1] & SEG_CLOSE) != 0) {\r
+                                       closedFigure = true;\r
+                                       // close figure\r
+                                       newTypes [newIdx--] = (sbyte)(SEG_CLOSE | mask1);\r
+                                       mask1 = 0;\r
+                                       mask2 = 0;\r
+                                       // end copy one cell earlier\r
+                                       copyEnd--;\r
+                                       closeMask = (sbyte)(Types [oldIdx - 1] & (sbyte)SEG_MARKER);\r
+                               }\r
+                               else {\r
+                                       mask2 = mask1;\r
+                                       mask1 = 0;\r
+                               }\r
+\r
+                               // copy reverted "inner" types\r
+                               for(int i = copyStart; i <= copyEnd; i++) {\r
+                                       newTypes [newIdx--] = (sbyte)((Types [i] & SEG_MASK) | mask2);\r
+                                       mask2 = mask1;\r
+                                       mask1 = (sbyte)(Types [i] & (sbyte)SEG_MARKER);\r
+                               }\r
+\r
+                               // copy moveto\r
+                               newTypes [newIdx--] = SEG_MOVETO;\r
+\r
+                               // pass close mask to the nex figure\r
+                               if (closedFigure) {\r
+                                       mask1 = closeMask;\r
+                                       closedFigure = false;\r
+                               }\r
+                       }\r
+\r
+                       _types = newTypes;\r
+               }\r
+\r
+               public PointF GetLastPoint ()\r
+               {\r
+                       if (CoordsCount == 0)\r
+                               throw new System.ArgumentException ("Invalid parameter used.");\r
+\r
+                       return new PointF (Coords [CoordsCount - 2], Coords [CoordsCount - 1]);\r
+               }\r
+\r
                #endregion //Methods\r
 \r
+               #region Private helpers\r
+\r
+#if DEBUG\r
+               private void Print()\r
+               {\r
+                       Console.WriteLine ("\n\n");\r
+                       float [] fpoints = _coords;\r
+                       int cpos = 0;\r
+                       for (int i=0; i < _typesCount; i++) {\r
+                               sbyte type = _types [i];\r
+                               string marker = String.Empty;\r
+                               if ((type & SEG_MARKER) != 0)\r
+                                       marker = " | MARKER";\r
+\r
+                               switch (type & SEG_MASK) {\r
+                                       case SEG_CLOSE:\r
+                                               Console.WriteLine ("CLOSE {0}",marker);\r
+                                               break;\r
+                                       case SEG_MOVETO:\r
+                                               Console.WriteLine("{0}{3} ({1},{2})","MOVETO", fpoints[cpos++], fpoints[cpos++], marker);\r
+                                               break;\r
+                                       case SEG_LINETO:\r
+                                               Console.WriteLine("{0}{3} ({1},{2})","LINETO", fpoints[cpos++], fpoints[cpos++], marker);\r
+                                               break;\r
+                                       case SEG_QUADTO:\r
+                                               Console.WriteLine("{0}{3} ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++], marker);\r
+                                               Console.WriteLine("       ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++]);\r
+                                               break;\r
+                                       case SEG_CUBICTO:\r
+                                               Console.WriteLine("{0}{3} ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++], marker);\r
+                                               Console.WriteLine("        ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);\r
+                                               Console.WriteLine("        ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);\r
+                                               break;\r
+                               }\r
+                       }\r
+               }\r
+#endif\r
+               #endregion // Private helpers\r
                \r
        }\r
 }\r