Consolidate the code and only switch on int/double.Parse.

This commit is contained in:
Eric Erhardt 2022-03-09 14:58:22 -06:00
Родитель 9f2e493f4c
Коммит 9cace0d81c
6 изменённых файлов: 420 добавлений и 388 удалений

Просмотреть файл

@ -1,72 +0,0 @@
using System;
using System.Globalization;
namespace Microsoft.Maui.Graphics
{
public partial class Color
{
private static Color FromArgbImplementation(string colorAsHex)
{
ReadOnlySpan<char> colorAsHexSpan = colorAsHex;
//Skip # if present
if (colorAsHexSpan[0] == '#')
colorAsHexSpan = colorAsHexSpan.Slice(1);
int red = 0;
int green = 0;
int blue = 0;
int alpha = 255;
if (colorAsHexSpan.Length == 6)
{
//#RRGGBB
red = ParseInt(colorAsHexSpan.Slice(0, 2));
green = ParseInt(colorAsHexSpan.Slice(2, 2));
blue = ParseInt(colorAsHexSpan.Slice(4, 2));
}
else if (colorAsHexSpan.Length == 3)
{
//#RGB
Span<char> temp = stackalloc char[2];
temp[0] = temp[1] = colorAsHexSpan[0];
red = ParseInt(temp);
temp[0] = temp[1] = colorAsHexSpan[1];
green = ParseInt(temp);
temp[0] = temp[1] = colorAsHexSpan[2];
blue = ParseInt(temp);
}
else if (colorAsHexSpan.Length == 4)
{
//#ARGB
Span<char> temp = stackalloc char[2];
temp[0] = temp[1] = colorAsHexSpan[0];
alpha = ParseInt(temp);
temp[0] = temp[1] = colorAsHexSpan[1];
red = ParseInt(temp);
temp[0] = temp[1] = colorAsHexSpan[2];
green = ParseInt(temp);
temp[0] = temp[1] = colorAsHexSpan[3];
blue = ParseInt(temp);
}
else if (colorAsHexSpan.Length == 8)
{
//#AARRGGBB
alpha = ParseInt(colorAsHexSpan.Slice(0, 2));
red = ParseInt(colorAsHexSpan.Slice(2, 2));
green = ParseInt(colorAsHexSpan.Slice(4, 2));
blue = ParseInt(colorAsHexSpan.Slice(6, 2));
}
return FromRgba(red / 255f, green / 255f, blue / 255f, alpha / 255f);
}
private static int ParseInt(ReadOnlySpan<char> s) =>
int.Parse(s, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
}
}

Просмотреть файл

@ -1,56 +0,0 @@
using System.Globalization;
namespace Microsoft.Maui.Graphics
{
public partial class Color
{
private static Color FromArgbImplementation(string colorAsHex)
{
//Skip # if present
if (colorAsHex[0] == '#')
colorAsHex = colorAsHex.Substring(1);
int red = 0;
int green = 0;
int blue = 0;
int alpha = 255;
if (colorAsHex.Length == 6)
{
//#RRGGBB
red = ParseInt(colorAsHex.Substring(0, 2));
green = ParseInt(colorAsHex.Substring(2, 2));
blue = ParseInt(colorAsHex.Substring(4, 2));
}
else if (colorAsHex.Length == 3)
{
//#RGB
red = ParseInt($"{colorAsHex[0]}{colorAsHex[0]}");
green = ParseInt($"{colorAsHex[1]}{colorAsHex[1]}");
blue = ParseInt($"{colorAsHex[2]}{colorAsHex[2]}");
}
else if (colorAsHex.Length == 4)
{
//#ARGB
alpha = ParseInt($"{colorAsHex[0]}{colorAsHex[0]}");
red = ParseInt($"{colorAsHex[1]}{colorAsHex[1]}");
green = ParseInt($"{colorAsHex[2]}{colorAsHex[2]}");
blue = ParseInt($"{colorAsHex[3]}{colorAsHex[3]}");
}
else if (colorAsHex.Length == 8)
{
//#AARRGGBB
alpha = ParseInt(colorAsHex.Substring(0, 2));
red = ParseInt(colorAsHex.Substring(2, 2));
green = ParseInt(colorAsHex.Substring(4, 2));
blue = ParseInt(colorAsHex.Substring(6, 2));
}
return FromRgba(red / 255f, green / 255f, blue / 255f, alpha / 255f);
}
private static int ParseInt(string s) =>
int.Parse(s, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
}
}

Просмотреть файл

@ -1,15 +1,15 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Numerics;
namespace Microsoft.Maui.Graphics
{
[DebuggerDisplay("Red={Red}, Green={Green}, Blue={Blue}, Alpha={Alpha}")]
[TypeConverter(typeof(Converters.ColorTypeConverter))]
public partial class Color
public class Color
{
public readonly float Red;
public readonly float Green;
@ -382,7 +382,69 @@ namespace Microsoft.Maui.Graphics
return FromRgba(red / 255f, green / 255f, blue / 255f, alpha / 255f);
}
public static Color FromArgb(string colorAsHex) => FromArgbImplementation(colorAsHex);
public static Color FromArgb(string colorAsHex) => FromArgb(colorAsHex != null ? colorAsHex.AsSpan() : default);
static Color FromArgb(ReadOnlySpan<char> colorAsHex)
{
int red = 0;
int green = 0;
int blue = 0;
int alpha = 255;
if (!colorAsHex.IsEmpty)
{
//Skip # if present
if (colorAsHex[0] == '#')
colorAsHex = colorAsHex.Slice(1);
if (colorAsHex.Length == 6)
{
//#RRGGBB
red = ParseInt(colorAsHex.Slice(0, 2));
green = ParseInt(colorAsHex.Slice(2, 2));
blue = ParseInt(colorAsHex.Slice(4, 2));
}
else if (colorAsHex.Length == 3)
{
//#RGB
Span<char> temp = stackalloc char[2];
temp[0] = temp[1] = colorAsHex[0];
red = ParseInt(temp);
temp[0] = temp[1] = colorAsHex[1];
green = ParseInt(temp);
temp[0] = temp[1] = colorAsHex[2];
blue = ParseInt(temp);
}
else if (colorAsHex.Length == 4)
{
//#ARGB
Span<char> temp = stackalloc char[2];
temp[0] = temp[1] = colorAsHex[0];
alpha = ParseInt(temp);
temp[0] = temp[1] = colorAsHex[1];
red = ParseInt(temp);
temp[0] = temp[1] = colorAsHex[2];
green = ParseInt(temp);
temp[0] = temp[1] = colorAsHex[3];
blue = ParseInt(temp);
}
else if (colorAsHex.Length == 8)
{
//#AARRGGBB
alpha = ParseInt(colorAsHex.Slice(0, 2));
red = ParseInt(colorAsHex.Slice(2, 2));
green = ParseInt(colorAsHex.Slice(4, 2));
blue = ParseInt(colorAsHex.Slice(6, 2));
}
}
return FromRgba(red / 255f, green / 255f, blue / 255f, alpha / 255f);
}
public static Color FromHsla(float h, float s, float l, float a = 1)
{
@ -522,12 +584,14 @@ namespace Microsoft.Maui.Graphics
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
}
public static bool TryParse(string value, out Color color)
public static bool TryParse(string value, out Color color) => TryParse(value != null ? value.AsSpan() : default, out color);
static bool TryParse(ReadOnlySpan<char> value, out Color color)
{
if (value != null)
value = value.Trim();
if (!value.IsEmpty)
{
value = value.Trim();
if (value.StartsWith("#", StringComparison.Ordinal))
if (value[0] == '#')
{
try
{
@ -541,308 +605,127 @@ namespace Microsoft.Maui.Graphics
}
}
if (value.StartsWith("rgba", StringComparison.OrdinalIgnoreCase))
if (value.StartsWith("rgba".AsSpan(), StringComparison.OrdinalIgnoreCase))
{
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
if (!TryParseFourColorRanges(value,
out ReadOnlySpan<char> quad0,
out ReadOnlySpan<char> quad1,
out ReadOnlySpan<char> quad2,
out ReadOnlySpan<char> quad3))
{
color = default;
return false;
}
var quad = value.Substring(op + 1, cp - op - 1).Split(',');
if (quad.Length != 4)
{
color = default;
return false;
}
var r = ParseColorValue(quad[0], 255, acceptPercent: true);
var g = ParseColorValue(quad[1], 255, acceptPercent: true);
var b = ParseColorValue(quad[2], 255, acceptPercent: true);
var a = ParseOpacity(quad[3]);
var r = ParseColorValue(quad0, 255, acceptPercent: true);
var g = ParseColorValue(quad1, 255, acceptPercent: true);
var b = ParseColorValue(quad2, 255, acceptPercent: true);
var a = ParseOpacity(quad3);
color = new Color((float)r, (float)g, (float)b, (float)a);
return true;
}
if (value.StartsWith("rgb", StringComparison.OrdinalIgnoreCase))
if (value.StartsWith("rgb".AsSpan(), StringComparison.OrdinalIgnoreCase))
{
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
if (!TryParseThreeColorRanges(value,
out ReadOnlySpan<char> triplet0,
out ReadOnlySpan<char> triplet1,
out ReadOnlySpan<char> triplet2))
{
color = default;
return false;
}
var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
if (triplet.Length != 3)
{
color = default;
return false;
}
var r = ParseColorValue(triplet[0], 255, acceptPercent: true);
var g = ParseColorValue(triplet[1], 255, acceptPercent: true);
var b = ParseColorValue(triplet[2], 255, acceptPercent: true);
var r = ParseColorValue(triplet0, 255, acceptPercent: true);
var g = ParseColorValue(triplet1, 255, acceptPercent: true);
var b = ParseColorValue(triplet2, 255, acceptPercent: true);
color = new Color((float)r, (float)g, (float)b);
return true;
}
if (value.StartsWith("hsla", StringComparison.OrdinalIgnoreCase))
if (value.StartsWith("hsla".AsSpan(), StringComparison.OrdinalIgnoreCase))
{
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
if (!TryParseFourColorRanges(value,
out ReadOnlySpan<char> quad0,
out ReadOnlySpan<char> quad1,
out ReadOnlySpan<char> quad2,
out ReadOnlySpan<char> quad3))
{
color = default;
return false;
}
var quad = value.Substring(op + 1, cp - op - 1).Split(',');
if (quad.Length != 4)
{
color = default;
return false;
}
var h = ParseColorValue(quad[0], 360, acceptPercent: false);
var s = ParseColorValue(quad[1], 100, acceptPercent: true);
var l = ParseColorValue(quad[2], 100, acceptPercent: true);
var a = ParseOpacity(quad[3]);
var h = ParseColorValue(quad0, 360, acceptPercent: false);
var s = ParseColorValue(quad1, 100, acceptPercent: true);
var l = ParseColorValue(quad2, 100, acceptPercent: true);
var a = ParseOpacity(quad3);
color = Color.FromHsla(h, s, l, a);
return true;
}
if (value.StartsWith("hsl", StringComparison.OrdinalIgnoreCase))
if (value.StartsWith("hsl".AsSpan(), StringComparison.OrdinalIgnoreCase))
{
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
if (!TryParseThreeColorRanges(value,
out ReadOnlySpan<char> triplet0,
out ReadOnlySpan<char> triplet1,
out ReadOnlySpan<char> triplet2))
{
color = default;
return false;
}
var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
if (triplet.Length != 3)
{
color = default;
return false;
}
var h = ParseColorValue(triplet[0], 360, acceptPercent: false);
var s = ParseColorValue(triplet[1], 100, acceptPercent: true);
var l = ParseColorValue(triplet[2], 100, acceptPercent: true);
var h = ParseColorValue(triplet0, 360, acceptPercent: false);
var s = ParseColorValue(triplet1, 100, acceptPercent: true);
var l = ParseColorValue(triplet2, 100, acceptPercent: true);
color = Color.FromHsla(h, s, l);
return true;
}
if (value.StartsWith("hsva", StringComparison.OrdinalIgnoreCase))
if (value.StartsWith("hsva".AsSpan(), StringComparison.OrdinalIgnoreCase))
{
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
if (!TryParseFourColorRanges(value,
out ReadOnlySpan<char> quad0,
out ReadOnlySpan<char> quad1,
out ReadOnlySpan<char> quad2,
out ReadOnlySpan<char> quad3))
{
color = default;
return false;
}
var quad = value.Substring(op + 1, cp - op - 1).Split(',');
if (quad.Length != 4)
{
color = default;
return false;
}
var h = ParseColorValue(quad[0], 360, acceptPercent: false);
var s = ParseColorValue(quad[1], 100, acceptPercent: true);
var v = ParseColorValue(quad[2], 100, acceptPercent: true);
var a = ParseOpacity(quad[3]);
var h = ParseColorValue(quad0, 360, acceptPercent: false);
var s = ParseColorValue(quad1, 100, acceptPercent: true);
var v = ParseColorValue(quad2, 100, acceptPercent: true);
var a = ParseOpacity(quad3);
color = Color.FromHsva((float)h, (float)s, (float)v, (float)a);
return true;
}
if (value.StartsWith("hsv", StringComparison.OrdinalIgnoreCase))
if (value.StartsWith("hsv".AsSpan(), StringComparison.OrdinalIgnoreCase))
{
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
if (!TryParseThreeColorRanges(value,
out ReadOnlySpan<char> triplet0,
out ReadOnlySpan<char> triplet1,
out ReadOnlySpan<char> triplet2))
{
color = default;
return false;
}
var triplet = value.Substring(op + 1, cp - op - 1).Split(',');
if (triplet.Length != 3)
{
color = default;
return false;
}
var h = ParseColorValue(triplet[0], 360, acceptPercent: false);
var s = ParseColorValue(triplet[1], 100, acceptPercent: true);
var v = ParseColorValue(triplet[2], 100, acceptPercent: true);
var h = ParseColorValue(triplet0, 360, acceptPercent: false);
var s = ParseColorValue(triplet1, 100, acceptPercent: true);
var v = ParseColorValue(triplet2, 100, acceptPercent: true);
color = Color.FromHsv((float)h, (float)s, (float)v);
return true;
}
var namedColor = value?.ToLowerInvariant() switch
{
"default" => default,
"aliceblue" => Colors.AliceBlue,
"antiquewhite" => Colors.AntiqueWhite,
"aqua" => Colors.Aqua,
"aquamarine" => Colors.Aquamarine,
"azure" => Colors.Azure,
"beige" => Colors.Beige,
"bisque" => Colors.Bisque,
"black" => Colors.Black,
"blanchedalmond" => Colors.BlanchedAlmond,
"blue" => Colors.Blue,
"blueViolet" => Colors.BlueViolet,
"brown" => Colors.Brown,
"burlywood" => Colors.BurlyWood,
"cadetblue" => Colors.CadetBlue,
"chartreuse" => Colors.Chartreuse,
"chocolate" => Colors.Chocolate,
"coral" => Colors.Coral,
"cornflowerblue" => Colors.CornflowerBlue,
"cornsilk" => Colors.Cornsilk,
"crimson" => Colors.Crimson,
"cyan" => Colors.Cyan,
"darkblue" => Colors.DarkBlue,
"darkcyan" => Colors.DarkCyan,
"darkgoldenrod" => Colors.DarkGoldenrod,
"darkgray" => Colors.DarkGray,
"darkgreen" => Colors.DarkGreen,
"darkkhaki" => Colors.DarkKhaki,
"darkmagenta" => Colors.DarkMagenta,
"darkolivegreen" => Colors.DarkOliveGreen,
"darkorange" => Colors.DarkOrange,
"darkorchid" => Colors.DarkOrchid,
"darkred" => Colors.DarkRed,
"darksalmon" => Colors.DarkSalmon,
"darkseagreen" => Colors.DarkSeaGreen,
"darkslateblue" => Colors.DarkSlateBlue,
"darkslategray" => Colors.DarkSlateGray,
"darkturquoise" => Colors.DarkTurquoise,
"darkviolet" => Colors.DarkViolet,
"deeppink" => Colors.DeepPink,
"deepskyblue" => Colors.DeepSkyBlue,
"dimgray" => Colors.DimGray,
"dodgerblue" => Colors.DodgerBlue,
"firebrick" => Colors.Firebrick,
"floralwhite" => Colors.FloralWhite,
"forestgreen" => Colors.ForestGreen,
"fuchsia" => Colors.Fuchsia,
"gainsboro" => Colors.Gainsboro,
"ghostwhite" => Colors.GhostWhite,
"gold" => Colors.Gold,
"goldenrod" => Colors.Goldenrod,
"gray" => Colors.Gray,
"green" => Colors.Green,
"greenyellow" => Colors.GreenYellow,
"honeydew" => Colors.Honeydew,
"hotpink" => Colors.HotPink,
"indianred" => Colors.IndianRed,
"indigo" => Colors.Indigo,
"ivory" => Colors.Ivory,
"khaki" => Colors.Khaki,
"lavender" => Colors.Lavender,
"lavenderblush" => Colors.LavenderBlush,
"lawngreen" => Colors.LawnGreen,
"lemonchiffon" => Colors.LemonChiffon,
"lightblue" => Colors.LightBlue,
"lightcoral" => Colors.LightCoral,
"lightcyan" => Colors.LightCyan,
"lightgoldenrodyellow" => Colors.LightGoldenrodYellow,
"lightgrey" => Colors.LightGrey,
"lightgray" => Colors.LightGray,
"lightgreen" => Colors.LightGreen,
"lightpink" => Colors.LightPink,
"lightsalmon" => Colors.LightSalmon,
"lightseagreen" => Colors.LightSeaGreen,
"lightskyblue" => Colors.LightSkyBlue,
"lightslategray" => Colors.LightSlateGray,
"lightsteelblue" => Colors.LightSteelBlue,
"lightyellow" => Colors.LightYellow,
"lime" => Colors.Lime,
"limegreen" => Colors.LimeGreen,
"linen" => Colors.Linen,
"magenta" => Colors.Magenta,
"maroon" => Colors.Maroon,
"mediumaquamarine" => Colors.MediumAquamarine,
"mediumblue" => Colors.MediumBlue,
"mediumorchid" => Colors.MediumOrchid,
"mediumpurple" => Colors.MediumPurple,
"mediumseagreen" => Colors.MediumSeaGreen,
"mediumslateblue" => Colors.MediumSlateBlue,
"mediumspringgreen" => Colors.MediumSpringGreen,
"mediumturquoise" => Colors.MediumTurquoise,
"mediumvioletred" => Colors.MediumVioletRed,
"midnightblue" => Colors.MidnightBlue,
"mintcream" => Colors.MintCream,
"mistyrose" => Colors.MistyRose,
"moccasin" => Colors.Moccasin,
"navajowhite" => Colors.NavajoWhite,
"navy" => Colors.Navy,
"oldlace" => Colors.OldLace,
"olive" => Colors.Olive,
"olivedrab" => Colors.OliveDrab,
"orange" => Colors.Orange,
"orangered" => Colors.OrangeRed,
"orchid" => Colors.Orchid,
"palegoldenrod" => Colors.PaleGoldenrod,
"palegreen" => Colors.PaleGreen,
"paleturquoise" => Colors.PaleTurquoise,
"palevioletred" => Colors.PaleVioletRed,
"papayawhip" => Colors.PapayaWhip,
"peachpuff" => Colors.PeachPuff,
"peru" => Colors.Peru,
"pink" => Colors.Pink,
"plum" => Colors.Plum,
"powderblue" => Colors.PowderBlue,
"purple" => Colors.Purple,
"red" => Colors.Red,
"rosybrown" => Colors.RosyBrown,
"royalblue" => Colors.RoyalBlue,
"saddlebrown" => Colors.SaddleBrown,
"salmon" => Colors.Salmon,
"sandybrown" => Colors.SandyBrown,
"seagreen" => Colors.SeaGreen,
"seashell" => Colors.SeaShell,
"sienna" => Colors.Sienna,
"silver" => Colors.Silver,
"skyblue" => Colors.SkyBlue,
"slateblue" => Colors.SlateBlue,
"slategray" => Colors.SlateGray,
"snow" => Colors.Snow,
"springgreen" => Colors.SpringGreen,
"steelblue" => Colors.SteelBlue,
"tan" => Colors.Tan,
"teal" => Colors.Teal,
"thistle" => Colors.Thistle,
"tomato" => Colors.Tomato,
"transparent" => Colors.Transparent,
"turquoise" => Colors.Turquoise,
"violet" => Colors.Violet,
"wheat" => Colors.Wheat,
"white" => Colors.White,
"whitesmoke" => Colors.WhiteSmoke,
"yellow" => Colors.Yellow,
"yellowgreen" => Colors.YellowGreen,
_ => null
};
var namedColor = GetNamedColor(value);
if (namedColor != null)
{
color = namedColor;
@ -854,21 +737,303 @@ namespace Microsoft.Maui.Graphics
return false;
}
static double ParseColorValue(string elem, int maxValue, bool acceptPercent)
static Color GetNamedColor(ReadOnlySpan<char> value)
{
elem = elem.Trim();
if (elem.EndsWith("%", StringComparison.Ordinal) && acceptPercent)
if (s_namedColors.TryGetValue(ComputeIgnoreCaseStringHash(value), out (string, Color) entry))
{
maxValue = 100;
elem = elem.Substring(0, elem.Length - 1);
if (value.Equals(entry.Item1.AsSpan(), StringComparison.OrdinalIgnoreCase))
{
return entry.Item2;
}
}
return double.Parse(elem, NumberStyles.Number, CultureInfo.InvariantCulture).Clamp(0, maxValue) / maxValue;
return null;
}
static double ParseOpacity(string elem)
=> double.Parse(elem, NumberStyles.Number, CultureInfo.InvariantCulture).Clamp(0, 1);
static readonly Dictionary<uint, (string, Color)> s_namedColors = BuildNamedColorDictionary();
static Dictionary<uint, (string, Color)> BuildNamedColorDictionary()
{
Dictionary<uint, (string, Color)> namedColors = new Dictionary<uint, (string, Color)>(capacity: 149);
void AddColor(string name, Color color)
{
uint hash = ComputeIgnoreCaseStringHash(name.AsSpan());
// If we encounter a hash-collison on the known color names, we will need to update our hashing algorithm
Debug.Assert(!namedColors.ContainsKey(hash));
namedColors.Add(hash, (name, color));
}
AddColor("default", default);
AddColor("aliceblue", Colors.AliceBlue);
AddColor("antiquewhite", Colors.AntiqueWhite);
AddColor("aqua", Colors.Aqua);
AddColor("aquamarine", Colors.Aquamarine);
AddColor("azure", Colors.Azure);
AddColor("beige", Colors.Beige);
AddColor("bisque", Colors.Bisque);
AddColor("black", Colors.Black);
AddColor("blanchedalmond", Colors.BlanchedAlmond);
AddColor("blue", Colors.Blue);
AddColor("blueviolet", Colors.BlueViolet);
AddColor("brown", Colors.Brown);
AddColor("burlywood", Colors.BurlyWood);
AddColor("cadetblue", Colors.CadetBlue);
AddColor("chartreuse", Colors.Chartreuse);
AddColor("chocolate", Colors.Chocolate);
AddColor("coral", Colors.Coral);
AddColor("cornflowerblue", Colors.CornflowerBlue);
AddColor("cornsilk", Colors.Cornsilk);
AddColor("crimson", Colors.Crimson);
AddColor("cyan", Colors.Cyan);
AddColor("darkblue", Colors.DarkBlue);
AddColor("darkcyan", Colors.DarkCyan);
AddColor("darkgoldenrod", Colors.DarkGoldenrod);
AddColor("darkgray", Colors.DarkGray);
AddColor("darkgreen", Colors.DarkGreen);
AddColor("darkkhaki", Colors.DarkKhaki);
AddColor("darkmagenta", Colors.DarkMagenta);
AddColor("darkolivegreen", Colors.DarkOliveGreen);
AddColor("darkorange", Colors.DarkOrange);
AddColor("darkorchid", Colors.DarkOrchid);
AddColor("darkred", Colors.DarkRed);
AddColor("darksalmon", Colors.DarkSalmon);
AddColor("darkseagreen", Colors.DarkSeaGreen);
AddColor("darkslateblue", Colors.DarkSlateBlue);
AddColor("darkslategray", Colors.DarkSlateGray);
AddColor("darkturquoise", Colors.DarkTurquoise);
AddColor("darkviolet", Colors.DarkViolet);
AddColor("deeppink", Colors.DeepPink);
AddColor("deepskyblue", Colors.DeepSkyBlue);
AddColor("dimgray", Colors.DimGray);
AddColor("dodgerblue", Colors.DodgerBlue);
AddColor("firebrick", Colors.Firebrick);
AddColor("floralwhite", Colors.FloralWhite);
AddColor("forestgreen", Colors.ForestGreen);
AddColor("fuchsia", Colors.Fuchsia);
AddColor("gainsboro", Colors.Gainsboro);
AddColor("ghostwhite", Colors.GhostWhite);
AddColor("gold", Colors.Gold);
AddColor("goldenrod", Colors.Goldenrod);
AddColor("gray", Colors.Gray);
AddColor("green", Colors.Green);
AddColor("greenyellow", Colors.GreenYellow);
AddColor("honeydew", Colors.Honeydew);
AddColor("hotpink", Colors.HotPink);
AddColor("indianred", Colors.IndianRed);
AddColor("indigo", Colors.Indigo);
AddColor("ivory", Colors.Ivory);
AddColor("khaki", Colors.Khaki);
AddColor("lavender", Colors.Lavender);
AddColor("lavenderblush", Colors.LavenderBlush);
AddColor("lawngreen", Colors.LawnGreen);
AddColor("lemonchiffon", Colors.LemonChiffon);
AddColor("lightblue", Colors.LightBlue);
AddColor("lightcoral", Colors.LightCoral);
AddColor("lightcyan", Colors.LightCyan);
AddColor("lightgoldenrodyellow", Colors.LightGoldenrodYellow);
AddColor("lightgrey", Colors.LightGrey);
AddColor("lightgray", Colors.LightGray);
AddColor("lightgreen", Colors.LightGreen);
AddColor("lightpink", Colors.LightPink);
AddColor("lightsalmon", Colors.LightSalmon);
AddColor("lightseagreen", Colors.LightSeaGreen);
AddColor("lightskyblue", Colors.LightSkyBlue);
AddColor("lightslategray", Colors.LightSlateGray);
AddColor("lightsteelblue", Colors.LightSteelBlue);
AddColor("lightyellow", Colors.LightYellow);
AddColor("lime", Colors.Lime);
AddColor("limegreen", Colors.LimeGreen);
AddColor("linen", Colors.Linen);
AddColor("magenta", Colors.Magenta);
AddColor("maroon", Colors.Maroon);
AddColor("mediumaquamarine", Colors.MediumAquamarine);
AddColor("mediumblue", Colors.MediumBlue);
AddColor("mediumorchid", Colors.MediumOrchid);
AddColor("mediumpurple", Colors.MediumPurple);
AddColor("mediumseagreen", Colors.MediumSeaGreen);
AddColor("mediumslateblue", Colors.MediumSlateBlue);
AddColor("mediumspringgreen", Colors.MediumSpringGreen);
AddColor("mediumturquoise", Colors.MediumTurquoise);
AddColor("mediumvioletred", Colors.MediumVioletRed);
AddColor("midnightblue", Colors.MidnightBlue);
AddColor("mintcream", Colors.MintCream);
AddColor("mistyrose", Colors.MistyRose);
AddColor("moccasin", Colors.Moccasin);
AddColor("navajowhite", Colors.NavajoWhite);
AddColor("navy", Colors.Navy);
AddColor("oldlace", Colors.OldLace);
AddColor("olive", Colors.Olive);
AddColor("olivedrab", Colors.OliveDrab);
AddColor("orange", Colors.Orange);
AddColor("orangered", Colors.OrangeRed);
AddColor("orchid", Colors.Orchid);
AddColor("palegoldenrod", Colors.PaleGoldenrod);
AddColor("palegreen", Colors.PaleGreen);
AddColor("paleturquoise", Colors.PaleTurquoise);
AddColor("palevioletred", Colors.PaleVioletRed);
AddColor("papayawhip", Colors.PapayaWhip);
AddColor("peachpuff", Colors.PeachPuff);
AddColor("peru", Colors.Peru);
AddColor("pink", Colors.Pink);
AddColor("plum", Colors.Plum);
AddColor("powderblue", Colors.PowderBlue);
AddColor("purple", Colors.Purple);
AddColor("red", Colors.Red);
AddColor("rosybrown", Colors.RosyBrown);
AddColor("royalblue", Colors.RoyalBlue);
AddColor("saddlebrown", Colors.SaddleBrown);
AddColor("salmon", Colors.Salmon);
AddColor("sandybrown", Colors.SandyBrown);
AddColor("seagreen", Colors.SeaGreen);
AddColor("seashell", Colors.SeaShell);
AddColor("sienna", Colors.Sienna);
AddColor("silver", Colors.Silver);
AddColor("skyblue", Colors.SkyBlue);
AddColor("slateblue", Colors.SlateBlue);
AddColor("slategray", Colors.SlateGray);
AddColor("snow", Colors.Snow);
AddColor("springgreen", Colors.SpringGreen);
AddColor("steelblue", Colors.SteelBlue);
AddColor("tan", Colors.Tan);
AddColor("teal", Colors.Teal);
AddColor("thistle", Colors.Thistle);
AddColor("tomato", Colors.Tomato);
AddColor("transparent", Colors.Transparent);
AddColor("turquoise", Colors.Turquoise);
AddColor("violet", Colors.Violet);
AddColor("wheat", Colors.Wheat);
AddColor("white", Colors.White);
AddColor("whitesmoke", Colors.WhiteSmoke);
AddColor("yellow", Colors.Yellow);
AddColor("yellowgreen", Colors.YellowGreen);
return namedColors;
}
// this algorithm was taken from Roslyn when it creates a string jump table, modified to use ToLowerInvariant
// https://github.com/dotnet/roslyn/blob/6920e1e044dcadbc53e0af7d1582190fdcb88ec6/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.Lowered.cs#L23
static uint ComputeIgnoreCaseStringHash(ReadOnlySpan<char> s)
{
uint hashCode = 2166136261u;
for (int i = 0; i < s.Length; i++)
{
hashCode = unchecked((char.ToLowerInvariant(s[i]) ^ hashCode) * 16777619);
}
return hashCode;
}
static bool TryParseFourColorRanges(
ReadOnlySpan<char> value,
out ReadOnlySpan<char> quad0,
out ReadOnlySpan<char> quad1,
out ReadOnlySpan<char> quad2,
out ReadOnlySpan<char> quad3)
{
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
goto ReturnFalse;
value = value.Slice(op + 1, cp - op - 1);
int index = value.IndexOf(',');
if (index == -1)
goto ReturnFalse;
quad0 = value.Slice(0, index);
value = value.Slice(index + 1);
index = value.IndexOf(',');
if (index == -1)
goto ReturnFalse;
quad1 = value.Slice(0, index);
value = value.Slice(index + 1);
index = value.IndexOf(',');
if (index == -1)
goto ReturnFalse;
quad2 = value.Slice(0, index);
quad3 = value.Slice(index + 1);
// if there are more commas, fail
if (quad3.IndexOf(',') != -1)
goto ReturnFalse;
return true;
ReturnFalse:
quad0 = quad1 = quad2 = quad3 = default;
return false;
}
static bool TryParseThreeColorRanges(
ReadOnlySpan<char> value,
out ReadOnlySpan<char> triplet0,
out ReadOnlySpan<char> triplet1,
out ReadOnlySpan<char> triplet2)
{
var op = value.IndexOf('(');
var cp = value.LastIndexOf(')');
if (op < 0 || cp < 0 || cp < op)
goto ReturnFalse;
value = value.Slice(op + 1, cp - op - 1);
int index = value.IndexOf(',');
if (index == -1)
goto ReturnFalse;
triplet0 = value.Slice(0, index);
value = value.Slice(index + 1);
index = value.IndexOf(',');
if (index == -1)
goto ReturnFalse;
triplet1 = value.Slice(0, index);
triplet2 = value.Slice(index + 1);
// if there are more commas, fail
if (triplet2.IndexOf(',') != -1)
goto ReturnFalse;
return true;
ReturnFalse:
triplet0 = triplet1 = triplet2 = default;
return false;
}
static double ParseColorValue(ReadOnlySpan<char> elem, int maxValue, bool acceptPercent)
{
elem = elem.Trim();
if (!elem.IsEmpty && elem[elem.Length - 1] == '%' && acceptPercent)
{
maxValue = 100;
elem = elem.Slice(0, elem.Length - 1);
}
return ParseDouble(elem).Clamp(0, maxValue) / maxValue;
}
static double ParseOpacity(ReadOnlySpan<char> elem)
=> ParseDouble(elem).Clamp(0, 1);
static double ParseDouble(ReadOnlySpan<char> s) =>
double.Parse(
#if NETSTANDARD2_0
s.ToString(),
#else
s,
#endif
NumberStyles.Number, CultureInfo.InvariantCulture);
static int ParseInt(ReadOnlySpan<char> s) =>
int.Parse(
#if NETSTANDARD2_0
s.ToString(),
#else
s,
#endif
NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
public static implicit operator Color(Vector4 color) => new Color(color);
}
}

Просмотреть файл

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net6.0-ios;net6.0-android;net6.0-maccatalyst;net6.0-macos;net6.0-tizen6.5</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0-ios;net6.0-android;net6.0-maccatalyst;net6.0-macos;net6.0-tizen6.5</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows')) and '$(MSBuildRuntimeType)' == 'Full'">$(TargetFrameworks);net6.0-windows10.0.18362</TargetFrameworks>
<!-- Optional: Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
@ -20,6 +20,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Memory" Version="4.5.4" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" Condition="$(TargetFramework.StartsWith('netstandard'))" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0" Condition="$(TargetFramework.Contains('-windows'))" />
</ItemGroup>

Просмотреть файл

@ -55,12 +55,6 @@
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<Compile Remove="**\*.NETCoreApp.cs"/>
<None Include="**\*.NETCoreApp.cs"/>
<Compile Remove="**\NETCoreApp\*.cs"/>
<None Include="**\NETCoreApp\*.cs"/>
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('netcoreapp')) != true ">
<Compile Remove="**\*.Win32.cs"/>
<None Include="**\*.Win32.cs"/>

Просмотреть файл

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>