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