[System.Net] Add support for .pac proxy config scripts on mac
[mono.git] / mcs / class / System.Drawing / System.Drawing.Drawing2D / GraphicsPath.jvm.cs
1 //
2 // System.Drawing.Drawing2D.GraphicsPath.cs
3 //
4 // Author:
5 // Konstantin Triger <kostat@mainsoft.com>
6 // Bors Kirzner <boris@mainsoft.com>    
7 //
8 // Copyright (C) 2005 Mainsoft Corporation, (http://www.mainsoft.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.Drawing;
31 using System.Drawing.Text;
32 using System.Collections;
33 using java.awt.geom;
34 using java.awt;
35
36 namespace System.Drawing.Drawing2D
37 {
38         public sealed class GraphicsPath : BasicShape, ICloneable
39         {
40                 internal enum JPI {
41                         SEG_MOVETO = ExtendedGeneralPath.SEG_MOVETO,
42                         SEG_LINETO = ExtendedGeneralPath.SEG_LINETO,
43                         SEG_QUADTO = ExtendedGeneralPath.SEG_QUADTO,
44                         SEG_CUBICTO = ExtendedGeneralPath.SEG_CUBICTO,
45                         SEG_CLOSE = ExtendedGeneralPath.SEG_CLOSE
46                 }
47
48                 #region Internal
49
50                 internal ExtendedGeneralPath NativeObject
51                 {
52                         get 
53                         {
54                                 return (ExtendedGeneralPath)Shape;
55                         }
56                 }
57
58                 GraphicsPath (ExtendedGeneralPath ptr) : base(ptr)
59                 {
60                 }
61                 #endregion
62
63                 #region  C-tors.
64                 public GraphicsPath ():
65                         this(FillMode.Alternate)
66                 {
67                 }
68                 
69                 public GraphicsPath (FillMode fillMode) : this(new ExtendedGeneralPath ())
70                 {
71                         FillMode = fillMode;
72                 }
73                 
74                 public GraphicsPath (Point[] pts, byte[] types) : this(pts, types, FillMode.Alternate)
75                 {
76                 }
77                 
78                 public GraphicsPath (PointF [] pts, byte [] types) : this(pts, types, FillMode.Alternate)
79                 {
80                 }
81                 
82                 public GraphicsPath (Point [] pts, byte [] types, FillMode fillMode) : this(new ExtendedGeneralPath ())
83                 {
84                         FillMode = fillMode;
85                         SetPath (pts, types);
86                 }
87
88                 public GraphicsPath (PointF [] pts, byte [] types, FillMode fillMode) : this(new ExtendedGeneralPath ())
89                 {
90                         FillMode = fillMode;
91                         SetPath (pts, types);
92                 }
93
94                 #endregion
95
96                 #region Clone
97                 public object Clone ()
98                 {
99                         return new GraphicsPath ((ExtendedGeneralPath) NativeObject.Clone ());
100                 }
101                 #endregion
102
103                 #region Properties
104                 public FillMode FillMode 
105                 {
106                         get 
107                         {   if(NativeObject.getWindingRule() == GeneralPath.WIND_EVEN_ODD)
108                                         return FillMode.Alternate;
109                                 else
110                                         return FillMode.Winding;
111                         }
112
113                         set 
114                         {
115                                 if (value == FillMode.Alternate)
116                                         NativeObject.setWindingRule (GeneralPath.WIND_EVEN_ODD);
117                                 else
118                                         NativeObject.setWindingRule (GeneralPath.WIND_NON_ZERO);
119                         }
120                 }
121
122                 public PathData PathData 
123                 {
124                         get { return NativeObject.PathData; }
125                 }
126
127                 public PointF [] PathPoints 
128                 {
129                         get 
130                         {
131                                 return PathData.Points;
132                         }
133                 }
134
135                 public byte [] PathTypes 
136                 {
137                         get 
138                         {
139                                 return PathData.Types;                  
140                         }
141                 }
142                 #endregion
143
144                 #region PointCount
145                 public int PointCount 
146                 {
147                         get 
148                         {
149                                 return NativeObject.PointCount;
150                         }
151                 }
152                 #endregion
153                         
154                 #region AddArc
155                 public void AddArc (Rectangle rect, float startAngle, float sweepAngle)
156                 {
157                         AddArc(rect.X,rect.Y,rect.Width,rect.Height,startAngle,sweepAngle);                     
158                 }
159
160                 public void AddArc (RectangleF rect, float startAngle, float sweepAngle)
161                 {
162                         AddArc(rect.X,rect.Y,rect.Width,rect.Height,startAngle,sweepAngle);
163                 }
164
165                 public void AddArc (int x, int y, int width, int height, float startAngle, float sweepAngle)
166                 {
167                         AddArc((float)x,(float)y,(float)width,(float)height,startAngle,sweepAngle);
168                 }
169
170                 public void AddArc (float x, float y, float width, float height, float startAngle, float sweepAngle)
171                 {
172                         Shape shape = null;
173
174                         if (sweepAngle >= 360)
175                                 shape = new Ellipse2D.Float(x, y, width, height);
176                         else {
177
178                                 double d1Tod2 = width/height;
179                                 double sqrd1Tod2 = d1Tod2*d1Tod2;
180                                 double start = ConvertArcAngle(sqrd1Tod2, startAngle);
181                                 double extent = ConvertArcAngle(sqrd1Tod2, startAngle+sweepAngle) - start;
182
183                                 shape = new Arc2D.Double(x,y,width,height,-start,-extent,Arc2D.OPEN);
184                         }
185
186                         NativeObject.append(shape);
187                 }
188
189                 /// <summary>
190                 /// .Net computes an angle by intersection of ellipse with a ray
191                 /// java does the following: x1 = d1*cos(a), y1 = d2*sin(a)
192                 /// where: d1 = width/2, d2 = height/2
193                 /// we need to find angle x, which satisfies:
194                 /// x1 = m*cos(a) = d1*cos(x)
195                 /// y1 = m*sin(a) = d2*sin(x)
196                 /// (x1*x1)/(d1*d1) + (x2*x2)/(d2*d2) = 1
197                 /// </summary>
198                 /// <param name="sqrd1Tod2">(d1/d2)*(d1/d2)</param>
199                 /// <param name="angle">angle in degrees</param>
200                 /// <returns>converted angle in degrees</returns>
201                 static double ConvertArcAngle(double sqrd1Tod2, double angle) {
202                         double angleRad = java.lang.Math.toRadians(angle);
203                         double tan = Math.Tan(angleRad);
204                         double cosx = 1/Math.Sqrt( sqrd1Tod2 * (tan*tan) + 1);
205                         double xRad = Math.Acos(cosx);
206                         double x = java.lang.Math.toDegrees(xRad);
207                         int q = (Math.Abs((int)angle))/90;
208
209                         switch (q&3) {
210                                 case 1:
211                                         x = 180-x;
212                                         break;
213                                 case 2:
214                                         x = 180+x;
215                                         break;
216                                 case 3:
217                                         x = 360-x;
218                                         break;
219                         }
220
221                         if (angle < 0)
222                                 x = -x;
223
224                         x += (((int)angle)/360)*360;
225
226                         return x;
227                 }
228
229                 #endregion
230                 
231                 #region AddBezier(s)
232                 public void AddBezier (Point pt1, Point pt2, Point pt3, Point pt4)
233                 {
234                         AddBezier(pt1.X,pt1.Y,pt2.X,pt2.Y,pt3.X,pt3.Y,pt4.X,pt4.Y);
235                 }
236
237                 public void AddBezier (PointF pt1, PointF pt2, PointF pt3, PointF pt4)
238                 {                       
239                         AddBezier(pt1.X,pt1.Y,pt2.X,pt2.Y,pt3.X,pt3.Y,pt4.X,pt4.Y);
240                 }
241
242                 public void AddBezier (int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
243                 {
244                         AddBezier((float)x1,(float)y1,(float)x2,(float)y2,(float)x3,(float)y3,(float)x4,(float)y4);
245                 }
246
247                 public void AddBezier (float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
248                 {
249                         CubicCurve2D cc = new CubicCurve2D.Float(x1,y1,x2,y2,x3,y3,x4,y4);
250                         NativeObject.append(cc);
251                 }
252
253                 public void AddBeziers (Point [] pts)
254                 {
255                         if (pts == null)
256                                 throw new ArgumentNullException("points");
257
258                         AddBezier(pts [0].X,pts [0].Y,
259                                         pts [1].X,pts [1].Y,
260                                         pts [2].X,pts [2].Y,
261                                         pts [3].X,pts [3].Y);
262
263                         for (int i = 4; i < pts.Length; i += 3) {
264                                 NativeObject.curveTo(   
265                                         pts [i].X,pts [i].Y,
266                                         pts [i+1].X,pts [i+1].Y,
267                                         pts [i+2].X,pts [i+2].Y);
268                         }
269                 }
270
271                 public void AddBeziers (PointF [] pts)
272                 {
273                         if (pts == null)
274                                 throw new ArgumentNullException("points");
275
276                         AddBezier(pts [0].X,pts [0].Y,
277                                 pts [1].X,pts [1].Y,
278                                 pts [2].X,pts [2].Y,
279                                 pts [3].X,pts [3].Y);
280
281                         for (int i = 4; i < pts.Length; i += 3) {
282                                 NativeObject.curveTo(   
283                                         pts [i].X,pts [i].Y,
284                                         pts [i+1].X,pts [i+1].Y,
285                                         pts [i+2].X,pts [i+2].Y);
286                         }
287                 }
288                 #endregion
289
290                 #region AddEllipse
291                 public void AddEllipse (float x, float y, float width, float height)
292                 {
293                         Ellipse2D e = new Ellipse2D.Float(x,y,width,height);
294                         NativeObject.append(e,false);
295                 }
296
297                 public void AddEllipse (RectangleF r)
298                 {
299                         AddEllipse(r.X,r.Y,r.Width,r.Height);
300                 }
301                 
302                 public void AddEllipse (Rectangle r)
303                 {
304                         AddEllipse(r.X,r.Y,r.Width,r.Height);
305                 }
306                 
307                 public void AddEllipse (int x, int y, int width, int height)
308                 {
309                         AddEllipse((float)x, (float)y, (float)width, (float)height);
310                 }
311                 #endregion
312                 
313                 #region AddLine
314                 public void AddLine (float x1, float y1, float x2, float y2)
315                 {
316                         Line2D l = new Line2D.Float(x1,y1,x2,y2);
317                         NativeObject.append(l);
318                 }
319
320                 public void AddLine (Point a, Point b)
321                 {
322                         AddLine(a.X,a.Y,b.X,b.Y);
323                 }
324
325                 public void AddLine (PointF a, PointF b)
326                 {
327                         AddLine(a.X,a.Y,b.X,b.Y);
328                 }
329
330                 public void AddLine (int x1, int y1, int x2, int y2)
331                 {
332                         AddLine((float)x1,(float)y1,(float)x2,(float)y2);
333                 }
334
335                 public void AddLines (Point [] points)
336                 {                       
337                         if (points == null)
338                                 throw new ArgumentNullException("points");
339
340                         if (points.Length == 0)
341                                 return;
342
343                         if (NativeObject.LastFigureClosed)
344                                 NativeObject.moveTo(points[0].X, points[0].Y);
345                         else
346                                 NativeObject.lineTo(points[0].X, points[0].Y);
347
348                         for (int i = 1; i < points.Length; i ++)
349                                 NativeObject.lineTo(points[i].X, points[i].Y);
350                 }
351
352                 public void AddLines (PointF [] points)
353                 {
354                         if (points == null)
355                                 throw new ArgumentNullException("points");
356
357                         if (points.Length == 0)
358                                 return;
359
360                         if (NativeObject.LastFigureClosed)
361                                 NativeObject.moveTo(points[0].X, points[0].Y);
362                         else
363                                 NativeObject.lineTo(points[0].X, points[0].Y);
364
365                         for (int i = 1; i < points.Length; i ++)
366                                 NativeObject.lineTo(points[i].X, points[i].Y);
367                 }
368                 #endregion
369         
370                 #region AddPie
371                 public void AddPie (float x, float y, float width, float height, float startAngle, float sweepAngle)
372                 {
373                         Shape shape = null;
374
375                         if (sweepAngle >= 360)
376                                 shape = new Ellipse2D.Float(x, y, width, height);
377                         else {
378
379                                 double d1Tod2 = width/height;
380                                 double sqrd1Tod2 = d1Tod2*d1Tod2;
381                                 double start = ConvertArcAngle(sqrd1Tod2, startAngle);
382                                 double extent = ConvertArcAngle(sqrd1Tod2, startAngle+sweepAngle) - start;
383
384                                 shape = new Arc2D.Double(x,y,width,height,-start,-extent,Arc2D.PIE);
385                         }
386
387                         NativeObject.append(shape,false);
388                 }
389
390                 public void AddPie (Rectangle rect, float startAngle, float sweepAngle)
391                 {
392                         AddPie((float)rect.X, (float)rect.Y,(float)rect.Width,(float)rect.Height,startAngle,sweepAngle);                
393                 }
394
395                 public void AddPie (int x, int y, int width, int height, float startAngle, float sweepAngle)
396                 {
397                         AddPie((float)x,(float)y,(float)width,(float)height,startAngle,sweepAngle);             
398                 }
399                 #endregion
400
401                 #region AddPolygon
402                 public void AddPolygon (Point [] points)
403                 {
404                         if (points == null)
405                                 throw new ArgumentNullException("points");
406
407                         if (points.Length < 3)
408                                 throw new ArgumentException("Invalid parameter used.");
409
410                         NativeObject.moveTo((float)points[0].X,(float)points[0].Y);
411                         for (int i = 1; i< points.Length; i++)
412                         {
413                                 NativeObject.lineTo((float)points[i].X,(float)points[i].Y);
414                         }
415                         NativeObject.closePath();
416                 }
417
418                 public void AddPolygon (PointF [] points)
419                 {
420                         if (points == null)
421                                 throw new ArgumentNullException("points");
422
423                         if (points.Length < 3)
424                                 throw new ArgumentException("Invalid parameter used.");
425
426                         NativeObject.moveTo(points[0].X,points[0].Y);
427                         for (int i = 1; i < points.Length; i++)
428                         {
429                                 NativeObject.lineTo(points[i].X,points[i].Y);
430                         }
431                         NativeObject.closePath();
432                 }
433                 #endregion
434
435                 #region AddRectangle(s)
436                 internal void AddRectangle(float x,float y, float w, float h)
437                 {
438                         NativeObject.moveTo(x, y);
439                         NativeObject.lineTo (x + w, y);
440                         NativeObject.lineTo (x + w, y + h);
441                         NativeObject.lineTo (x, y + h);
442                         NativeObject.closePath ();
443                 }
444                 public void AddRectangle (RectangleF rect)
445                 {
446                         AddRectangle(rect.X,rect.Y,rect.Width,rect.Height);
447                 }
448
449                 public void AddRectangle (Rectangle rect)
450                 {
451                         AddRectangle(rect.X,rect.Y,rect.Width,rect.Height);
452                 }
453
454                 public void AddRectangles (Rectangle [] rects)
455                 {
456                         foreach(Rectangle rect in rects)
457                                 AddRectangle(rect.X,rect.Y,rect.Width,rect.Height);
458                 }
459
460                 public void AddRectangles (RectangleF [] rects)
461                 {
462                         foreach(RectangleF rect in rects)
463                                 AddRectangle(rect.X,rect.Y,rect.Width,rect.Height);
464                 }
465                 #endregion
466
467                 #region AddPath
468                 public void AddPath (GraphicsPath addingPath, bool connect)
469                 {
470                         if (NativeObject.LastFigureClosed || addingPath.NativeObject.LastFigureClosed)
471                                 connect = false;
472
473                         NativeObject.append(addingPath.NativeObject,connect);
474                 }
475                 #endregion
476
477                 #region GetLastPoint
478                 public PointF GetLastPoint ()
479                 {
480                         return NativeObject.GetLastPoint ();
481                 }
482                 #endregion
483
484                 #region Reset
485                 public void Reset ()
486                 {
487                         NativeObject.reset();
488                 }
489                 #endregion
490
491                 #region GetBounds
492                 public RectangleF GetBounds ()
493                 {
494                         return GetBounds (null, null);
495                 }               
496
497                 public RectangleF GetBounds (Matrix matrix)
498                 {
499                         return GetBounds (matrix, null);
500                 }
501
502                 public RectangleF GetBounds (Matrix matrix, Pen pen)
503                 {
504                         // FIXME : we do not know exacly how the bounding rectangle 
505                         // is calculated so this implementation obtains different bounds
506                         // that still contains the path widened by oen and transformed by matrix
507                         // the order of operations is similar to widening, as .Net does.
508
509                         // first get original shape bounds
510                         //Shape shape = NativeObject.getBounds2D();
511                         Shape shape = NativeObject;
512
513                         // stroke bounds
514                         if (pen != null)
515                                 shape = ((Stroke)pen).createStrokedShape (shape);
516
517                         Rectangle2D rect = shape.getBounds2D ();
518
519                         // transform bounds                     
520                         if (matrix != null)
521                                 rect = matrix.NativeObject.createTransformedShape(rect).getBounds2D();
522
523                         return new RectangleF (rect);
524                 }
525                 #endregion
526         
527                 #region Transform
528                 public void Transform (Matrix matrix)
529                 {
530                         if(matrix == null)
531                                 return;
532
533                         NativeObject.transform(matrix.NativeObject);
534                 }
535                 #endregion
536
537                 #region IsVisible
538                 public bool IsVisible (Point point)
539                 {
540                         return IsVisible (point.X, point.Y, null);
541                 }               
542                 
543                 public bool IsVisible (PointF point)
544                 {
545                         return IsVisible (point.X, point.Y, null);
546                 }               
547                 
548                 public bool IsVisible (int x, int y)
549                 {
550                         return IsVisible (x, y, null);
551                 }
552
553                 public bool IsVisible (float x, float y)
554                 {
555                         return IsVisible (x, y, null);
556                 }                               
557                 
558                 public bool IsVisible (Point pt, Graphics graphics)
559                 {
560                         return IsVisible (pt.X, pt.Y, graphics);
561                 }               
562                 
563                 public bool IsVisible (PointF pt, Graphics graphics)
564                 {
565                         return IsVisible (pt.X, pt.Y, graphics);
566                 }               
567                                 
568                 public bool IsVisible (int x, int y, Graphics graphics)
569                 {
570                         return IsVisible((float)x,(float)y,null);
571                 }               
572                 
573                 public bool IsVisible (float x, float y, Graphics graphics)
574                 {
575                         // LAMESPEC : .Net is currently ignorig Graphics object
576                         //if (graphics != null && !graphics.IsVisible(x,y))
577                         //      return false;
578
579                         return NativeObject.contains(x,y);
580                 }
581                 #endregion
582         
583                 #region Reverse
584                 public void Reverse ()
585                 {
586                         NativeObject.Reverse ();
587                 }
588                 #endregion
589              
590                 #region AddClosedCurve
591                 public void AddClosedCurve (Point [] points)
592                 {
593                         AddClosedCurve(points, 0.5f);
594                 }
595
596                 public void AddClosedCurve (PointF [] points)
597                 {
598                         AddClosedCurve(points, 0.5f);
599                 }
600
601                 public void AddClosedCurve (Point [] points, float tension)
602                 {
603                         if (points == null)
604                                 throw new ArgumentNullException("points");
605
606                         if (points.Length < 3)
607                                 throw new ArgumentException("Invalid parameter used.");
608
609                         int length = (points.Length + 3)*2;
610
611                         float[] pts = new float[length];
612                         pts[--length] = points[1].Y;
613                         pts[--length] = points[1].X;
614                         pts[--length] = points[0].Y;
615                         pts[--length] = points[0].X;
616
617                         for (int i = points.Length-1; i >= 0; i--) {
618                                 pts[--length] = points[i].Y;
619                                 pts[--length] = points[i].X;
620                         }
621
622                         pts[--length] = points[points.Length-1].Y;
623                         pts[--length] = points[points.Length-1].X;
624
625                         AddCurve(pts, !NativeObject.LastFigureClosed, tension);
626                         CloseFigure ();
627                 }
628
629                 public void AddClosedCurve (PointF [] points, float tension)
630                 {
631                         if (points == null)
632                                 throw new ArgumentNullException("points");
633
634                         if (points.Length < 3)
635                                 throw new ArgumentException("Invalid parameter used.");
636
637                         int length = (points.Length + 3)*2;
638
639                         float[] pts = new float[length];
640                         pts[--length] = points[1].Y;
641                         pts[--length] = points[1].X;
642                         pts[--length] = points[0].Y;
643                         pts[--length] = points[0].X;
644
645                         for (int i = points.Length-1; i >= 0; i--) {
646                                 pts[--length] = points[i].Y;
647                                 pts[--length] = points[i].X;
648                         }
649
650                         pts[--length] = points[points.Length-1].Y;
651                         pts[--length] = points[points.Length-1].X;
652
653                         AddCurve(pts, !NativeObject.LastFigureClosed, tension);
654                         CloseFigure ();
655                 }
656                 #endregion
657
658                 #region AddCurve
659                 //we have now two approaches for drawing cardinal curves
660                 //the first one is to convert cardinals into approximate beziers
661                 //the second one - to draw curve ourself with all interpolation staff
662                 //here. I preffer the first one because we could utilize java antialiasing and
663                 //flattening features, otherwise curves will be more strict but less cool
664                 public void AddCurve (Point [] points)
665                 {
666                         AddCurve(points,0.5F);
667                 }
668                 
669                 public void AddCurve (PointF [] points)
670                 {
671                         AddCurve(points,0.5f);
672                 }
673                 
674                 public void AddCurve (Point [] points, float tension)
675                 {
676                         AddCurve(points, 0, points.Length-1, tension);
677                 }
678                 
679                 public void AddCurve (PointF [] points, float tension)
680                 {
681                         AddCurve(points, 0, points.Length-1, tension);
682                 }
683
684                 public void AddCurve (Point [] points, int offset, int numberOfSegments, float tension)
685                 {
686                         int nPoints = numberOfSegments + 1;
687                         int length = nPoints*2 + 4;
688                         float[] pts = new float[length];
689
690                         int lastP = offset + nPoints;
691                         if (lastP == points.Length) {
692                                 lastP--;
693                                 pts[--length] = points[lastP].Y;
694                                 pts[--length] = points[lastP].X;
695                         }
696
697                         for (; length > 0 && lastP >= 0; lastP--) {
698                                 pts[--length] = points[lastP].Y;
699                                 pts[--length] = points[lastP].X;
700                         }
701
702                         if (length > 0) {
703                                 pts[1] = points[0].Y;
704                                 pts[0] = points[0].X;
705                         }
706
707                         AddCurve(pts, !NativeObject.LastFigureClosed, tension);
708                 }
709                 
710                 public void AddCurve (PointF [] points, int offset, int numberOfSegments, float tension)
711                 {
712                         int nPoints = numberOfSegments + 1;
713                         int length = nPoints*2 + 4;
714                         float[] pts = new float[length];
715
716                         int lastP = offset + nPoints;
717                         if (lastP == points.Length) {
718                                 lastP--;
719                                 pts[--length] = points[lastP].Y;
720                                 pts[--length] = points[lastP].X;
721                         }
722
723                         for (; length > 0 && lastP >= 0; lastP--) {
724                                 pts[--length] = points[lastP].Y;
725                                 pts[--length] = points[lastP].X;
726                         }
727
728                         if (length > 0) {
729                                 pts[1] = points[0].Y;
730                                 pts[0] = points[0].X;
731                         }
732
733                         AddCurve(pts, !NativeObject.LastFigureClosed, tension);
734                 }
735
736                 /// <summary>
737                 /// Based on http://pubpages.unh.edu/~cs770/a5/cardinal.html
738                 /// </summary>
739                 /// <param name="pts">point array (x1,y1,x2,y2 ...).
740                 /// The first and last points considered only for calculations, but are not added.</param>
741                 void AddCurve(float[] pts, bool connect, float tension) {
742                         tension /= 3f; //looks like a good pick
743
744                         if (connect)
745                                 NativeObject.lineTo(pts[2],pts[3]);
746                         else
747                                 NativeObject.moveTo(pts[2],pts[3]);
748
749                         float dx = pts[4] - pts[0];
750                         float dy = pts[5] - pts[1];
751
752                         float sx = pts[2] + tension*dx;
753                         float sy = pts[3] + tension*dy;
754
755                         for (int offset = 2, total = pts.Length-4; offset < total; offset += 2) {
756                                 int cur_offset = offset;
757                                 int pX = cur_offset++;
758                                 int pY = cur_offset++;
759                                 int X = cur_offset++;
760                                 int Y = cur_offset++;
761                                 int nX = cur_offset++;
762                                 int nY = cur_offset++;
763
764                                 dx = pts[nX] - pts[pX];
765                                 dy = pts[nY] - pts[pY];
766
767                                 float rx = pts[X] - tension*dx;
768                                 float ry = pts[Y] - tension*dy;
769                                 
770                                 NativeObject.curveTo(sx, sy, rx, ry, pts[X], pts[Y]);
771
772                                 sx = pts[X] + tension*dx;
773                                 sy = pts[Y] + tension*dy;
774                         }
775                 }
776                 #endregion
777
778                 #region AddString
779                 public void AddString (string s, FontFamily family, int style,  float emSize,  Point origin,   StringFormat format)
780                 {
781                         AddString(s, new Font(family, emSize, (FontStyle)style, GraphicsUnit.World), origin.X, origin.Y, float.PositiveInfinity, float.PositiveInfinity,
782                                 format);
783                 }       
784                 
785                 public void AddString (string s,  FontFamily family,  int style,  float emSize,  PointF origin,   StringFormat format)
786                 {
787                         AddString(s, new Font(family, emSize, (FontStyle)style, GraphicsUnit.World), origin.X, origin.Y, float.PositiveInfinity, float.PositiveInfinity,
788                                 format);
789                 }       
790                 
791                 public void AddString (string s, FontFamily family, int style, float emSize,  Rectangle layoutRect, StringFormat format)
792                 {
793                         AddString(s, new Font(family, emSize, (FontStyle)style, GraphicsUnit.World),
794                                 layoutRect.X, layoutRect.Y, layoutRect.Width, layoutRect.Height,
795                                 format);
796                 }       
797                 
798                 public void AddString (string s, FontFamily family, int style, float emSize,  RectangleF layoutRect,   StringFormat format)
799                 {
800                         AddString(s, new Font(family, emSize, (FontStyle)style, GraphicsUnit.World),
801                                 layoutRect.X, layoutRect.Y, layoutRect.Width, layoutRect.Height,
802                                 format);
803                 }
804
805                 void AddString (string s, Font font,
806                         float x, float y, float width, float height, 
807                         StringFormat format) {
808
809                         TextLineIterator iter = new TextLineIterator(s, font,
810                                 new java.awt.font.FontRenderContext(null, false, false),
811                                 format, width, height);
812
813                         int coordsCount = NativeObject.CoordsCount;
814
815                         for (LineLayout layout = iter.NextLine(); layout != null; layout = iter.NextLine()) {
816                                 NativeObject.append(layout.GetOutline(x, y), false);
817                         }
818
819                         AffineTransform lineAlignT = iter.CalcLineAlignmentTransform();
820                         if (lineAlignT != null)
821                                 NativeObject.transform(lineAlignT, coordsCount, NativeObject.CoordsCount - coordsCount);
822                 }
823                 #endregion
824                 
825                 #region ClearMarkers
826                 public void ClearMarkers()               
827                 {
828                         NativeObject.ClearMarkers ();
829                 }
830                 #endregion
831         
832                 #region Close
833                 public void CloseAllFigures()
834                 {
835                         ExtendedGeneralPath p = new ExtendedGeneralPath();
836                         PathIterator pi = NativeObject.getPathIterator(null);
837                         JPI lastSeg = JPI.SEG_CLOSE;
838                         float [] points = new float[6];
839  
840                         p.setWindingRule(pi.getWindingRule());
841                         while(!pi.isDone())
842                         {
843                                 JPI curSeg = (JPI)pi.currentSegment(points);
844                                 switch(curSeg)
845                                 {
846                                         case JPI.SEG_CLOSE:
847                                                 p.closePath();
848                                                 break;
849                                         case JPI.SEG_MOVETO:
850                                                 if(lastSeg != JPI.SEG_CLOSE)
851                                                         p.closePath();
852                                                 p.moveTo(points[0],points[1]);
853                                                 break;
854                                         case JPI.SEG_LINETO:
855                                                 p.lineTo(points[0],points[1]);
856                                                 break;
857                                         case JPI.SEG_QUADTO:
858                                                 p.quadTo(points[0],points[1],points[2],points[3]);
859                                                 break;
860                                         case JPI.SEG_CUBICTO:
861                                                 p.curveTo(points[0],points[1],points[2],points[3],points[4],points[5]);
862                                                 break;
863                                         default:
864                                                 break;
865                                 }                               
866                                 lastSeg = curSeg;
867                                 pi.next();
868                         }
869
870                         p.closePath();
871                         Shape = p;
872                 }       
873                 
874                 public void CloseFigure() {
875                         if (!NativeObject.LastFigureClosed)
876                                 NativeObject.closePath();
877                 }
878                 #endregion
879
880                 #region Flatten
881                 public void Flatten ()
882                 {
883                         // 1/4 is the FlatnessDefault as defined in GdiPlusEnums.h
884                         Flatten (null, 1.0f / 4.0f); 
885                 }       
886   
887                 public void Flatten (Matrix matrix)
888                 {
889                         Flatten (matrix, 1.0f / 4.0f);
890                 }
891                 
892                 public void Flatten (Matrix matrix, float flatness)
893                 {
894                         AffineTransform tr = null;
895                         if(matrix != null)                      
896                                 tr = matrix.NativeObject;
897
898                         //FIXME : Review (perfomance reasons).
899                         PathIterator pi = NativeObject.getPathIterator(tr,flatness);
900                         ExtendedGeneralPath newPath = new ExtendedGeneralPath();
901                         newPath.append(pi,false);
902                         Shape = newPath;
903                 }
904                 #endregion
905         
906                 #region GetOutlineVisible
907                 public bool IsOutlineVisible (Point point, Pen pen)
908                 {
909                         return IsOutlineVisible (point.X, point.Y, pen, null);
910                 }               
911                 
912                 public bool IsOutlineVisible (PointF point, Pen pen)
913                 {
914                         return IsOutlineVisible (point.X, point.Y, pen, null);
915                 } 
916                 
917                 public bool IsOutlineVisible (int x, int y, Pen pen)
918                 {
919                         return IsOutlineVisible (x, y, pen, null);
920                 }
921
922                 public bool IsOutlineVisible (float x, float y, Pen pen)
923                 {
924                         return IsOutlineVisible (x, y, pen, null);
925                 }               
926                 
927                 public bool IsOutlineVisible (Point pt, Pen pen, Graphics graphics)
928                 {
929                         return IsOutlineVisible (pt.X, pt.Y, pen, graphics);
930                 }               
931                 
932                 public bool IsOutlineVisible (PointF pt, Pen pen, Graphics graphics)
933                 {
934                         return IsOutlineVisible (pt.X, pt.Y, pen, graphics);
935                 }               
936                                 
937                 public bool IsOutlineVisible (int x, int y, Pen pen, Graphics graphics)
938                 {
939                         // LAMESPEC : .Net is currently ignorig Graphics object
940                         //if (graphics != null) {
941                         //      if (!graphics.IsVisible (x, y))
942                         //              return false;                           
943                         //}
944
945                         return ((Stroke)pen).createStrokedShape (NativeObject).contains (x, y);
946                 }               
947                                 
948                 public bool IsOutlineVisible (float x, float y, Pen pen, Graphics graphics)
949                 {
950                         return ((Stroke)pen).createStrokedShape (NativeObject).contains (x, y);
951                 }               
952                 #endregion
953         
954                 #region SetMarkers 
955                 public void SetMarkers ()
956                 {
957                         NativeObject.SetMarkers ();
958                 }
959                 #endregion
960                 
961                 #region StartFigure
962                 public void StartFigure()
963                 {
964                         NativeObject.StartFigure ();
965                 }
966                 #endregion
967                         
968                 #region Warp
969                 [MonoNotSupported ("")]
970                 public void Warp (PointF[] destPoints, RectangleF srcRect)
971                 {
972                         Warp (destPoints, srcRect, null, WarpMode.Perspective, 1.0f / 4.0f);
973                 }               
974
975                 [MonoNotSupported ("")]
976                 public void Warp (PointF[] destPoints, RectangleF srcRect, Matrix matrix)
977                 {
978                         Warp (destPoints, srcRect, matrix, WarpMode.Perspective, 1.0f / 4.0f);
979                 }               
980
981                 [MonoNotSupported ("")]
982                 public void Warp (PointF[] destPoints, RectangleF srcRect, Matrix matrix, WarpMode warpMode)
983                 {
984                         Warp (destPoints, srcRect, matrix, warpMode, 1.0f / 4.0f);
985                 }               
986
987                 [MonoNotSupported ("")]
988                 public void Warp (PointF[] destPoints, RectangleF srcRect, Matrix matrix,  WarpMode warpMode, float flatness)
989                 {
990                         throw new NotImplementedException();
991                 }
992                 #endregion
993         
994                 #region Widen
995                 public void Widen (Pen pen)
996                 {
997                         Widen (pen, null);
998                 }               
999                 
1000                 public void Widen (Pen pen, Matrix matrix)
1001                 {       
1002                         Widen (pen, matrix, 2f/3f);
1003                 }               
1004                                 
1005                 public void Widen (Pen pen, Matrix matrix, float flatness)
1006                 {
1007                         if (pen == null)
1008                                 throw new ArgumentNullException("pen");
1009
1010                         Shape = new ExtendedGeneralPath(((Stroke)pen).createStrokedShape(this));
1011                         Flatten(matrix, flatness);
1012                 } 
1013                 #endregion
1014
1015                 private void SetPath (Point [] pts, byte [] types)
1016                 {
1017                         NativeObject.Clear ();
1018                         if (((PathPointType)types [0] & PathPointType.PathTypeMask) != PathPointType.Start)
1019                                 NativeObject.moveTo (pts [0].X, pts [0].Y);
1020
1021                         for (int i=0; i < pts.Length; i++) {
1022                                 switch (((PathPointType)types [i] & PathPointType.PathTypeMask)) {
1023                                         case PathPointType.Start :
1024                                                 NativeObject.moveTo (pts [i].X, pts [i].Y);
1025                                                 break;
1026                                         case PathPointType.Line :
1027                                                 NativeObject.lineTo (pts [i].X, pts [i].Y);
1028                                                 break;
1029                                         case PathPointType.Bezier3 :
1030                                                 float x1 = pts [i].X;
1031                                                 float y1 = pts [i].Y;
1032                                                 i++;
1033                                                 float x2 = pts [i].X;
1034                                                 float y2 = pts [i].Y;
1035                                                 i++;
1036                                                 float x3 = pts [i].X;
1037                                                 float y3 = pts [i].Y;
1038                                                 NativeObject.curveTo (x1,y1, x2, y2, x3, y3);
1039                                                 break;                                          
1040                                 }
1041                                 if (((PathPointType)types [i] & PathPointType.CloseSubpath) != 0)
1042                                         NativeObject.closePath();
1043
1044                                 if (((PathPointType)types [i] & PathPointType.PathMarker) != 0)
1045                                         NativeObject.SetMarkers ();
1046                         }
1047                 }
1048
1049                 internal void SetPath (PointF [] pts, byte [] types)
1050                 {
1051                         NativeObject.Clear ();
1052                         if (((PathPointType)types [0] & PathPointType.PathTypeMask) != PathPointType.Start)
1053                                 NativeObject.moveTo (pts [0].X, pts [0].Y);
1054                         for (int i=0; i < pts.Length; i++) {
1055                                 switch (((PathPointType)types [i] & PathPointType.PathTypeMask)) {
1056                                         case PathPointType.Start :
1057                                                 NativeObject.moveTo (pts [i].X, pts [i].Y);
1058                                                 break;
1059                                         case PathPointType.Line :
1060                                                 NativeObject.lineTo (pts [i].X, pts [i].Y);
1061                                                 break;
1062                                         case PathPointType.Bezier3 :
1063                                                 float x1 = pts [i].X;
1064                                                 float y1 = pts [i].Y;
1065                                                 i++;
1066                                                 float x2 = pts [i].X;
1067                                                 float y2 = pts [i].Y;
1068                                                 i++;
1069                                                 float x3 = pts [i].X;
1070                                                 float y3 = pts [i].Y;
1071                                                 NativeObject.curveTo (x1,y1, x2, y2, x3, y3);
1072                                                 break;                                          
1073                                 }
1074                                 if (((PathPointType)types [i] & PathPointType.CloseSubpath) != 0)
1075                                         NativeObject.closePath();
1076
1077                                 if (((PathPointType)types [i] & PathPointType.PathMarker) != 0)
1078                                         NativeObject.SetMarkers ();
1079                         }
1080                 }
1081         }
1082 }