Support new features of Xamari.Forms (#186)
[platform/core/csapi/xsf.git] / src / XSF / Xamarin.Forms.Core / ColorTypeConverter.cs
1 using System;
2 using System.Linq;
3 using System.Globalization;
4 using Xamarin.Forms.Internals;
5
6 namespace Xamarin.Forms
7 {
8         [Xaml.ProvideCompiled("Xamarin.Forms.Core.XamlC.ColorTypeConverter")]
9         [Xaml.TypeConversion(typeof(Color))]
10         public class ColorTypeConverter : TypeConverter
11         {
12                 // Supported inputs
13                 // HEX          #rgb, #argb, #rrggbb, #aarrggbb
14                 // RGB          rgb(255,0,0), rgb(100%,0%,0%)                                   values in range 0-255 or 0%-100%
15                 // RGBA         rgba(255, 0, 0, 0.8), rgba(100%, 0%, 0%, 0.8)   opacity is 0.0-1.0
16                 // HSL          hsl(120, 100%, 50%)                                                             h is 0-360, s and l are 0%-100%
17                 // HSLA         hsla(120, 100%, 50%, .8)                                                opacity is 0.0-1.0
18                 // HSV          hsv(120, 100%, 50%)                                                             h is 0-360, s and v are 0%-100%
19                 // HSVA         hsva(120, 100%, 50%, .8)                                                opacity is 0.0-1.0
20                 // Predefined color                                                                                     case insensitive
21                 public override object ConvertFromInvariantString(string value)
22                 {
23                         if (value != null)
24                         {
25                                 value = value.Trim();
26                                 if (value.StartsWith("#", StringComparison.Ordinal))
27                                         return Color.FromHex(value);
28
29                                 if (value.StartsWith("rgba", StringComparison.OrdinalIgnoreCase)) {
30                                         var op = value.IndexOf('(');
31                                         var cp = value.LastIndexOf(')');
32                                         if (op < 0 || cp < 0 || cp < op)
33                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
34                                         var quad = value.Substring(op + 1, cp - op - 1).Split(',');
35                                         if (quad.Length != 4)
36                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
37                                         var r = ParseColorValue(quad[0], 255, acceptPercent: true);
38                                         var g = ParseColorValue(quad[1], 255, acceptPercent: true);
39                                         var b = ParseColorValue(quad[2], 255, acceptPercent: true);
40                                         var a = ParseOpacity(quad[3]);
41                                         return new Color(r, g, b, a);
42                                 }
43
44                                 if (value.StartsWith("rgb", StringComparison.OrdinalIgnoreCase)) {
45                                         var op = value.IndexOf('(');
46                                         var cp = value.LastIndexOf(')');
47                                         if (op < 0 || cp < 0 || cp < op)
48                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
49                                         var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
50                                         if (triplet.Length != 3)
51                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
52                                         var r = ParseColorValue(triplet[0], 255, acceptPercent: true);
53                                         var g = ParseColorValue(triplet[1], 255, acceptPercent: true);
54                                         var b = ParseColorValue(triplet[2], 255, acceptPercent: true);
55                                         return new Color(r, g, b);
56                                 }
57
58                                 if (value.StartsWith("hsla", StringComparison.OrdinalIgnoreCase)) {
59                                         var op = value.IndexOf('(');
60                                         var cp = value.LastIndexOf(')');
61                                         if (op < 0 || cp < 0 || cp < op)
62                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
63                                         var quad = value.Substring(op + 1, cp - op - 1).Split(',');
64                                         if (quad.Length != 4)
65                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
66                                         var h = ParseColorValue(quad[0], 360, acceptPercent: false);
67                                         var s = ParseColorValue(quad[1], 100, acceptPercent: true);
68                                         var l = ParseColorValue(quad[2], 100, acceptPercent: true);
69                                         var a = ParseOpacity(quad[3]);
70                                         return Color.FromHsla(h, s, l, a);
71                                 }
72
73                                 if (value.StartsWith("hsl", StringComparison.OrdinalIgnoreCase)) {
74                                         var op = value.IndexOf('(');
75                                         var cp = value.LastIndexOf(')');
76                                         if (op < 0 || cp < 0 || cp < op)
77                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
78                                         var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
79                                         if (triplet.Length != 3)
80                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
81                                         var h = ParseColorValue(triplet[0], 360, acceptPercent: false);
82                                         var s = ParseColorValue(triplet[1], 100, acceptPercent: true);
83                                         var l = ParseColorValue(triplet[2], 100, acceptPercent: true);
84                                         return Color.FromHsla(h, s, l);
85                                 }
86
87                                 if (value.StartsWith("hsva", StringComparison.OrdinalIgnoreCase))
88                                 {
89                                         var op = value.IndexOf('(');
90                                         var cp = value.LastIndexOf(')');
91                                         if (op < 0 || cp < 0 || cp < op)
92                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
93                                         var quad = value.Substring(op + 1, cp - op - 1).Split(',');
94                                         if (quad.Length != 4)
95                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
96                                         var h = ParseColorValue(quad[0], 360, acceptPercent: false);
97                                         var s = ParseColorValue(quad[1], 100, acceptPercent: true);
98                                         var v = ParseColorValue(quad[2], 100, acceptPercent: true);
99                                         var a = ParseOpacity(quad[3]);
100                                         return Color.FromHsva(h, s, v, a);
101                                 }
102
103                                 if (value.StartsWith("hsv", StringComparison.OrdinalIgnoreCase))
104                                 {
105                                         var op = value.IndexOf('(');
106                                         var cp = value.LastIndexOf(')');
107                                         if (op < 0 || cp < 0 || cp < op)
108                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
109                                         var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
110                                         if (triplet.Length != 3)
111                                                 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
112                                         var h = ParseColorValue(triplet[0], 360, acceptPercent: false);
113                                         var s = ParseColorValue(triplet[1], 100, acceptPercent: true);
114                                         var v = ParseColorValue(triplet[2], 100, acceptPercent: true);
115                                         return Color.FromHsv(h, s, v);
116                                 }
117
118                                 string[] parts = value.Split('.');
119                                 if (parts.Length == 1 || (parts.Length == 2 && parts[0] == "Color"))
120                                 {
121                                         string color = parts[parts.Length - 1];
122                                         switch (color.ToLowerInvariant()) {
123                                         case "default": return Color.Default;
124                                         case "accent": return Color.Accent;
125                                         case "aliceblue": return Color.AliceBlue;
126                                         case "antiquewhite": return Color.AntiqueWhite;
127                                         case "aqua": return Color.Aqua;
128                                         case "aquamarine": return Color.Aquamarine;
129                                         case "azure": return Color.Azure;
130                                         case "beige": return Color.Beige;
131                                         case "bisque": return Color.Bisque;
132                                         case "black": return Color.Black;
133                                         case "blanchedalmond": return Color.BlanchedAlmond;
134                                         case "blue": return Color.Blue;
135                                         case "blueViolet": return Color.BlueViolet;
136                                         case "brown": return Color.Brown;
137                                         case "burlywood": return Color.BurlyWood;
138                                         case "cadetblue": return Color.CadetBlue;
139                                         case "chartreuse": return Color.Chartreuse;
140                                         case "chocolate": return Color.Chocolate;
141                                         case "coral": return Color.Coral;
142                                         case "cornflowerblue": return Color.CornflowerBlue;
143                                         case "cornsilk": return Color.Cornsilk;
144                                         case "crimson": return Color.Crimson;
145                                         case "cyan": return Color.Cyan;
146                                         case "darkblue": return Color.DarkBlue;
147                                         case "darkcyan": return Color.DarkCyan;
148                                         case "darkgoldenrod": return Color.DarkGoldenrod;
149                                         case "darkgray": return Color.DarkGray;
150                                         case "darkgreen": return Color.DarkGreen;
151                                         case "darkkhaki": return Color.DarkKhaki;
152                                         case "darkmagenta": return Color.DarkMagenta;
153                                         case "darkolivegreen": return Color.DarkOliveGreen;
154                                         case "darkorange": return Color.DarkOrange;
155                                         case "darkorchid": return Color.DarkOrchid;
156                                         case "darkred": return Color.DarkRed;
157                                         case "darksalmon": return Color.DarkSalmon;
158                                         case "darkseagreen": return Color.DarkSeaGreen;
159                                         case "darkslateblue": return Color.DarkSlateBlue;
160                                         case "darkslategray": return Color.DarkSlateGray;
161                                         case "darkturquoise": return Color.DarkTurquoise;
162                                         case "darkviolet": return Color.DarkViolet;
163                                         case "deeppink": return Color.DeepPink;
164                                         case "deepskyblue": return Color.DeepSkyBlue;
165                                         case "dimgray": return Color.DimGray;
166                                         case "dodgerblue": return Color.DodgerBlue;
167                                         case "firebrick": return Color.Firebrick;
168                                         case "floralwhite": return Color.FloralWhite;
169                                         case "forestgreen": return Color.ForestGreen;
170                                         case "fuchsia": return Color.Fuchsia;
171                                         case "gainsboro": return Color.Gainsboro;
172                                         case "ghostwhite": return Color.GhostWhite;
173                                         case "gold": return Color.Gold;
174                                         case "goldenrod": return Color.Goldenrod;
175                                         case "gray": return Color.Gray;
176                                         case "green": return Color.Green;
177                                         case "greenyellow": return Color.GreenYellow;
178                                         case "honeydew": return Color.Honeydew;
179                                         case "hotpink": return Color.HotPink;
180                                         case "indianred": return Color.IndianRed;
181                                         case "indigo": return Color.Indigo;
182                                         case "ivory": return Color.Ivory;
183                                         case "khaki": return Color.Khaki;
184                                         case "lavender": return Color.Lavender;
185                                         case "lavenderblush": return Color.LavenderBlush;
186                                         case "lawngreen": return Color.LawnGreen;
187                                         case "lemonchiffon": return Color.LemonChiffon;
188                                         case "lightblue": return Color.LightBlue;
189                                         case "lightcoral": return Color.LightCoral;
190                                         case "lightcyan": return Color.LightCyan;
191                                         case "lightgoldenrodyellow": return Color.LightGoldenrodYellow;
192                                         case "lightgrey":
193                                         case "lightgray": return Color.LightGray;
194                                         case "lightgreen": return Color.LightGreen;
195                                         case "lightpink": return Color.LightPink;
196                                         case "lightsalmon": return Color.LightSalmon;
197                                         case "lightseagreen": return Color.LightSeaGreen;
198                                         case "lightskyblue": return Color.LightSkyBlue;
199                                         case "lightslategray": return Color.LightSlateGray;
200                                         case "lightsteelblue": return Color.LightSteelBlue;
201                                         case "lightyellow": return Color.LightYellow;
202                                         case "lime": return Color.Lime;
203                                         case "limegreen": return Color.LimeGreen;
204                                         case "linen": return Color.Linen;
205                                         case "magenta": return Color.Magenta;
206                                         case "maroon": return Color.Maroon;
207                                         case "mediumaquamarine": return Color.MediumAquamarine;
208                                         case "mediumblue": return Color.MediumBlue;
209                                         case "mediumorchid": return Color.MediumOrchid;
210                                         case "mediumpurple": return Color.MediumPurple;
211                                         case "mediumseagreen": return Color.MediumSeaGreen;
212                                         case "mediumslateblue": return Color.MediumSlateBlue;
213                                         case "mediumspringgreen": return Color.MediumSpringGreen;
214                                         case "mediumturquoise": return Color.MediumTurquoise;
215                                         case "mediumvioletred": return Color.MediumVioletRed;
216                                         case "midnightblue": return Color.MidnightBlue;
217                                         case "mintcream": return Color.MintCream;
218                                         case "mistyrose": return Color.MistyRose;
219                                         case "moccasin": return Color.Moccasin;
220                                         case "navajowhite": return Color.NavajoWhite;
221                                         case "navy": return Color.Navy;
222                                         case "oldlace": return Color.OldLace;
223                                         case "olive": return Color.Olive;
224                                         case "olivedrab": return Color.OliveDrab;
225                                         case "orange": return Color.Orange;
226                                         case "orangered": return Color.OrangeRed;
227                                         case "orchid": return Color.Orchid;
228                                         case "palegoldenrod": return Color.PaleGoldenrod;
229                                         case "palegreen": return Color.PaleGreen;
230                                         case "paleturquoise": return Color.PaleTurquoise;
231                                         case "palevioletred": return Color.PaleVioletRed;
232                                         case "papayawhip": return Color.PapayaWhip;
233                                         case "peachpuff": return Color.PeachPuff;
234                                         case "peru": return Color.Peru;
235                                         case "pink": return Color.Pink;
236                                         case "plum": return Color.Plum;
237                                         case "powderblue": return Color.PowderBlue;
238                                         case "purple": return Color.Purple;
239                                         case "red": return Color.Red;
240                                         case "rosybrown": return Color.RosyBrown;
241                                         case "royalblue": return Color.RoyalBlue;
242                                         case "saddlebrown": return Color.SaddleBrown;
243                                         case "salmon": return Color.Salmon;
244                                         case "sandybrown": return Color.SandyBrown;
245                                         case "seagreen": return Color.SeaGreen;
246                                         case "seashell": return Color.SeaShell;
247                                         case "sienna": return Color.Sienna;
248                                         case "silver": return Color.Silver;
249                                         case "skyblue": return Color.SkyBlue;
250                                         case "slateblue": return Color.SlateBlue;
251                                         case "slategray": return Color.SlateGray;
252                                         case "snow": return Color.Snow;
253                                         case "springgreen": return Color.SpringGreen;
254                                         case "steelblue": return Color.SteelBlue;
255                                         case "tan": return Color.Tan;
256                                         case "teal": return Color.Teal;
257                                         case "thistle": return Color.Thistle;
258                                         case "tomato": return Color.Tomato;
259                                         case "transparent": return Color.Transparent;
260                                         case "turquoise": return Color.Turquoise;
261                                         case "violet": return Color.Violet;
262                                         case "wheat": return Color.Wheat;
263                                         case "white": return Color.White;
264                                         case "whitesmoke": return Color.WhiteSmoke;
265                                         case "yellow": return Color.Yellow;
266                                         case "yellowgreen": return Color.YellowGreen;
267                                         }
268                                         var field = typeof(Color).GetFields().FirstOrDefault(fi => fi.IsStatic && string.Equals(fi.Name, color, StringComparison.OrdinalIgnoreCase));
269                                         if (field != null)
270                                                 return (Color)field.GetValue(null);
271                                         var property = typeof(Color).GetProperties().FirstOrDefault(pi => string.Equals(pi.Name, color, StringComparison.OrdinalIgnoreCase) && pi.CanRead && pi.GetMethod.IsStatic);
272                                         if (property != null)
273                                                 return (Color)property.GetValue(null, null);
274                                 }
275                         }
276
277                         throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
278                 }
279
280                 static double ParseColorValue(string elem, int maxValue, bool acceptPercent)
281                 {
282                         elem = elem.Trim();
283                         if (elem.EndsWith("%", StringComparison.Ordinal) && acceptPercent) {
284                                 maxValue = 100;
285                                 elem = elem.Substring(0, elem.Length - 1);
286                         }
287                         return double.Parse(elem, NumberStyles.Number, CultureInfo.InvariantCulture).Clamp(0, maxValue) / maxValue;
288                 }
289
290                 static double ParseOpacity(string elem)
291                 {
292                         return double.Parse(elem, NumberStyles.Number, CultureInfo.InvariantCulture).Clamp(0, 1);
293                 }
294         }
295 }