Refeence latest ExCSS instead of copying it (#990)

* reference latest ExCSS (version 4.1.4)
* remove copied ExCSS sources
* fix style tests
This commit is contained in:
H1Gdev 2022-07-16 17:16:25 +09:00 коммит произвёл GitHub
Родитель aee2e93fa5
Коммит 8c9b1f2b6d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
80 изменённых файлов: 51 добавлений и 11616 удалений

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

@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using Fizzler;
using Svg.ExCSS;
using ExCSS;
namespace Svg.Css
{
@ -14,63 +14,16 @@ namespace Svg.Css
return generator.Selector(Enumerable.Repeat(elem, 1));
}
public static int GetSpecificity(this BaseSelector selector)
public static int GetSpecificity(this ISelector selector)
{
if (selector is SimpleSelector)
{
var simpleCode = selector.ToString().ToLowerInvariant();
if (simpleCode.StartsWith(":not("))
{
simpleCode = simpleCode.Substring(5, simpleCode.Length - 6);
return GetSpecificity(new SimpleSelector(simpleCode));
}
else if (simpleCode.StartsWith("#"))
{
// ID selector
return 1 << 12;
}
else if (simpleCode.StartsWith("::") || simpleCode == ":after" || simpleCode == ":before" ||
simpleCode == ":first-letter" || simpleCode == ":first-line" || simpleCode == ":selection")
{
// pseudo-element
return 1 << 4;
}
else if (simpleCode.StartsWith(".") || simpleCode.StartsWith(":") || simpleCode.StartsWith("["))
{
// class, pseudo-class, attribute
return 1 << 8;
}
else if (simpleCode.Equals("*"))
{
// all selector
return 0;
}
else
{
// element selector
return 1 << 4;
}
}
else
{
var list = selector as IEnumerable<BaseSelector>;
if (list != null)
{
return (from s in list select GetSpecificity(s)).Aggregate((p, c) => p + c);
}
else
{
var complex = selector as IEnumerable<CombinatorSelector>;
if (complex != null)
{
return (from s in complex select GetSpecificity(s.Selector)).Aggregate((p, c) => p + c);
}
else
{
return 0;
}
}
}
var specificity = 0x0;
// ID selector
specificity |= (1 << 12) * selector.Specificity.Ids;
// class selector
specificity |= (1 << 8) * selector.Specificity.Classes;
// element selector
specificity |= (1 << 4) * selector.Specificity.Tags;
return specificity;
}
}
}

7
Source/External/ExCSS/IToString.cs поставляемый
Просмотреть файл

@ -1,7 +0,0 @@
namespace Svg.ExCSS
{
public interface IToString
{
string ToString(bool friendlyFormat, int indentation = 0);
}
}

1227
Source/External/ExCSS/Lexer.cs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

257
Source/External/ExCSS/Model/Enumerations.cs поставляемый
Просмотреть файл

@ -1,257 +0,0 @@

// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
internal static class RuleTypes
{
internal const string CharacterSet = "charset";
internal const string Keyframes = "keyframes";
internal const string Media = "media";
internal const string Page = "page";
internal const string Import = "import";
internal const string FontFace = "font-face";
internal const string Namespace = "namespace";
internal const string Supports = "supports";
internal const string Document = "document";
}
internal static class PseudoSelectorPrefix
{
internal const string NthChildOdd = "odd";
internal const string NthChildEven = "even";
internal const string NthChildN = "n";
internal const string PseudoFunctionNthchild = "nth-child";
internal const string PseudoFunctionNthlastchild = "nth-last-child";
internal const string PseudoFunctionNthOfType = "nth-of-type";
internal const string PseudoFunctionNthLastOfType = "nth-last-of-type";
internal const string PseudoRoot = "root";
internal const string PseudoFirstOfType = "first-of-type";
internal const string PseudoLastoftype = "last-of-type";
internal const string PseudoOnlychild = "only-child";
internal const string PseudoOnlyOfType = "only-of-type";
internal const string PseudoFirstchild = "first-child";
internal const string PseudoLastchild = "last-child";
internal const string PseudoEmpty = "empty";
internal const string PseudoLink = "link";
internal const string PseudoVisited = "visited";
internal const string PseudoActive = "active";
internal const string PseudoHover = "hover";
internal const string PseudoFocus = "focus";
internal const string PseudoTarget = "target";
internal const string PseudoEnabled = "enabled";
internal const string PseudoDisabled = "disabled";
internal const string PseudoChecked = "checked";
internal const string PseudoUnchecked = "unchecked";
internal const string PseudoIndeterminate = "indeterminate";
internal const string PseudoDefault = "default";
internal const string PseudoValid = "valid";
internal const string PseudoInvalid = "invalid";
internal const string PseudoRequired = "required";
internal const string PseudoInrange = "in-range";
internal const string PseudoOutofrange = "out-of-range";
internal const string PseudoOptional = "optional";
internal const string PseudoReadonly = "read-only";
internal const string PseudoReadwrite = "read-write";
internal const string PseudoFunctionDir = "dir";
internal const string PseudoFunctionNot = "not";
internal const string PseudoFunctionLang = "lang";
internal const string PseudoFunctionContains = "contains";
internal const string PseudoElementBefore = "before";
internal const string PseudoElementAfter = "after";
internal const string PseudoElementSelection = "selection";
internal const string PseudoElementFirstline = "first-line";
internal const string PseudoElementFirstletter = "first-letter";
}
internal static class ErrorMessages
{
internal const string InvalidCharacter = "Invalid character detected.";
internal const string LineBreakEof = "Unexpected line break or EOF.";
internal const string UnexpectedCommentToken = "The input element is unexpected and has been ignored.";
internal const string DoubleQuotedString = "Expected double quoted string to terminate before form feed or line feed.";
internal const string DoubleQuotedStringEof = "Expected double quoted string to terminate before end of file.";
internal const string SingleQuotedString = "Expected single quoted string to terminate before form feed or line feed.";
internal const string SingleQuotedStringEof = "Expected single quoted string to terminate before end of file.";
internal const string InvalidCharacterAfterHash = "Invalid character after #.";
internal const string InvalidIdentAfterHash = "Invalid character after #.";
internal const string InvalidUrlEnd = "Expected URL to terminate before line break or end of file.";
internal const string InvalidUrlQuote = "Expected quotation or open paren in URL.";
internal const string InvalidUrlCharacter = "Invalid character in URL.";
internal const string ExpectedCommentEnd = "Expected comment to close before end of file.";
internal const string Default = "An unexpected error occurred.";
}
public enum Combinator
{
Child,
Descendent,
AdjacentSibling,
Sibling,
Namespace
}
internal enum GrammarSegment
{
String,
Url,
UrlPrefix,
Domain,
Hash, //#
AtRule, //@
Ident,
Function,
Number,
Percentage,
Dimension,
Range,
CommentOpen,
CommentClose,
Column,
Delimiter,
IncludeMatch, //~=
DashMatch, // |=
PrefixMatch, // ^=
SuffixMatch, // $=
SubstringMatch, // *=
NegationMatch, // !=
ParenOpen,
ParenClose,
CurlyBraceOpen,
CurlyBracketClose,
SquareBraceOpen,
SquareBracketClose,
Colon,
Comma,
Semicolon,
Whitespace
}
public enum RuleType
{
Unknown = 0,
Style = 1,
Charset = 2,
Import = 3,
Media = 4,
FontFace = 5,
Page = 6,
Keyframes = 7,
Keyframe = 8,
Namespace = 10,
CounterStyle = 11,
Supports = 12,
Document = 13,
FontFeatureValues = 14,
Viewport = 15,
RegionStyle = 16
}
public enum UnitType
{
Unknown = 0,
Number = 1,
Percentage = 2,
Ems = 3,
Exs = 4,
Pixel = 5,
Centimeter = 6,
Millimeter = 7,
Inch = 8,
Point = 9,
Percent = 10,
Degree = 11,
Radian = 12,
Grad = 13,
Millisecond = 14,
Second = 15,
Hertz = 16,
KiloHertz = 17,
Dimension = 18,
String = 19,
Uri = 20,
Ident = 21,
Attribute = 22,
Counter = 23,
Rect = 24,
RGB = 25,
ViewportWidth = 26,
ViewportHeight = 28,
ViewportMin = 29,
ViewportMax = 30,
Turn = 31,
}
public enum DocumentFunction
{
Url,
UrlPrefix,
Domain,
RegExp
}
public enum DirectionMode
{
LeftToRight,
RightToLeft
}
public enum ParserError
{
EndOfFile,
UnexpectedLineBreak,
InvalidCharacter,
UnexpectedCommentToken
}
internal enum SelectorOperation
{
Data,
Attribute,
AttributeOperator,
AttributeValue,
AttributeEnd,
Class,
PseudoClass,
PseudoClassFunction,
PseudoClassFunctionEnd,
PseudoElement
}
internal enum ParsingContext
{
DataBlock,
InSelector,
InDeclaration,
AfterProperty,
BeforeValue,
InValuePool,
InValueList,
InSingleValue,
InMediaList,
InMediaValue,
BeforeImport,
BeforeCharset,
BeforeNamespacePrefix,
AfterNamespacePrefix,
BeforeFontFace,
FontfaceData,
FontfaceProperty,
AfterInstruction,
InCondition,
BeforeKeyframesName,
BeforeKeyframesData,
KeyframesData,
InKeyframeText,
BeforePageSelector,
BeforeDocumentFunction,
InDocumentFunction,
AfterDocumentFunction,
BetweenDocumentFunctions,
InUnknown,
ValueImportant,
AfterValue,
InHexValue,
InFunction
}
}

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

@ -1,80 +0,0 @@
using System.Collections.Generic;
namespace Svg.ExCSS.Model.Extensions
{
static class CharacterExtensions
{
public static int FromHex(this char character)
{
return character.IsDigit() ? character - 0x30 : character - (character.IsLowercaseAscii() ? 0x57 : 0x37);
}
public static string TrimArray(this char[] array)
{
var start = 0;
var end = array.Length - 1;
while (start < array.Length && array[start].IsSpaceCharacter())
{
start++;
}
while (end > start && array[end].IsSpaceCharacter())
{
end--;
}
return new string(array, start, 1 + end - start);
}
public static string[] SplitOnCommas(this string value)
{
var list = new List<string>();
var buffer = new List<char>();
var chars = value.ToCharArray();
for (var i = 0; i <= chars.Length; i++)
{
if (i == chars.Length || chars[i] == ',')
{
if (buffer.Count <= 0)
{
continue;
}
var token = buffer.ToArray().TrimArray();
if (token.Length != 0)
{
list.Add(token);
}
buffer.Clear();
}
else
{
buffer.Add(chars[i]);
}
}
return list.ToArray();
}
public static string ToHex(this byte num)
{
var characters = new char[2];
var rem = num >> 4;
characters[0] = (char)(rem + (rem < 10 ? 48 : 55));
rem = num - 16 * rem;
characters[1] = (char)(rem + (rem < 10 ? 48 : 55));
return new string(characters);
}
public static char ToHexChar(this byte num)
{
var rem = num & 0x0F;
return (char)(rem + (rem < 10 ? 48 : 55));
}
}
}

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

@ -1,59 +0,0 @@
using System;
using System.Text;
namespace Svg.ExCSS.Model.Extensions
{
public static class StringExtensions
{
public static string Indent(this string value, bool friendlyForamt, int indentation)
{
if (!friendlyForamt)
{
return value;
}
var tabs = new StringBuilder();
for (var i = 0; i < indentation; i++)
{
tabs.Append("\t");
}
return string.Format("{0}{1}", tabs, value);
}
public static string NewLineIndent(this string value, bool friendlyFormat, int indentation)
{
if (!friendlyFormat)
{
return value;
}
return Environment.NewLine + value.Indent(true, indentation);
}
public static string TrimFirstLine(this string value)
{
return new StringBuilder(value).TrimFirstLine().ToString();
}
public static StringBuilder TrimLastLine(this StringBuilder builder)
{
while (builder[builder.Length - 1] == '\r' || builder[builder.Length - 1] == '\n' || builder[builder.Length - 1] == '\t')
{
builder.Remove(builder.Length - 1, 1);
}
return builder;
}
public static StringBuilder TrimFirstLine(this StringBuilder builder)
{
while (builder[0] == '\r' || builder[0] == '\n' || builder[0] == '\t')
{
builder.Remove(0, 1);
}
return builder;
}
}
}

137
Source/External/ExCSS/Model/FunctionBuffer.cs поставляемый
Просмотреть файл

@ -1,137 +0,0 @@
using System;
using System.Collections.Generic;
namespace Svg.ExCSS.Model
{
internal class FunctionBuffer
{
private readonly string _function;
private readonly List<Term> _termList;
private Term _term;
internal FunctionBuffer(string function)
{
_termList = new List<Term>();
_function = function;
}
public List<Term> TermList
{
get { return _termList; }
}
public Term Term
{
get { return _term; }
set { _term = value; }
}
public void Include()
{
if (_term != null)
{
_termList.Add(_term);
}
_term = null;
}
public Term Done()
{
Include();
return BuildFunctionTerm(_function, _termList);
}
private Term BuildFunctionTerm(string name, List<Term> terms)
{
switch (name)
{
case "rgb":
{
if (terms.Count == 3)
{
if (CheckNumber(terms[0]) &&
CheckNumber(terms[1]) &&
CheckNumber(terms[2]))
{
return HtmlColor.FromRgb(
ToByte(terms[0]),
ToByte(terms[1]),
ToByte(terms[2]));
}
}
break;
}
case "rgba":
{
if (terms.Count == 4)
{
if (CheckNumber(terms[0]) &&
CheckNumber(terms[1]) &&
CheckNumber(terms[2]) &&
CheckNumber(terms[3]))
{
return HtmlColor.FromRgba(
ToByte(terms[0]),
ToByte(terms[1]),
ToByte(terms[2]),
ToSingle(terms[3]));
}
}
break;
}
case "hsl":
{
if (_termList.Count == 3)
{
if (CheckNumber(terms[0]) &&
CheckNumber(terms[1]) &&
CheckNumber(terms[2]))
{
return HtmlColor.FromHsl(
ToSingle(terms[0]),
ToSingle(terms[1]),
ToSingle(terms[2]));
}
}
break;
}
}
return new GenericFunction(name, terms);
}
private static bool CheckNumber(Term cssValue)
{
return (cssValue is PrimitiveTerm &&
((PrimitiveTerm)cssValue).PrimitiveType == UnitType.Number);
}
private static Single ToSingle(Term cssValue)
{
var value = ((PrimitiveTerm)cssValue).GetFloatValue(UnitType.Number);
return value.HasValue
? value.Value
: 0f;
}
private static byte ToByte(Single? value)
{
if (value.HasValue)
{
return (byte)Math.Min(Math.Max(value.Value, 0), 255);
}
return 0;
}
private static byte ToByte(Term cssValue)
{
return ToByte(((PrimitiveTerm)cssValue).GetFloatValue(UnitType.Number));
}
}
}

459
Source/External/ExCSS/Model/HtmlEncoding.cs поставляемый
Просмотреть файл

@ -1,459 +0,0 @@
using System;
using System.Text;
namespace Svg.ExCSS.Model
{
internal static class HtmlEncoding
{
internal static string Extract(string content)
{
var position = 0;
content = content.ToLower();
for (var i = position; i < content.Length - 7; i++)
{
if (!content.Substring(i).StartsWith("charset"))
{
continue;
}
position = i + 7;
break;
}
if (position <= 0 || position >= content.Length)
{
return string.Empty;
}
for (var i = position; i < content.Length - 1; i++)
{
if (content[i].IsSpaceCharacter())
{
position++;
}
else
{
break;
}
}
if (content[position] != Specification.EqualSign)
{
return Extract(content.Substring(position));
}
position++;
for (var i = position; i < content.Length; i++)
{
if (content[i].IsSpaceCharacter())
{
position++;
}
else
{
break;
}
}
if (position >= content.Length)
{
return string.Empty;
}
switch (content[position])
{
case Specification.DoubleQuote:
{
content = content.Substring(position + 1);
var index = content.IndexOf(Specification.DoubleQuote);
if (index != -1)
{
return content.Substring(0, index);
}
}
break;
case Specification.SingleQuote:
{
content = content.Substring(position + 1);
var index = content.IndexOf(Specification.SingleQuote);
if (index != -1)
{
return content.Substring(0, index);
}
}
break;
default:
{
content = content.Substring(position);
var index = 0;
for (var i = 0; i < content.Length; i++)
{
if (content[i].IsSpaceCharacter())
{
break;
}
if (content[i] == ';')
{
break;
}
index++;
}
return content.Substring(0, index);
}
}
return string.Empty;
}
internal static bool IsSupported(string charset)
{
return Resolve(charset) != null;
}
internal static Encoding Resolve(string charset)
{
charset = charset.ToLower();
switch (charset)
{
case "unicode-1-1-utf-8":
case "utf-8":
case "utf8":
return Encoding.UTF8;
case "utf-16be":
return Encoding.BigEndianUnicode;
case "utf-16":
case "utf-16le":
return Encoding.Unicode;
case "dos-874":
case "iso-8859-11":
case "iso8859-11":
case "iso885911":
case "tis-620":
case "windows-874":
return Encoding.GetEncoding("windows-874");
case "cp1250":
case "windows-1250":
case "x-cp1250":
return Encoding.GetEncoding("windows-1250");
case "cp1251":
case "windows-1251":
case "x-cp1251":
return Encoding.GetEncoding("windows-1251");
case "ansi_x3.4-1968":
case "ascii":
case "cp1252":
case "cp819":
case "csisolatin1":
case "ibm819":
case "iso-8859-1":
case "iso-ir-100":
case "iso8859-1":
case "iso88591":
case "iso_8859-1":
case "iso_8859-1:1987":
case "l1":
case "latin1":
case "us-ascii":
case "windows-1252":
case "x-cp1252":
return Encoding.GetEncoding("windows-1252");
case "cp1253":
case "windows-1253":
case "x-cp1253":
return Encoding.GetEncoding("windows-1253");
case "cp1254":
case "csisolatin5":
case "iso-8859-9":
case "iso-ir-148":
case "iso8859-9":
case "iso88599":
case "iso_8859-9":
case "iso_8859-9:1989":
case "l5":
case "latin5":
case "windows-1254":
case "x-cp1254":
return Encoding.GetEncoding("windows-1254");
case "cp1255":
case "windows-1255":
case "x-cp1255":
return Encoding.GetEncoding("windows-1255");
case "cp1256":
case "windows-1256":
case "x-cp1256":
return Encoding.GetEncoding("windows-1256");
case "cp1257":
case "windows-1257":
case "x-cp1257":
return Encoding.GetEncoding("windows-1257");
case "cp1258":
case "windows-1258":
case "x-cp1258":
return Encoding.GetEncoding("windows-1258");
case "csmacintosh":
case "mac":
case "macintosh":
case "x-mac-roman":
return Encoding.GetEncoding("macintosh");
case "x-mac-cyrillic":
case "x-mac-ukrainian":
return Encoding.GetEncoding("x-mac-cyrillic");
case "866":
case "cp866":
case "csibm866":
case "ibm866":
return Encoding.GetEncoding("cp866");
case "csisolatin2":
case "iso-8859-2":
case "iso-ir-101":
case "iso8859-2":
case "iso88592":
case "iso_8859-2":
case "iso_8859-2:1987":
case "l2":
case "latin2":
return Encoding.GetEncoding("iso-8859-2");
case "csisolatin3":
case "iso-8859-3":
case "iso-ir-109":
case "iso8859-3":
case "iso88593":
case "iso_8859-3":
case "iso_8859-3:1988":
case "l3":
case "latin3":
return Encoding.GetEncoding("iso-8859-3");
case "csisolatin4":
case "iso-8859-4":
case "iso-ir-110":
case "iso8859-4":
case "iso88594":
case "iso_8859-4":
case "iso_8859-4:1988":
case "l4":
case "latin4":
return Encoding.GetEncoding("iso-8859-4");
case "csisolatincyrillic":
case "cyrillic":
case "iso-8859-5":
case "iso-ir-144":
case "iso8859-5":
case "iso88595":
case "iso_8859-5":
case "iso_8859-5:1988":
return Encoding.GetEncoding("iso-8859-5");
case "arabic":
case "asmo-708":
case "csiso88596e":
case "csiso88596i":
case "csisolatinarabic":
case "ecma-114":
case "iso-8859-6":
case "iso-8859-6-e":
case "iso-8859-6-i":
case "iso-ir-127":
case "iso8859-6":
case "iso88596":
case "iso_8859-6":
case "iso_8859-6:1987":
return Encoding.GetEncoding("iso-8859-6");
case "csisolatingreek":
case "ecma-118":
case "elot_928":
case "greek":
case "greek8":
case "iso-8859-7":
case "iso-ir-126":
case "iso8859-7":
case "iso88597":
case "iso_8859-7":
case "iso_8859-7:1987":
case "sun_eu_greek":
return Encoding.GetEncoding("iso-8859-7");
case "csiso88598e":
case "csisolatinhebrew":
case "hebrew":
case "iso-8859-8":
case "iso-8859-8-e":
case "iso-ir-138":
case "iso8859-8":
case "iso88598":
case "iso_8859-8":
case "iso_8859-8:1988":
case "visual":
return Encoding.GetEncoding("iso-8859-8");
case "csiso88598i":
case "iso-8859-8-i":
case "logical":
return Encoding.GetEncoding("iso-8859-8-i");
case "iso-8859-13":
case "iso8859-13":
case "iso885913":
return Encoding.GetEncoding("iso-8859-13");
case "csisolatin9":
case "iso-8859-15":
case "iso8859-15":
case "iso885915":
case "iso_8859-15":
case "l9":
return Encoding.GetEncoding("iso-8859-15");
case "cskoi8r":
case "koi":
case "koi8":
case "koi8-r":
case "koi8_r":
return Encoding.GetEncoding("koi8-r");
case "koi8-u":
return Encoding.GetEncoding("koi8-u");
case "chinese":
case "csgb2312":
case "csiso58gb231280":
case "gb2312":
case "gb_2312":
case "gb_2312-80":
case "gbk":
case "iso-ir-58":
case "x-gbk":
return Encoding.GetEncoding("x-cp20936");
case "hz-gb-2312":
return Encoding.GetEncoding("hz-gb-2312");
case "gb18030":
return Encoding.GetEncoding("GB18030");
case "big5":
case "big5-hkscs":
case "cn-big5":
case "csbig5":
case "x-x-big5":
return Encoding.GetEncoding("big5");
case "csiso2022jp":
case "iso-2022-jp":
return Encoding.GetEncoding("iso-2022-jp");
case "csiso2022kr":
case "iso-2022-kr":
return Encoding.GetEncoding("iso-2022-kr");
case "iso-2022-cn":
case "iso-2022-cn-ext":
return Encoding.GetEncoding("iso-2022-jp");
default:
return null;
}
}
internal static Encoding Suggest(string local)
{
if (local.Length < 2)
return Encoding.UTF8;
var firstTwo = local.Substring(0, 2).ToLower();
switch (firstTwo)
{
case "ar":
case "cy":
case "fa":
case "hr":
case "kk":
case "mk":
case "or":
case "ro":
case "sr":
case "vi":
return Encoding.UTF8;
case "be":
return Encoding.GetEncoding("iso-8859-5");
case "bg":
case "ru":
case "uk":
return Encoding.GetEncoding("windows-1251");
case "cs":
case "hu":
case "pl":
case "sl":
return Encoding.GetEncoding("iso-8859-2");
case "tr":
case "ku":
return Encoding.GetEncoding("windows-1254");
case "he":
return Encoding.GetEncoding("windows-1255");
case "lv":
return Encoding.GetEncoding("iso-8859-13");
case "ja":// Windows-31J ???? Replaced by something better anyway
return Encoding.UTF8;
case "ko":
return Encoding.GetEncoding("ks_c_5601-1987");
case "lt":
return Encoding.GetEncoding("windows-1257");
case "sk":
return Encoding.GetEncoding("windows-1250");
case "th":
return Encoding.GetEncoding("windows-874");
}
if (local.Equals("zh-CN", StringComparison.OrdinalIgnoreCase))
{
return Encoding.GetEncoding("GB18030");
}
return Encoding.GetEncoding(local.Equals("zh-TW", StringComparison.OrdinalIgnoreCase)
? "big5"
: "windows-1252");
}
}
}

9
Source/External/ExCSS/Model/ICssRules.cs поставляемый
Просмотреть файл

@ -1,9 +0,0 @@
using System.Collections.Generic;
namespace Svg.ExCSS.Model
{
interface ISupportsRuleSets
{
List<RuleSet> RuleSets { get; }
}
}

7
Source/External/ExCSS/Model/ICssSelector.cs поставляемый
Просмотреть файл

@ -1,7 +0,0 @@
namespace Svg.ExCSS.Model
{
interface ISupportsSelector
{
BaseSelector Selector { get; set; }
}
}

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

@ -1,7 +0,0 @@
namespace Svg.ExCSS.Model
{
interface ISupportsDeclarations
{
StyleDeclaration Declarations { get; }
}
}

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

@ -1,7 +0,0 @@
namespace Svg.ExCSS.Model
{
interface ISupportsMedia
{
MediaTypeList Media { get; }
}
}

98
Source/External/ExCSS/Model/MediaTypeList.cs поставляемый
Просмотреть файл

@ -1,98 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class MediaTypeList : IEnumerable<string>
{
private readonly List<string> _media;
private string _buffer;
internal MediaTypeList()
{
_buffer = string.Empty;
_media = new List<string>();
}
public string this[int index]
{
get
{
if (index < 0 || index >= _media.Count)
{
return null;
}
return _media[index];
}
set
{
_media[index] = value;
}
}
public int Count
{
get { return _media.Count; }
}
public string MediaType
{
get { return _buffer; }
set
{
_buffer = string.Empty;
_media.Clear();
if (string.IsNullOrEmpty(value))
{
return;
}
var entries = value.SplitOnCommas();
foreach (var t in entries)
{
AppendMedium(t);
}
}
}
internal MediaTypeList AppendMedium(string newMedium)
{
if (_media.Contains(newMedium))
{
return this;
}
_media.Add(newMedium);
_buffer += (string.IsNullOrEmpty(_buffer) ? string.Empty : ",") + newMedium;
return this;
}
public override string ToString()
{
return ToString(false);
}
public string ToString(bool friendlyFormat, int indentation = 0)
{
return friendlyFormat
? string.Join(", ", _media.ToArray())
: string.Join(",", _media.ToArray());
}
public IEnumerator<string> GetEnumerator()
{
return ((IEnumerable<string>)_media).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

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

@ -1,16 +0,0 @@
using System.Collections.Generic;
using Svg.ExCSS.Model;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public abstract class AggregateRule : RuleSet, ISupportsRuleSets
{
protected AggregateRule()
{
RuleSets = new List<RuleSet>();
}
public List<RuleSet> RuleSets { get; private set; }
}
}

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

@ -1,25 +0,0 @@
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class CharacterSetRule : RuleSet
{
public CharacterSetRule()
{
RuleType = RuleType.Charset;
}
public string Encoding { get; internal set; }
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return string.Format("@charset '{0}';", Encoding).NewLineIndent(friendlyFormat, indentation);
}
}
}

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

@ -1,13 +0,0 @@
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public abstract class ConditionalRule : AggregateRule
{
public virtual string Condition
{
get { return string.Empty; }
set { }
}
}
}

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

@ -1,82 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public sealed class DocumentRule : AggregateRule
{
readonly List<KeyValuePair<DocumentFunction, string>> _conditions;
internal DocumentRule()
{
RuleType = RuleType.Document;
_conditions = new List<KeyValuePair<DocumentFunction, string>>();
}
public string ConditionText
{
get
{
var builder = new StringBuilder();
var concat = false;
foreach (var condition in _conditions)
{
if (concat)
{
builder.Append(',');
}
switch (condition.Key)
{
case DocumentFunction.Url:
builder.Append("url");
break;
case DocumentFunction.UrlPrefix:
builder.Append("url-prefix");
break;
case DocumentFunction.Domain:
builder.Append("domain");
break;
case DocumentFunction.RegExp:
builder.Append("regexp");
break;
}
builder.Append(Specification.ParenOpen);
builder.Append(Specification.DoubleQuote);
builder.Append(condition.Value);
builder.Append(Specification.DoubleQuote);
builder.Append(Specification.ParenClose);
concat = true;
}
return builder.ToString();
}
}
internal List<KeyValuePair<DocumentFunction, string>> Conditions
{
get { return _conditions; }
}
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return "@document " + ConditionText + " {" +
RuleSets +
"}".NewLineIndent(friendlyFormat, indentation);
}
}
}

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

@ -1,88 +0,0 @@
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class FontFaceRule : RuleSet, ISupportsDeclarations
{
private readonly StyleDeclaration _declarations;
public FontFaceRule()
{
_declarations = new StyleDeclaration();
RuleType = RuleType.FontFace;
}
internal FontFaceRule AppendRule(Property rule)
{
_declarations.Properties.Add(rule);
return this;
}
public StyleDeclaration Declarations
{
get { return _declarations; }
}
public string FontFamily
{
get { return _declarations.GetPropertyValue("font-family"); }
set { _declarations.SetProperty("font-family", value); }
}
public string Src
{
get { return _declarations.GetPropertyValue("src"); }
set { _declarations.SetProperty("src", value); }
}
public string FontStyle
{
get { return _declarations.GetPropertyValue("font-style"); }
set { _declarations.SetProperty("font-style", value); }
}
public string FontWeight
{
get { return _declarations.GetPropertyValue("font-weight"); }
set { _declarations.SetProperty("font-weight", value); }
}
public string Stretch
{
get { return _declarations.GetPropertyValue("stretch"); }
set { _declarations.SetProperty("stretch", value); }
}
public string UnicodeRange
{
get { return _declarations.GetPropertyValue("unicode-range"); }
set { _declarations.SetProperty("unicode-range", value); }
}
public string FontVariant
{
get { return _declarations.GetPropertyValue("font-variant"); }
set { _declarations.SetProperty("font-variant", value); }
}
public string FeatureSettings
{
get { return _declarations.GetPropertyValue("font-feature-settings"); }
set { _declarations.SetProperty("font-feature-settings", value); }
}
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return "@font-face{".NewLineIndent(friendlyFormat, indentation) +
_declarations.ToString(friendlyFormat, indentation) +
"}".NewLineIndent(friendlyFormat, indentation);
}
}
}

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

@ -1,36 +0,0 @@
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class GenericRule : AggregateRule
{
private string _text;
private bool _stopped;
internal void SetInstruction(string text)
{
_text = text;
_stopped = true;
}
internal void SetCondition(string text)
{
_text = text;
_stopped = false;
}
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
if (_stopped)
{
return _text + ";";
}
return _text + "{" + RuleSets + "}";
}
}
}

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

@ -1,10 +0,0 @@
using System.Collections.Generic;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public interface IRuleContainer
{
List<RuleSet> Declarations { get; }
}
}

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

@ -1,41 +0,0 @@
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class ImportRule : RuleSet, ISupportsMedia
{
private string _href;
private readonly MediaTypeList _media;
public ImportRule()
{
_media = new MediaTypeList();
RuleType = RuleType.Import;
}
public string Href
{
get { return _href; }
set { _href = value; }
}
public MediaTypeList Media
{
get { return _media; }
}
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return _media.Count > 0
? string.Format("@import url({0}) {1};", _href, _media).NewLineIndent(friendlyFormat, indentation)
: string.Format("@import url({0});", _href).NewLineIndent(friendlyFormat, indentation);
}
}
}

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

@ -1,39 +0,0 @@
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class KeyframeRule : RuleSet, ISupportsDeclarations
{
private string _value;
public KeyframeRule()
{
Declarations = new StyleDeclaration();
RuleType = RuleType.Keyframe;
}
public string Value
{
get { return _value; }
set { _value = value; }
}
public StyleDeclaration Declarations { get; private set; }
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return string.Empty.Indent(friendlyFormat, indentation) +
_value +
"{" +
Declarations.ToString(friendlyFormat, indentation) +
"}".NewLineIndent(friendlyFormat, indentation);
}
}
}

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

@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class KeyframesRule : RuleSet, IRuleContainer
{
private readonly List<RuleSet> _ruleSets;
private string _identifier;
public KeyframesRule()
{
_ruleSets = new List<RuleSet>();
RuleType = RuleType.Keyframes;
}
public string Identifier
{
get { return _identifier; }
set { _identifier = value; }
}
//TODO change to "keyframes"
public List<RuleSet> Declarations
{
get { return _ruleSets; }
}
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
var join = friendlyFormat ? "".NewLineIndent(true, indentation) : "";
var declarationList = _ruleSets.Select(d => d.ToString(friendlyFormat, indentation + 1));
var declarations = string.Join(join, declarationList.ToArray());
return ("@keyframes " + _identifier + "{").NewLineIndent(friendlyFormat, indentation) +
declarations.NewLineIndent(friendlyFormat, indentation) +
"}".NewLineIndent(friendlyFormat, indentation);
}
}
}

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

@ -1,47 +0,0 @@
using System;
using System.Linq;
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class MediaRule : ConditionalRule, ISupportsMedia
{
private readonly MediaTypeList _media;
public MediaRule()
{
_media = new MediaTypeList();
RuleType = RuleType.Media;
}
public override string Condition
{
get { return _media.MediaType; }
set { _media.MediaType = value; }
}
public MediaTypeList Media
{
get { return _media; }
}
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
var join = friendlyFormat ? "".NewLineIndent(true, indentation + 1) : "";
var declarationList = RuleSets.Select(d => d.ToString(friendlyFormat, indentation + 1).TrimFirstLine());
var declarations = string.Join(join, declarationList.ToArray());
return ("@media " + _media.MediaType + "{").NewLineIndent(friendlyFormat, indentation) +
declarations.TrimFirstLine().NewLineIndent(friendlyFormat, indentation + 1) +
"}".NewLineIndent(friendlyFormat, indentation);
}
}
}

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

@ -1,30 +0,0 @@
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class NamespaceRule : RuleSet
{
public NamespaceRule()
{
RuleType = RuleType.Namespace;
}
public string Uri { get; set; }
public string Prefix { get; set; }
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return string.IsNullOrEmpty(Prefix)
? string.Format("@namespace '{0}';", Uri).NewLineIndent(friendlyFormat, indentation)
: string.Format("@namespace {0} '{1}';", Prefix, Uri).NewLineIndent(friendlyFormat, indentation);
}
}
}

58
Source/External/ExCSS/Model/Rules/PageRule.cs поставляемый
Просмотреть файл

@ -1,58 +0,0 @@
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class PageRule : RuleSet, ISupportsSelector, ISupportsDeclarations
{
private readonly StyleDeclaration _declarations;
private BaseSelector _selector;
private string _selectorText;
public PageRule()
{
_declarations = new StyleDeclaration();
RuleType = RuleType.Page;
}
internal PageRule AppendRule(Property rule)
{
_declarations.Properties.Add(rule);
return this;
}
public BaseSelector Selector
{
get { return _selector; }
set
{
_selector = value;
_selectorText = value.ToString();
}
}
public StyleDeclaration Declarations
{
get { return _declarations; }
}
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
var pseudo = string.IsNullOrEmpty(_selectorText)
? ""
: ":" + _selectorText;
var declarations = _declarations.ToString(friendlyFormat, indentation);//.TrimFirstLine();
return ("@page " + pseudo + "{").NewLineIndent(friendlyFormat, indentation) +
declarations +
"}".NewLineIndent(friendlyFormat, indentation);
}
}
}

16
Source/External/ExCSS/Model/Rules/RuleSet.cs поставляемый
Просмотреть файл

@ -1,16 +0,0 @@
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public abstract class RuleSet
{
internal RuleSet()
{
RuleType = RuleType.Unknown;
}
public RuleType RuleType { get; set; }
public abstract string ToString(bool friendlyFormat, int indentation = 0);
}
}

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

@ -1,184 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class StyleDeclaration : IList<Property>
{
private readonly List<Property> _properties;
private readonly Func<string> _getter;
private readonly Action<string> _setter;
private bool _blocking;
public StyleDeclaration()
{
var text = string.Empty;
_getter = () => text;
_setter = value => text = value;
_properties = new List<Property>();
}
public string Value
{
get { return _getter(); }
set
{
Update(value);
_setter(value);
}
}
public RuleSet ParentRule { get; set; }
public void Add(Property item)
{
_properties.Add(item);
}
public void Clear()
{
_properties.Clear();
}
public bool Contains(Property item)
{
return _properties.Contains(item);
}
public void CopyTo(Property[] array, int arrayIndex)
{
_properties.CopyTo(array, arrayIndex);
}
public bool Remove(Property item)
{
return _properties.Remove(item);
}
public int IndexOf(Property item)
{
return _properties.IndexOf(item);
}
public void Insert(int index, Property item)
{
_properties.Insert(index, item);
}
public void RemoveAt(int index)
{
_properties.RemoveAt(index);
}
public override string ToString()
{
return ToString(false);
}
public string ToString(bool friendlyFormat, int indentation = 0)
{
var builder = new StringBuilder();
foreach (var property in _properties)
{
if (friendlyFormat)
{
builder.Append(Environment.NewLine);
}
builder.Append(property.ToString(friendlyFormat, indentation + 1)).Append(';');
}
return builder.ToString();
}
internal string RemoveProperty(string propertyName)
{
for (var i = 0; i < _properties.Count; i++)
{
if (!_properties[i].Name.Equals(propertyName))
{
continue;
}
var value = _properties[i].Term;
_properties.RemoveAt(i);
Propagate();
return value.ToString();
}
return null;
}
internal string GetPropertyValue(string propertyName)
{
for (var i = 0; i < _properties.Count; i++)
{
if (_properties[i].Name.Equals(propertyName))
{
return _properties[i].Term.ToString();
}
}
return null;
}
public IEnumerator<Property> GetEnumerator()
{
return _properties.GetEnumerator();
}
public Property this[int index]
{
get { return _properties[index]; }
set { _properties[index] = value; }
}
public List<Property> Properties
{
get { return _properties; }
}
public int Count { get { return _properties.Count; } }
public bool IsReadOnly { get { return false; } }
internal StyleDeclaration SetProperty(string propertyName, string propertyValue)
{
//_properties.Add(Parser.ParseDeclaration(propertyName + ":" + propertyValue));
//TODO
Propagate();
return this;
}
internal void Update(string value)
{
if (_blocking)
{
return;
}
var rules = Parser.ParseDeclarations(value ?? string.Empty).Properties;
_properties.Clear();
_properties.AddRange(rules);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_properties).GetEnumerator();
}
private void Propagate()
{
_blocking = true;
_setter(ToString());
_blocking = false;
}
}
}

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

@ -1,61 +0,0 @@
using System;
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class StyleRule : RuleSet, ISupportsSelector, ISupportsDeclarations
{
private string _value;
private BaseSelector _selector;
private readonly StyleDeclaration _declarations;
public StyleRule() : this(new StyleDeclaration())
{ }
public StyleRule(StyleDeclaration declarations)
{
RuleType = RuleType.Style;
_declarations = declarations;
}
public BaseSelector Selector
{
get { return _selector; }
set
{
_selector = value;
_value = value.ToString();
}
}
public string Value
{
get { return _value; }
set
{
_selector = Parser.ParseSelector(value);
_value = value;
}
}
public StyleDeclaration Declarations
{
get { return _declarations; }
}
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return _value.NewLineIndent(friendlyFormat, indentation) +
"{" +
_declarations.ToString(friendlyFormat, indentation) +
"}".NewLineIndent(friendlyFormat, indentation);
}
}
}

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

@ -1,42 +0,0 @@
using System.Linq;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class SupportsRule : ConditionalRule
{
private string _condition;
public SupportsRule()
{
RuleType = RuleType.Supports;
_condition = string.Empty;
}
public override string Condition
{
get { return _condition; }
set { _condition = value; }
}
public bool IsSupported { get; set; }
public override string ToString()
{
return ToString(false);
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
var join = friendlyFormat ? "".NewLineIndent(true, indentation + 1) : "";
var declarationList = RuleSets.Select(d => d.ToString(friendlyFormat, indentation + 1).TrimFirstLine());
var declarations = string.Join(join, declarationList.ToArray());
return ("@supports" + _condition + "{").NewLineIndent(friendlyFormat, indentation) +
declarations.TrimFirstLine().NewLineIndent(friendlyFormat, indentation + 1) +
"}".NewLineIndent(friendlyFormat, indentation);
}
}
}

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

@ -1,44 +0,0 @@
using System;
using System.Text;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class AggregateSelectorList : SelectorList
{
public readonly string Delimiter;
public AggregateSelectorList(string delimiter)
{
if (delimiter.Length > 1)
{
throw new ArgumentException("Expected single character delimiter or empty string", "delimiter");
}
Delimiter = delimiter;
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
var builder = new StringBuilder();
foreach (var selector in Selectors)
{
builder.Append(selector.ToString(friendlyFormat, indentation + 1));
builder.Append(Delimiter);
}
if (Delimiter.Length <= 0)
{
return builder.ToString();
}
if (builder.Length > 0)
{
builder.Remove(builder.Length - 1, 1);
}
return builder.ToString();
}
}
}

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

@ -1,15 +0,0 @@

// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public abstract class BaseSelector
{
public sealed override string ToString()
{
return ToString(false);
}
public abstract string ToString(bool friendlyFormat, int indentation = 0);
}
}

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

@ -1,46 +0,0 @@
using System;
using Svg.ExCSS.Model;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public struct CombinatorSelector
{
public BaseSelector Selector;
public Combinator Delimiter;
public CombinatorSelector(BaseSelector selector, Combinator delimiter)
{
Selector = selector;
Delimiter = delimiter;
}
public char Character
{
get
{
switch (Delimiter)
{
case Combinator.Child:
return Specification.GreaterThan;
case Combinator.AdjacentSibling:
return Specification.PlusSign;
case Combinator.Descendent:
return Specification.Space;
case Combinator.Sibling:
return Specification.Tilde;
case Combinator.Namespace:
return Specification.Pipe;
default:
throw new NotImplementedException("Unknown combinator: " + Delimiter);
}
}
}
}
}

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

@ -1,66 +0,0 @@
using System;
using System.Text;
using System.Collections.Generic;
using System.Collections;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class ComplexSelector : BaseSelector, IEnumerable<CombinatorSelector>
{
private readonly List<CombinatorSelector> _selectors;
public ComplexSelector()
{
_selectors = new List<CombinatorSelector>();
}
public ComplexSelector AppendSelector(BaseSelector selector, Combinator combinator)
{
_selectors.Add(new CombinatorSelector(selector, combinator));
return this;
}
public IEnumerator<CombinatorSelector> GetEnumerator()
{
return _selectors.GetEnumerator();
}
internal void ConcludeSelector(BaseSelector selector)
{
_selectors.Add(new CombinatorSelector { Selector = selector });
}
public int Length
{
get { return _selectors.Count; }
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_selectors).GetEnumerator();
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
var builder = new StringBuilder();
if (_selectors.Count <= 0)
{
return builder.ToString();
}
var n = _selectors.Count - 1;
for (var i = 0; i < n; i++)
{
builder.Append(_selectors[i].Selector);
builder.Append(_selectors[i].Character);
}
builder.Append(_selectors[n].Selector);
return builder.ToString();
}
}
}

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

@ -1,21 +0,0 @@
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
internal sealed class FirstChildSelector : BaseSelector, IToString
{
FirstChildSelector()
{ }
static FirstChildSelector _instance;
public static FirstChildSelector Instance
{
get { return _instance ?? (_instance = new FirstChildSelector()); }
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return ":" + PseudoSelectorPrefix.PseudoFirstchild;
}
}
}

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

@ -1,21 +0,0 @@
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
internal sealed class LastChildSelector : BaseSelector, IToString
{
LastChildSelector()
{ }
static LastChildSelector _instance;
public static LastChildSelector Instance
{
get { return _instance ?? (_instance = new LastChildSelector()); }
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return ":" + PseudoSelectorPrefix.PseudoLastchild;
}
}
}

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

@ -1,41 +0,0 @@
using System.Text;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class MultipleSelectorList : SelectorList, IToString
{
internal static MultipleSelectorList Create(params SimpleSelector[] selectors)
{
var multiple = new MultipleSelectorList();
foreach (var selector in selectors)
{
multiple.Selectors.Add(selector);
}
return multiple;
}
internal bool IsInvalid { get; set; }
public override string ToString(bool friendlyFormat, int indentation = 0)
{
var builder = new StringBuilder();
if (Selectors.Count <= 0)
{
return builder.ToString();
}
builder.Append(Selectors[0]);
for (var i = 1; i < Selectors.Count; i++)
{
builder.Append(',').Append(Selectors[i]);
}
return builder.ToString();
}
}
}

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

@ -1,24 +0,0 @@

// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
internal abstract class NthChildSelector : BaseSelector, IToString
{
public int Step;
public int Offset;
internal string FunctionText { get; set; }
internal string FormatSelector(string functionName)
{
var format = Offset < 0
? ":{0}({1}n{2})"
: ":{0}({1}n+{2})";
return string.IsNullOrEmpty(FunctionText)
? string.Format(format, functionName, Step, Offset)
: string.Format(":{0}({1})", functionName, FunctionText);
}
public abstract override string ToString(bool friendlyFormat, int indentation = 0);
}
}

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

@ -1,12 +0,0 @@

// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
internal sealed class NthFirstChildSelector : NthChildSelector, IToString
{
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return FormatSelector(PseudoSelectorPrefix.PseudoFunctionNthchild);
}
}
}

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

@ -1,13 +0,0 @@
using System;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
internal sealed class NthLastChildSelector : NthChildSelector, IToString
{
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return FormatSelector(PseudoSelectorPrefix.PseudoFunctionNthlastchild);
}
}
}

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

@ -1,12 +0,0 @@

// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
internal sealed class NthLastOfTypeSelector : NthChildSelector, IToString
{
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return FormatSelector(PseudoSelectorPrefix.PseudoFunctionNthLastOfType);
}
}
}

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

@ -1,12 +0,0 @@

// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
internal sealed class NthOfTypeSelector : NthChildSelector, IToString
{
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return FormatSelector(PseudoSelectorPrefix.PseudoFunctionNthOfType);
}
}
}

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

@ -1,802 +0,0 @@
using System;
using System.Globalization;
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.TextBlocks;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
internal sealed class SelectorFactory
{
private SelectorOperation _selectorOperation;
private BaseSelector _currentSelector;
private AggregateSelectorList _aggregateSelectorList;
private ComplexSelector _complexSelector;
private bool _hasCombinator;
private Combinator _combinator;
private SelectorFactory _nestedSelectorFactory;
private string _attributeName;
private string _attributeValue;
private string _attributeOperator;
internal SelectorFactory()
{
ResetFactory();
}
internal BaseSelector GetSelector()
{
if (_complexSelector != null)
{
_complexSelector.ConcludeSelector(_currentSelector);
_currentSelector = _complexSelector;
}
if (_aggregateSelectorList == null || _aggregateSelectorList.Length == 0)
{
return _currentSelector ?? SimpleSelector.All;
}
if (_currentSelector == null && _aggregateSelectorList.Length == 1)
{
return _aggregateSelectorList[0];
}
if (_currentSelector == null)
{
return _aggregateSelectorList;
}
_aggregateSelectorList.AppendSelector(_currentSelector);
_currentSelector = null;
return _aggregateSelectorList;
}
internal void Apply(Block token)
{
switch (_selectorOperation)
{
case SelectorOperation.Data:
ParseSymbol(token);
break;
case SelectorOperation.Class:
PraseClass(token);
break;
case SelectorOperation.Attribute:
ParseAttribute(token);
break;
case SelectorOperation.AttributeOperator:
ParseAttributeOperator(token);
break;
case SelectorOperation.AttributeValue:
ParseAttributeValue(token);
break;
case SelectorOperation.AttributeEnd:
ParseAttributeEnd(token);
break;
case SelectorOperation.PseudoClass:
ParsePseudoClass(token);
break;
case SelectorOperation.PseudoClassFunction:
ParsePseudoClassFunction(token);
break;
case SelectorOperation.PseudoClassFunctionEnd:
PrasePseudoClassFunctionEnd(token);
break;
case SelectorOperation.PseudoElement:
ParsePseudoElement(token);
break;
}
}
internal SelectorFactory ResetFactory()
{
_attributeName = null;
_attributeValue = null;
_attributeOperator = string.Empty;
_selectorOperation = SelectorOperation.Data;
_combinator = Combinator.Descendent;
_hasCombinator = false;
_currentSelector = null;
_aggregateSelectorList = null;
_complexSelector = null;
return this;
}
private void ParseSymbol(Block token)
{
switch (token.GrammarSegment)
{
// Attribute [A]
case GrammarSegment.SquareBraceOpen:
_attributeName = null;
_attributeValue = null;
_attributeOperator = string.Empty;
_selectorOperation = SelectorOperation.Attribute;
return;
// Pseudo :P
case GrammarSegment.Colon:
_selectorOperation = SelectorOperation.PseudoClass;
return;
// ID #I
case GrammarSegment.Hash:
Insert(SimpleSelector.Id(((SymbolBlock)token).Value));
return;
// Type E
case GrammarSegment.Ident:
Insert(SimpleSelector.Type(((SymbolBlock)token).Value));
return;
// Whitespace
case GrammarSegment.Whitespace:
Insert(Combinator.Descendent);
return;
case GrammarSegment.Delimiter:
ParseDelimiter(token);
return;
case GrammarSegment.Comma:
InsertCommaDelimited();
return;
}
}
private void ParseAttribute(Block token)
{
if (token.GrammarSegment == GrammarSegment.Whitespace)
{
return;
}
_selectorOperation = SelectorOperation.AttributeOperator;
switch (token.GrammarSegment)
{
case GrammarSegment.Ident:
_attributeName = ((SymbolBlock)token).Value;
break;
case GrammarSegment.String:
_attributeName = ((StringBlock)token).Value;
break;
default:
_selectorOperation = SelectorOperation.Data;
break;
}
}
private void ParseAttributeOperator(Block token)
{
if (token.GrammarSegment == GrammarSegment.Whitespace)
{
return;
}
_selectorOperation = SelectorOperation.AttributeValue;
if (token.GrammarSegment == GrammarSegment.SquareBracketClose)
{
ParseAttributeEnd(token);
}
else if (token is MatchBlock || token.GrammarSegment == GrammarSegment.Delimiter)
{
_attributeOperator = token.ToString();
}
else
{
_selectorOperation = SelectorOperation.AttributeEnd;
}
}
private void ParseAttributeValue(Block token)
{
if (token.GrammarSegment == GrammarSegment.Whitespace)
{
return;
}
_selectorOperation = SelectorOperation.AttributeEnd;
switch (token.GrammarSegment)
{
case GrammarSegment.Ident:
_attributeValue = ((SymbolBlock)token).Value;
break;
case GrammarSegment.String:
_attributeValue = ((StringBlock)token).Value;
break;
case GrammarSegment.Number:
_attributeValue = ((NumericBlock)token).Value.ToString(CultureInfo.InvariantCulture);
break;
default:
_selectorOperation = SelectorOperation.Data;
break;
}
}
private void ParseAttributeEnd(Block token)
{
if (token.GrammarSegment == GrammarSegment.Whitespace)
{
return;
}
_selectorOperation = SelectorOperation.Data;
if (token.GrammarSegment != GrammarSegment.SquareBracketClose)
{
return;
}
switch (_attributeOperator)
{
case "=":
Insert(SimpleSelector.AttributeMatch(_attributeName, _attributeValue));
break;
case "~=":
Insert(SimpleSelector.AttributeSpaceSeparated(_attributeName, _attributeValue));
break;
case "|=":
Insert(SimpleSelector.AttributeDashSeparated(_attributeName, _attributeValue));
break;
case "^=":
Insert(SimpleSelector.AttributeStartsWith(_attributeName, _attributeValue));
break;
case "$=":
Insert(SimpleSelector.AttributeEndsWith(_attributeName, _attributeValue));
break;
case "*=":
Insert(SimpleSelector.AttributeContains(_attributeName, _attributeValue));
break;
case "!=":
Insert(SimpleSelector.AttributeNegatedMatch(_attributeName, _attributeValue));
break;
default:
Insert(SimpleSelector.AttributeUnmatched(_attributeName));
break;
}
}
private void ParsePseudoClass(Block token)
{
_selectorOperation = SelectorOperation.Data;
switch (token.GrammarSegment)
{
case GrammarSegment.Colon:
_selectorOperation = SelectorOperation.PseudoElement;
break;
case GrammarSegment.Function:
_attributeName = ((SymbolBlock)token).Value;
_attributeValue = string.Empty;
_selectorOperation = SelectorOperation.PseudoClassFunction;
if (_nestedSelectorFactory != null)
{
_nestedSelectorFactory.ResetFactory();
}
break;
case GrammarSegment.Ident:
var pseudoSelector = GetPseudoSelector(token);
if (pseudoSelector != null)
{
Insert(pseudoSelector);
}
break;
}
}
private void ParsePseudoElement(Block token)
{
if (token.GrammarSegment != GrammarSegment.Ident)
{
return;
}
var data = ((SymbolBlock)token).Value;
switch (data)
{
case PseudoSelectorPrefix.PseudoElementBefore:
Insert(SimpleSelector.PseudoElement(PseudoSelectorPrefix.PseudoElementBefore));
break;
case PseudoSelectorPrefix.PseudoElementAfter:
Insert(SimpleSelector.PseudoElement(PseudoSelectorPrefix.PseudoElementAfter));
break;
case PseudoSelectorPrefix.PseudoElementSelection:
Insert(SimpleSelector.PseudoElement(PseudoSelectorPrefix.PseudoElementSelection));
break;
case PseudoSelectorPrefix.PseudoElementFirstline:
Insert(SimpleSelector.PseudoElement(PseudoSelectorPrefix.PseudoElementFirstline));
break;
case PseudoSelectorPrefix.PseudoElementFirstletter:
Insert(SimpleSelector.PseudoElement(PseudoSelectorPrefix.PseudoElementFirstletter));
break;
default:
Insert(SimpleSelector.PseudoElement(data));
break;
}
}
private void PraseClass(Block token)
{
_selectorOperation = SelectorOperation.Data;
if (token.GrammarSegment == GrammarSegment.Ident)
{
Insert(SimpleSelector.Class(((SymbolBlock)token).Value));
}
}
private void ParsePseudoClassFunction(Block token)
{
if (token.GrammarSegment == GrammarSegment.Whitespace)
{
return;
}
switch (_attributeName)
{
case PseudoSelectorPrefix.PseudoFunctionNthchild:
case PseudoSelectorPrefix.PseudoFunctionNthlastchild:
case PseudoSelectorPrefix.PseudoFunctionNthOfType:
case PseudoSelectorPrefix.PseudoFunctionNthLastOfType:
{
switch (token.GrammarSegment)
{
case GrammarSegment.Ident:
case GrammarSegment.Number:
case GrammarSegment.Dimension:
_attributeValue += token.ToString();
return;
case GrammarSegment.Delimiter:
var chr = ((DelimiterBlock)token).Value;
if (chr == Specification.PlusSign || chr == Specification.MinusSign)
{
_attributeValue += chr;
return;
}
break;
}
break;
}
case PseudoSelectorPrefix.PseudoFunctionNot:
{
if (_nestedSelectorFactory == null)
{
_nestedSelectorFactory = new SelectorFactory();
}
if (token.GrammarSegment != GrammarSegment.ParenClose || _nestedSelectorFactory._selectorOperation != SelectorOperation.Data)
{
_nestedSelectorFactory.Apply(token);
return;
}
break;
}
case PseudoSelectorPrefix.PseudoFunctionDir:
{
if (token.GrammarSegment == GrammarSegment.Ident)
{
_attributeValue = ((SymbolBlock)token).Value;
}
_selectorOperation = SelectorOperation.PseudoClassFunctionEnd;
return;
}
case PseudoSelectorPrefix.PseudoFunctionLang:
{
if (token.GrammarSegment == GrammarSegment.Ident)
{
_attributeValue = ((SymbolBlock)token).Value;
}
_selectorOperation = SelectorOperation.PseudoClassFunctionEnd;
return;
}
case PseudoSelectorPrefix.PseudoFunctionContains:
{
switch (token.GrammarSegment)
{
case GrammarSegment.String:
_attributeValue = ((StringBlock)token).Value;
break;
case GrammarSegment.Ident:
_attributeValue = ((SymbolBlock)token).Value;
break;
}
_selectorOperation = SelectorOperation.PseudoClassFunctionEnd;
return;
}
}
PrasePseudoClassFunctionEnd(token);
}
private void PrasePseudoClassFunctionEnd(Block token)
{
_selectorOperation = SelectorOperation.Data;
if (token.GrammarSegment != GrammarSegment.ParenClose)
{
return;
}
switch (_attributeName)
{
case PseudoSelectorPrefix.PseudoFunctionNthchild:
Insert(GetChildSelector<NthFirstChildSelector>());
break;
case PseudoSelectorPrefix.PseudoFunctionNthlastchild:
Insert(GetChildSelector<NthLastChildSelector>());
break;
case PseudoSelectorPrefix.PseudoFunctionNthOfType:
Insert(GetChildSelector<NthOfTypeSelector>());
break;
case PseudoSelectorPrefix.PseudoFunctionNthLastOfType:
Insert(GetChildSelector<NthLastOfTypeSelector>());
break;
case PseudoSelectorPrefix.PseudoFunctionNot:
{
var selector = _nestedSelectorFactory.GetSelector();
var code = string.Format("{0}({1})", PseudoSelectorPrefix.PseudoFunctionNot, selector);
Insert(SimpleSelector.PseudoClass(code));
break;
}
case PseudoSelectorPrefix.PseudoFunctionDir:
{
var code = string.Format("{0}({1})", PseudoSelectorPrefix.PseudoFunctionDir, _attributeValue);
Insert(SimpleSelector.PseudoClass(code));
break;
}
case PseudoSelectorPrefix.PseudoFunctionLang:
{
var code = string.Format("{0}({1})", PseudoSelectorPrefix.PseudoFunctionLang, _attributeValue);
Insert(SimpleSelector.PseudoClass(code));
break;
}
case PseudoSelectorPrefix.PseudoFunctionContains:
{
var code = string.Format("{0}({1})", PseudoSelectorPrefix.PseudoFunctionContains, _attributeValue);
Insert(SimpleSelector.PseudoClass(code));
break;
}
}
}
private void InsertCommaDelimited()
{
if (_currentSelector == null)
{
return;
}
if (_aggregateSelectorList == null)
{
_aggregateSelectorList = new AggregateSelectorList(",");
}
if (_complexSelector != null)
{
_complexSelector.ConcludeSelector(_currentSelector);
_aggregateSelectorList.AppendSelector(_complexSelector);
_complexSelector = null;
}
else
{
_aggregateSelectorList.AppendSelector(_currentSelector);
}
_currentSelector = null;
}
private void Insert(BaseSelector selector)
{
if (_currentSelector != null)
{
if (!_hasCombinator)
{
var compound = _currentSelector as AggregateSelectorList;
if (compound == null)
{
compound = new AggregateSelectorList("");
compound.AppendSelector(_currentSelector);
}
compound.AppendSelector(selector);
_currentSelector = compound;
}
else
{
if (_complexSelector == null)
{
_complexSelector = new ComplexSelector();
}
_complexSelector.AppendSelector(_currentSelector, _combinator);
_combinator = Combinator.Descendent;
_hasCombinator = false;
_currentSelector = selector;
}
}
else
{
if (_currentSelector == null && _complexSelector == null && _combinator == Combinator.Namespace)
{
_complexSelector = new ComplexSelector();
_complexSelector.AppendSelector(SimpleSelector.Type(""), _combinator);
_currentSelector = selector;
}
else
{
_combinator = Combinator.Descendent;
_hasCombinator = false;
_currentSelector = selector;
}
}
}
private void Insert(Combinator combinator)
{
_hasCombinator = true;
if (combinator != Combinator.Descendent)
{
_combinator = combinator;
}
}
private void ParseDelimiter(Block token)
{
switch (((DelimiterBlock)token).Value)
{
case Specification.Comma:
InsertCommaDelimited();
return;
case Specification.GreaterThan:
Insert(Combinator.Child);
return;
case Specification.PlusSign:
Insert(Combinator.AdjacentSibling);
return;
case Specification.Tilde:
Insert(Combinator.Sibling);
return;
case Specification.Asterisk:
Insert(SimpleSelector.All);
return;
case Specification.Period:
_selectorOperation = SelectorOperation.Class;
return;
case Specification.Pipe:
Insert(Combinator.Namespace);
return;
}
}
private BaseSelector GetChildSelector<T>() where T : NthChildSelector, new()
{
var selector = new T();
if (_attributeValue.Equals(PseudoSelectorPrefix.NthChildOdd, StringComparison.OrdinalIgnoreCase))
{
selector.Step = 2;
selector.Offset = 1;
selector.FunctionText = PseudoSelectorPrefix.NthChildOdd;
}
else if (_attributeValue.Equals(PseudoSelectorPrefix.NthChildEven, StringComparison.OrdinalIgnoreCase))
{
selector.Step = 2;
selector.Offset = 0;
selector.FunctionText = PseudoSelectorPrefix.NthChildEven;
}
else if (!int.TryParse(_attributeValue, out selector.Offset))
{
var index = _attributeValue.IndexOf(PseudoSelectorPrefix.NthChildN, StringComparison.OrdinalIgnoreCase);
if (_attributeValue.Length <= 0 || index == -1)
{
return selector;
}
var first = _attributeValue.Substring(0, index).Replace(" ", "");
var second = "";
if (_attributeValue.Length > index + 1)
{
second = _attributeValue.Substring(index + 1).Replace(" ", "");
}
if (first == string.Empty || (first.Length == 1 && first[0] == Specification.PlusSign))
{
selector.Step = 1;
}
else if (first.Length == 1 && first[0] == Specification.MinusSign)
{
selector.Step = -1;
}
else
{
int step;
if (int.TryParse(first, out step))
{
selector.Step = step;
}
}
if (second == string.Empty)
{
selector.Offset = 0;
}
else
{
int offset;
if (int.TryParse(second, out offset))
{
selector.Offset = offset;
}
}
}
return selector;
}
private static BaseSelector GetPseudoSelector(Block token)
{
switch (((SymbolBlock)token).Value)
{
case PseudoSelectorPrefix.PseudoRoot:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoRoot);
case PseudoSelectorPrefix.PseudoFirstOfType:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoFirstOfType);
case PseudoSelectorPrefix.PseudoLastoftype:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoLastoftype);
case PseudoSelectorPrefix.PseudoOnlychild:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoOnlychild);
case PseudoSelectorPrefix.PseudoOnlyOfType:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoOnlyOfType);
case PseudoSelectorPrefix.PseudoFirstchild:
return FirstChildSelector.Instance;
case PseudoSelectorPrefix.PseudoLastchild:
return LastChildSelector.Instance;
case PseudoSelectorPrefix.PseudoEmpty:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoEmpty);
case PseudoSelectorPrefix.PseudoLink:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoLink);
case PseudoSelectorPrefix.PseudoVisited:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoVisited);
case PseudoSelectorPrefix.PseudoActive:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoActive);
case PseudoSelectorPrefix.PseudoHover:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoHover);
case PseudoSelectorPrefix.PseudoFocus:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoFocus);
case PseudoSelectorPrefix.PseudoTarget:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoTarget);
case PseudoSelectorPrefix.PseudoEnabled:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoEnabled);
case PseudoSelectorPrefix.PseudoDisabled:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoDisabled);
case PseudoSelectorPrefix.PseudoDefault:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoDefault);
case PseudoSelectorPrefix.PseudoChecked:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoChecked);
case PseudoSelectorPrefix.PseudoIndeterminate:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoIndeterminate);
case PseudoSelectorPrefix.PseudoUnchecked:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoUnchecked);
case PseudoSelectorPrefix.PseudoValid:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoValid);
case PseudoSelectorPrefix.PseudoInvalid:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoInvalid);
case PseudoSelectorPrefix.PseudoRequired:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoRequired);
case PseudoSelectorPrefix.PseudoReadonly:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoReadonly);
case PseudoSelectorPrefix.PseudoReadwrite:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoReadwrite);
case PseudoSelectorPrefix.PseudoInrange:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoInrange);
case PseudoSelectorPrefix.PseudoOutofrange:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoOutofrange);
case PseudoSelectorPrefix.PseudoOptional:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoOptional);
case PseudoSelectorPrefix.PseudoElementBefore:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoElementBefore);
case PseudoSelectorPrefix.PseudoElementAfter:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoElementAfter);
case PseudoSelectorPrefix.PseudoElementFirstline:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoElementFirstline);
case PseudoSelectorPrefix.PseudoElementFirstletter:
return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoElementFirstletter);
default:
return SimpleSelector.PseudoClass(token.ToString());
}
}
}
}

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

@ -1,57 +0,0 @@
using System.Collections;
using System.Collections.Generic;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public abstract class SelectorList : BaseSelector, IEnumerable<BaseSelector>
{
protected List<BaseSelector> Selectors;
protected SelectorList()
{
Selectors = new List<BaseSelector>();
}
public int Length
{
get { return Selectors.Count; }
}
public BaseSelector this[int index]
{
get { return Selectors[index]; }
set { Selectors[index] = value; }
}
public SelectorList AppendSelector(BaseSelector selector)
{
Selectors.Add(selector);
return this;
}
public SelectorList RemoveSelector(SimpleSelector selector)
{
Selectors.Remove(selector);
return this;
}
public SelectorList ClearSelectors()
{
Selectors.Clear();
return this;
}
public IEnumerator<BaseSelector> GetEnumerator()
{
return Selectors.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)Selectors).GetEnumerator();
}
public override abstract string ToString(bool friendlyFormat, int indentation = 0);
}
}

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

@ -1,126 +0,0 @@
using System;
using Svg.ExCSS.Model;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public sealed class SimpleSelector : BaseSelector
{
private readonly string _code;
internal static readonly SimpleSelector All = new SimpleSelector("*");
public SimpleSelector(string selectorText)
{
_code = selectorText;
}
internal static SimpleSelector PseudoElement(string pseudoElement)
{
return new SimpleSelector("::" + pseudoElement);
}
internal static SimpleSelector PseudoClass(string pseudoClass)
{
return new SimpleSelector(":" + pseudoClass);
}
internal static SimpleSelector Class(string match)
{
return new SimpleSelector("." + match);
}
internal static SimpleSelector Id(string match)
{
return new SimpleSelector("#" + match);
}
internal static SimpleSelector AttributeUnmatched(string match)
{
return new SimpleSelector("[" + match + "]");
}
internal static SimpleSelector AttributeMatch(string match, string value)
{
var code = string.Format("[{0}=\"{1}\"]", match, GetValueAsString(value));
return new SimpleSelector(code);
}
internal static SimpleSelector AttributeNegatedMatch(string match, string value)
{
var code = string.Format("[{0}!=\"{1}\"]", match, GetValueAsString(value));
return new SimpleSelector(code);
}
internal static SimpleSelector AttributeSpaceSeparated(string match, string value)
{
var code = string.Format("[{0}~=\"{1}\"]", match, GetValueAsString(value));
return new SimpleSelector(code);
}
internal static SimpleSelector AttributeStartsWith(string match, string value)
{
var code = string.Format("[{0}^=\"{1}\"]", match, GetValueAsString(value));
return new SimpleSelector(code);
}
internal static SimpleSelector AttributeEndsWith(string match, string value)
{
var code = string.Format("[{0}$=\"{1}\"]", match, GetValueAsString(value));
return new SimpleSelector(code);
}
internal static SimpleSelector AttributeContains(string match, string value)
{
var code = string.Format("[{0}*=\"{1}\"]", match, GetValueAsString(value));
return new SimpleSelector(code);
}
internal static SimpleSelector AttributeDashSeparated(string match, string value)
{
var code = string.Format("[{0}|=\"{1}\"]", match, GetValueAsString(value));
return new SimpleSelector(code);
}
internal static SimpleSelector Type(string match)
{
return new SimpleSelector(match);
}
private static string GetValueAsString(string value)
{
var containsSpace = false;
for (var i = 0; i < value.Length; i++)
{
if (!value[i].IsSpaceCharacter())
{
continue;
}
containsSpace = true;
break;
}
if (!containsSpace)
{
return value;
}
if (value.IndexOf(Specification.SingleQuote) != -1)
{
return '"' + value + '"';
}
return "'" + value + "'";
}
public override string ToString(bool friendlyFormat, int indentation = 0)
{
return _code;
}
}
}

98
Source/External/ExCSS/Model/Specification.cs поставляемый
Просмотреть файл

@ -1,98 +0,0 @@
namespace Svg.ExCSS.Model
{
internal static class Specification
{
internal const char EndOfFile = (char)0x1a;
internal const char Tilde = (char)0x7e;
internal const char Pipe = (char)0x7c;
internal const char Null = (char)0x0;
internal const char Ampersand = (char)0x26;
internal const char Hash = (char)0x23;
internal const char DollarSign = (char)0x24;
internal const char Simicolon = (char)0x3b;
internal const char Asterisk = (char)0x2a;
internal const char EqualSign = (char)0x3d;
internal const char PlusSign = (char)0x2b;
internal const char Comma = (char)0x2c;
internal const char Period = (char)0x2e;
internal const char Accent = (char)0x5e;
internal const char At = (char)0x40;
internal const char LessThan = (char)0x3c;
internal const char GreaterThan = (char)0x3e;
internal const char SingleQuote = (char)0x27;
internal const char DoubleQuote = (char)0x22;
internal const char QuestionMark = (char)0x3f;
internal const char Tab = (char)0x09;
internal const char LineFeed = (char)0x0a;
internal const char CarriageReturn = (char)0x0d;
internal const char FormFeed = (char)0x0c;
internal const char Space = (char)0x20;
internal const char Solidus = (char)0x2f;
internal const char ReverseSolidus = (char)0x5c;
internal const char Colon = (char)0x3a;
internal const char Em = (char)0x21;
internal const char MinusSign = (char)0x2d;
internal const char Replacement = (char)0xfffd;
internal const char Underscore = (char)0x5f;
internal const char ParenOpen = (char)0x28;
internal const char ParenClose = (char)0x29;
internal const char Percent = (char)0x25;
internal const char SquareBracketOpen = (char)0x5b;
internal const char SquareBracketClose = (char)0x5d;
internal const char CurlyBraceOpen = (char)0x7b;
internal const char CurlyBraceClose = (char)0x7d;
internal const int MaxPoint = 0x10FFFF;/// The maximum allowed codepoint (defined in Unicode).
internal static bool IsNonPrintable(this char c)
{
return (c >= 0x0 && c <= 0x8) || (c >= 0xe && c <= 0x1f) || (c >= 0x7f && c <= 0x9f);
}
internal static bool IsLetter(this char c)
{
return IsUppercaseAscii(c) || IsLowercaseAscii(c);
}
internal static bool IsName(this char c)
{
return c >= 0x80 || c.IsLetter() || c == Underscore || c == MinusSign || IsDigit(c);
}
internal static bool IsNameStart(this char c)
{
return c >= 0x80 || IsUppercaseAscii(c) || IsLowercaseAscii(c) || c == Underscore;
}
internal static bool IsLineBreak(this char c)
{
//line feed, carriage return
return c == LineFeed || c == CarriageReturn;
}
internal static bool IsSpaceCharacter(this char c)
{
//white space, tab, line feed, form feed, carriage return
return c == Space || c == Tab || c == LineFeed || c == FormFeed || c == CarriageReturn;
}
internal static bool IsDigit(this char c)
{
return c >= 0x30 && c <= 0x39;
}
internal static bool IsUppercaseAscii(this char c)
{
return c >= 0x41 && c <= 0x5a;
}
internal static bool IsLowercaseAscii(this char c)
{
return c >= 0x61 && c <= 0x7a;
}
internal static bool IsHex(this char c)
{
return IsDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66);
}
}
}

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

@ -1,28 +0,0 @@

namespace Svg.ExCSS.Model.TextBlocks
{
internal abstract class Block
{
internal GrammarSegment GrammarSegment { get; set; }
internal static PipeBlock Column
{
get { return PipeBlock.Token; }
}
internal static DelimiterBlock Delim(char value)
{
return new DelimiterBlock(value);
}
internal static NumericBlock Number(string value)
{
return new NumericBlock(value);
}
internal static RangeBlock Range(string start, string end)
{
return new RangeBlock().SetRange(start, end);
}
}
}

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

@ -1,123 +0,0 @@

namespace Svg.ExCSS.Model.TextBlocks
{
internal class BracketBlock : Block
{
private readonly static BracketBlock RoundOpen = new BracketBlock { GrammarSegment = GrammarSegment.ParenOpen, _mirror = GrammarSegment.ParenClose };
private readonly static BracketBlock RoundClose = new BracketBlock { GrammarSegment = GrammarSegment.ParenClose, _mirror = GrammarSegment.ParenOpen };
private readonly static BracketBlock CurlyOpen = new BracketBlock { GrammarSegment = GrammarSegment.CurlyBraceOpen, _mirror = GrammarSegment.CurlyBracketClose };
private readonly static BracketBlock CurlyClose = new BracketBlock { GrammarSegment = GrammarSegment.CurlyBracketClose, _mirror = GrammarSegment.CurlyBraceOpen };
private readonly static BracketBlock SquareOpen = new BracketBlock { GrammarSegment = GrammarSegment.SquareBraceOpen, _mirror = GrammarSegment.SquareBracketClose };
private readonly static BracketBlock SquareClose = new BracketBlock { GrammarSegment = GrammarSegment.SquareBracketClose, _mirror = GrammarSegment.SquareBraceOpen };
private GrammarSegment _mirror;
BracketBlock()
{
}
internal char Open
{
get
{
switch (GrammarSegment)
{
case GrammarSegment.ParenOpen:
return '(';
case GrammarSegment.SquareBraceOpen:
return '[';
default:
return '{';
}
}
}
internal char Close
{
get
{
switch (GrammarSegment)
{
case GrammarSegment.ParenOpen:
return ')';
case GrammarSegment.SquareBraceOpen:
return ']';
default:
return '}';
}
}
}
internal GrammarSegment Mirror
{
get { return _mirror; }
}
internal static BracketBlock OpenRound
{
get { return RoundOpen; }
}
internal static BracketBlock CloseRound
{
get { return RoundClose; }
}
internal static BracketBlock OpenCurly
{
get { return CurlyOpen; }
}
internal static BracketBlock CloseCurly
{
get { return CurlyClose; }
}
internal static BracketBlock OpenSquare
{
get { return SquareOpen; }
}
internal static BracketBlock CloseSquare
{
get { return SquareClose; }
}
public override string ToString()
{
return ToString(false);
}
public string ToString(bool friendlyFormat, int indentation = 0)
{
switch (GrammarSegment)
{
case GrammarSegment.CurlyBraceOpen:
return "{";
case GrammarSegment.CurlyBracketClose:
return "}";
case GrammarSegment.ParenClose:
return ")";
case GrammarSegment.ParenOpen:
return "(";
case GrammarSegment.SquareBracketClose:
return "]";
case GrammarSegment.SquareBraceOpen:
return "[";
}
return string.Empty;
}
}
}

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

@ -1,23 +0,0 @@

namespace Svg.ExCSS.Model.TextBlocks
{
internal abstract class CharacterBlock : Block
{
private readonly char _value;
protected CharacterBlock()
{
_value = Specification.Null;
}
protected CharacterBlock(char value)
{
_value = value;
}
internal char Value
{
get { return _value; }
}
}
}

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

@ -1,35 +0,0 @@

namespace Svg.ExCSS.Model.TextBlocks
{
internal class CommentBlock : Block
{
private readonly static CommentBlock OpenBlock;
private readonly static CommentBlock CloseBlock;
static CommentBlock()
{
OpenBlock = new CommentBlock { GrammarSegment = GrammarSegment.CommentOpen };
CloseBlock = new CommentBlock { GrammarSegment = GrammarSegment.CommentClose };
}
CommentBlock()
{
}
internal static CommentBlock Open
{
get { return OpenBlock; }
}
internal static CommentBlock Close
{
get { return CloseBlock; }
}
public override string ToString()
{
return GrammarSegment == GrammarSegment.CommentOpen ? "<!--" : "-->";
}
}
}

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

@ -1,23 +0,0 @@

using System.Globalization;
namespace Svg.ExCSS.Model.TextBlocks
{
internal class DelimiterBlock : CharacterBlock
{
internal DelimiterBlock()
{
GrammarSegment = GrammarSegment.Delimiter;
}
internal DelimiterBlock(char value) : base(value)
{
GrammarSegment = GrammarSegment.Delimiter;
}
public override string ToString()
{
return Value.ToString(CultureInfo.InvariantCulture);
}
}
}

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

@ -1,39 +0,0 @@

namespace Svg.ExCSS.Model.TextBlocks
{
internal class MatchBlock : Block
{
internal readonly static MatchBlock Include = new MatchBlock { GrammarSegment = GrammarSegment.IncludeMatch };
internal readonly static MatchBlock Dash = new MatchBlock { GrammarSegment = GrammarSegment.DashMatch };
internal readonly static Block Prefix = new MatchBlock { GrammarSegment = GrammarSegment.PrefixMatch };
internal readonly static Block Substring = new MatchBlock { GrammarSegment = GrammarSegment.SubstringMatch };
internal readonly static Block Suffix = new MatchBlock { GrammarSegment = GrammarSegment.SuffixMatch };
internal readonly static Block Not = new MatchBlock { GrammarSegment = GrammarSegment.NegationMatch };
public override string ToString()
{
switch (GrammarSegment)
{
case GrammarSegment.SubstringMatch:
return "*=";
case GrammarSegment.SuffixMatch:
return "$=";
case GrammarSegment.PrefixMatch:
return "^=";
case GrammarSegment.IncludeMatch:
return "~=";
case GrammarSegment.DashMatch:
return "|=";
case GrammarSegment.NegationMatch:
return "!=";
}
return string.Empty;
}
}
}

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

@ -1,26 +0,0 @@
using System;
using System.Globalization;
namespace Svg.ExCSS.Model.TextBlocks
{
internal class NumericBlock : Block
{
private readonly string _data;
internal NumericBlock(string number)
{
_data = number;
GrammarSegment = GrammarSegment.Number;
}
public Single Value
{
get { return Single.Parse(_data, CultureInfo.InvariantCulture); }
}
public override string ToString()
{
return _data;
}
}
}

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

@ -1,28 +0,0 @@

namespace Svg.ExCSS.Model.TextBlocks
{
internal class PipeBlock : Block
{
private readonly static PipeBlock TokenBlock;
static PipeBlock()
{
TokenBlock = new PipeBlock();
}
PipeBlock()
{
GrammarSegment = GrammarSegment.Column;
}
internal static PipeBlock Token
{
get { return TokenBlock; }
}
public override string ToString()
{
return "||";
}
}
}

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

@ -1,69 +0,0 @@
using System.Collections.Generic;
namespace Svg.ExCSS.Model.TextBlocks
{
internal class RangeBlock : Block
{
public RangeBlock()
{
GrammarSegment = GrammarSegment.Range;
}
internal bool IsEmpty
{
get { return SelectedRange == null || SelectedRange.Length == 0; }
}
internal string[] SelectedRange { get; private set; }
internal RangeBlock SetRange(string start, string end)
{
var startValue = int.Parse(start, System.Globalization.NumberStyles.HexNumber);
if (startValue > Specification.MaxPoint)
{
return this;
}
if (end == null)
{
SelectedRange = new[] { char.ConvertFromUtf32(startValue) };
}
else
{
var list = new List<string>();
var endValue = int.Parse(end, System.Globalization.NumberStyles.HexNumber);
if (endValue > Specification.MaxPoint)
{
endValue = Specification.MaxPoint;
}
for (; startValue <= endValue; startValue++)
{
list.Add(char.ConvertFromUtf32(startValue));
}
SelectedRange = list.ToArray();
}
return this;
}
public override string ToString()
{
if (IsEmpty)
{
return string.Empty;
}
if (SelectedRange.Length == 1)
{
return "#" + char.ConvertToUtf32(SelectedRange[0], 0).ToString("x");
}
return "#" + char.ConvertToUtf32(SelectedRange[0], 0).ToString("x") + "-#" +
char.ConvertToUtf32(SelectedRange[SelectedRange.Length - 1], 0).ToString("x");
}
}
}

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

@ -1,21 +0,0 @@

namespace Svg.ExCSS.Model.TextBlocks
{
internal class SpecialCharacter : CharacterBlock
{
internal static readonly SpecialCharacter Colon = new SpecialCharacter(Specification.Colon, GrammarSegment.Colon);
internal static readonly SpecialCharacter Comma = new SpecialCharacter(Specification.Comma, GrammarSegment.Comma);
internal static readonly SpecialCharacter Semicolon = new SpecialCharacter(Specification.Simicolon, GrammarSegment.Semicolon);
internal static readonly SpecialCharacter Whitespace = new SpecialCharacter(Specification.Space, GrammarSegment.Whitespace);
SpecialCharacter(char specialCharacter, GrammarSegment type) : base(specialCharacter)
{
GrammarSegment = type;
}
public override string ToString()
{
return Value.ToString();
}
}
}

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

@ -1,35 +0,0 @@

namespace Svg.ExCSS.Model.TextBlocks
{
internal class StringBlock : Block
{
StringBlock(GrammarSegment type)
{
GrammarSegment = type;
}
internal static StringBlock Plain(string data, bool bad = false)
{
return new StringBlock(GrammarSegment.String) { Value = data, IsBad = bad };
}
internal static StringBlock Url(string data, bool bad = false)
{
return new StringBlock(GrammarSegment.Url) { Value = data, IsBad = bad };
}
internal string Value { get; private set; }
internal bool IsBad { get; private set; }
public override string ToString()
{
if (GrammarSegment == GrammarSegment.Url)
{
return "url(" + Value + ")";
}
return "'" + Value + "'";
}
}
}

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

@ -1,47 +0,0 @@

namespace Svg.ExCSS.Model.TextBlocks
{
internal class SymbolBlock : Block
{
SymbolBlock(GrammarSegment type)
{
GrammarSegment = type;
}
internal static SymbolBlock Function(string name)
{
return new SymbolBlock(GrammarSegment.Function) { Value = name };
}
internal static SymbolBlock Ident(string identifier)
{
return new SymbolBlock(GrammarSegment.Ident) { Value = identifier };
}
internal static SymbolBlock At(string name)
{
return new SymbolBlock(GrammarSegment.AtRule) { Value = name };
}
internal static SymbolBlock Hash(string characters)
{
return new SymbolBlock(GrammarSegment.Hash) { Value = characters };
}
internal string Value { get; private set; }
public override string ToString()
{
switch (GrammarSegment)
{
case GrammarSegment.Hash:
return "#" + Value;
case GrammarSegment.AtRule:
return "@" + Value;
}
return Value;
}
}
}

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

@ -1,37 +0,0 @@
using System;
using System.Globalization;
namespace Svg.ExCSS.Model.TextBlocks
{
internal class UnitBlock : Block
{
private string _value;
UnitBlock(GrammarSegment type)
{
GrammarSegment = type;
}
internal Single Value
{
get { return Single.Parse(_value, CultureInfo.InvariantCulture); }
}
internal string Unit { get; private set; }
internal static UnitBlock Percentage(string value)
{
return new UnitBlock(GrammarSegment.Percentage) { _value = value, Unit = "%" };
}
internal static UnitBlock Dimension(string value, string dimension)
{
return new UnitBlock(GrammarSegment.Dimension) { _value = value, Unit = dimension };
}
public override string ToString()
{
return _value + Unit;
}
}
}

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

@ -1,33 +0,0 @@
using System.Collections.Generic;
using System.Text;
using Svg.ExCSS.Model;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class GenericFunction : Term
{
public string Name { get; set; }
public TermList Arguments { get; set; }
public GenericFunction(string name, List<Term> arguments)
{
this.Name = name;
var list = new TermList();
for (int n = 0; n < arguments.Count; n++)
{
list.AddTerm(arguments[n]);
if (n == arguments.Count - 1)
break;
list.AddSeparator(GrammarSegment.Comma);
}
this.Arguments = list;
}
public override string ToString()
{
return Name + "(" + Arguments + ")";
}
}
}

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

@ -1,252 +0,0 @@
using System;
using System.Runtime.InteropServices;
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class HtmlColor : Term, IEquatable<HtmlColor>
{
public byte A;
public byte R;
public byte G;
public byte B;
public HtmlColor(byte r, byte g, byte b)
{
A = 255;
R = r;
B = b;
G = g;
}
public HtmlColor(byte a, byte r, byte g, byte b)
{
A = a;
R = r;
B = b;
G = g;
}
public HtmlColor(Double a, byte r, byte g, byte b)
{
A = (byte)Math.Max(Math.Min(Math.Ceiling(255 * a), 255), 0);
R = r;
B = b;
G = g;
}
public static HtmlColor FromRgba(byte r, byte g, byte b, Single a)
{
return new HtmlColor(a, r, g, b);
}
public static HtmlColor FromRgba(byte r, byte g, byte b, Double a)
{
return new HtmlColor(a, r, g, b);
}
public static HtmlColor FromRgb(byte r, byte g, byte b)
{
return new HtmlColor(r, g, b);
}
public static HtmlColor FromHsl(Single h, Single s, Single l)
{
const Single third = 1f / 3f;
var m2 = l <= 0.5f ? (l * (s + 1f)) : (l + s - l * s);
var m1 = 2f * l - m2;
var r = (Byte)Math.Round(255 * HueToRgb(m1, m2, h + third));
var g = (Byte)Math.Round(255 * HueToRgb(m1, m2, h));
var b = (Byte)Math.Round(255 * HueToRgb(m1, m2, h - third));
return new HtmlColor(r, g, b);
}
public static HtmlColor FromHex(string color)
{
if (color.Length == 3)
{
var r = color[0].FromHex();
r += r * 16;
var g = color[1].FromHex();
g += g * 16;
var b = color[2].FromHex();
b += b * 16;
return new HtmlColor((byte)r, (byte)g, (byte)b);
}
if (color.Length == 6)
{
var r = 16 * color[0].FromHex();
var g = 16 * color[2].FromHex();
var b = 16 * color[4].FromHex();
r += color[1].FromHex();
g += color[3].FromHex();
b += color[5].FromHex();
return new HtmlColor((byte)r, (byte)g, (byte)b);
}
throw new ArgumentException("Invalid color code length: " + color, "color");
}
public static bool TryFromHex(string color, out HtmlColor htmlColor)
{
htmlColor = new HtmlColor(255, 0, 0, 0);
if (color.Length == 3)
{
if (!color[0].IsHex() || !color[1].IsHex() || !color[2].IsHex())
{
return false;
}
var r = color[0].FromHex();
r += r * 16;
var g = color[1].FromHex();
g += g * 16;
var b = color[2].FromHex();
b += b * 16;
htmlColor.R = (byte)r;
htmlColor.G = (byte)g;
htmlColor.B = (byte)b;
return true;
}
if (color.Length == 6)
{
if (!color[0].IsHex() || !color[1].IsHex() || !color[2].IsHex() ||
!color[3].IsHex() || !color[4].IsHex() || !color[5].IsHex())
{
return false;
}
var r = 16 * color[0].FromHex();
var g = 16 * color[2].FromHex();
var b = 16 * color[4].FromHex();
r += color[1].FromHex();
g += color[3].FromHex();
b += color[5].FromHex();
htmlColor.R = (byte)r;
htmlColor.G = (byte)g;
htmlColor.B = (byte)b;
return true;
}
return false;
}
public double Alpha
{
get { return A / 255.0; }
}
public static bool operator ==(HtmlColor a, HtmlColor b)
{
return a.GetHashCode() == b.GetHashCode();
}
public static bool operator !=(HtmlColor a, HtmlColor b)
{
return a.GetHashCode() != b.GetHashCode();
}
public override bool Equals(Object obj)
{
if (obj is HtmlColor)
{
return Equals((HtmlColor)obj);
}
return false;
}
public override int GetHashCode()
{
return unchecked(A + (R << 8) + (G << 16) + (B << 24));
}
public override string ToString()
{
return ToString(false);
}
public string ToString(bool friendlyFormat, int indentation = 0)
{
return ToCss().Indent(friendlyFormat, indentation);
}
public string ToString(bool forceLong, bool friendlyFormat, int indentation = 0)
{
return ToCss(forceLong).Indent(friendlyFormat, indentation);
}
/// <summary>
/// Return the shortest form possible
/// </summary>
string ToCss(bool forceLong = false)
{
if (A == 255 && !forceLong && ((R >> 4) == (R & 0x0F)) && ((G >> 4) == (G & 0x0F)) && ((B >> 4) == (B & 0x0F)))
return "#" + R.ToHexChar() + G.ToHexChar() + B.ToHexChar();
if (A == 255)
{
return "#" + R.ToHex() + G.ToHex() + B.ToHex();
//return "rgb(" + R + ", " + G + ", " + B + ")";
}
return "rgba(" + R + ", " + G + ", " + B + ", " + Alpha.ToString("0.##") + ")";
}
public bool Equals(HtmlColor other)
{
HtmlColor o = other as HtmlColor;
if (o == null)
return false;
return GetHashCode() == other.GetHashCode();
}
private static Single HueToRgb(Single m1, Single m2, Single h)
{
const Single sixth = 1f / 6f;
const Single third2 = 2f / 3f;
if (h < 0f)
{
h += 1f;
}
else if (h > 1f)
{
h -= 1f;
}
if (h < sixth)
{
return m1 + (m2 - m1) * h * 6f;
}
if (h < 0.5)
{
return m2;
}
if (h < third2)
{
return m1 + (m2 - m1) * (third2 - h) * 6f;
}
return m1;
}
}
}

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

@ -1,17 +0,0 @@
using System;
namespace Svg.ExCSS
{
public class InheritTerm : Term
{
internal InheritTerm()
{
}
public override string ToString()
{
return "inherit";
}
}
}

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

@ -1,169 +0,0 @@
using System;
using System.Globalization;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class PrimitiveTerm : Term
{
public object Value { get; set; }
public UnitType PrimitiveType { get; set; }
public PrimitiveTerm(UnitType unitType, string value)
{
PrimitiveType = unitType;
Value = value;
}
public PrimitiveTerm(UnitType unitType, Single value)
{
PrimitiveType = unitType;
Value = value;
}
public PrimitiveTerm(string unit, Single value)
{
PrimitiveType = ConvertStringToUnitType(unit); ;
Value = value;
}
public Single? GetFloatValue(UnitType unit)
{
if (!(Value is Single))
{
return null;
}
var quantity = (Single)Value;
switch (unit)
{
case UnitType.Percentage:
quantity = quantity / 100f;
break;
}
return quantity;
}
public override string ToString()
{
switch (PrimitiveType)
{
case UnitType.String:
return "'" + Value + "'";
case UnitType.Uri:
return "url(" + Value + ")";
default:
if (Value is Single)
return ((Single)Value).ToString(CultureInfo.InvariantCulture) + ConvertUnitTypeToString(PrimitiveType);
return Value.ToString();
}
}
internal static UnitType ConvertStringToUnitType(string unit)
{
switch (unit)
{
case "%":
return UnitType.Percentage;
case "em":
return UnitType.Ems;
case "cm":
return UnitType.Centimeter;
case "deg":
return UnitType.Degree;
case "grad":
return UnitType.Grad;
case "rad":
return UnitType.Radian;
case "turn":
return UnitType.Turn;
case "ex":
return UnitType.Exs;
case "hz":
return UnitType.Hertz;
case "in":
return UnitType.Inch;
case "khz":
return UnitType.KiloHertz;
case "mm":
return UnitType.Millimeter;
case "ms":
return UnitType.Millisecond;
case "s":
return UnitType.Second;
case "pc":
return UnitType.Percent;
case "pt":
return UnitType.Point;
case "px":
return UnitType.Pixel;
case "vw":
return UnitType.ViewportWidth;
case "vh":
return UnitType.ViewportHeight;
case "vmin":
return UnitType.ViewportMin;
case "vmax":
return UnitType.ViewportMax;
}
return UnitType.Unknown;
}
internal static string ConvertUnitTypeToString(UnitType unit)
{
switch (unit)
{
case UnitType.Percentage:
return "%";
case UnitType.Ems:
return "em";
case UnitType.Centimeter:
return "cm";
case UnitType.Degree:
return "deg";
case UnitType.Grad:
return "grad";
case UnitType.Radian:
return "rad";
case UnitType.Turn:
return "turn";
case UnitType.Exs:
return "ex";
case UnitType.Hertz:
return "hz";
case UnitType.Inch:
return "in";
case UnitType.KiloHertz:
return "khz";
case UnitType.Millimeter:
return "mm";
case UnitType.Millisecond:
return "ms";
case UnitType.Second:
return "s";
case UnitType.Percent:
return "pc";
case UnitType.Point:
return "pt";
case UnitType.Pixel:
return "px";
case UnitType.ViewportWidth:
return "vw";
case UnitType.ViewportHeight:
return "vh";
case UnitType.ViewportMin:
return "vmin";
case UnitType.ViewportMax:
return "vmax";
}
return string.Empty;
}
}
}

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

@ -1,47 +0,0 @@
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class Property
{
private Term _term;
private bool _important;
public Property(string name)
{
Name = name;
}
public string Name { get; private set; }
public Term Term
{
get { return _term; }
set { _term = value; }
}
public bool Important
{
get { return _important; }
set { _important = value; }
}
public override string ToString()
{
return ToString(false);
}
public string ToString(bool friendlyFormat, int indentation = 0)
{
var value = Name + ":" + _term;
if (_important)
{
value += " !important";
}
return value.Indent(friendlyFormat, indentation);
}
}
}

9
Source/External/ExCSS/Model/Values/Term.cs поставляемый
Просмотреть файл

@ -1,9 +0,0 @@

// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public abstract class Term
{
public static readonly InheritTerm Inherit = new InheritTerm();
}
}

131
Source/External/ExCSS/Model/Values/TermList.cs поставляемый
Просмотреть файл

@ -1,131 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public class TermList : Term
{
private readonly List<GrammarSegment> _separator = new List<GrammarSegment>();
private readonly List<Term> _items = new List<Term>();
private const GrammarSegment DefaultSeparator = GrammarSegment.Comma;
public TermList()
{
}
public TermList(params Term[] terms)
{
for (var i = 0; i < terms.Length; ++i)
{
AddTerm(terms[i]);
if (i != terms.Length - 1)
{
AddSeparator(DefaultSeparator);
}
}
}
public void AddTerm(Term term)
{
if (_items.Count != _separator.Count)
{
throw new NotSupportedException("Must call AddTerm AddSeparator in that order");
}
_items.Add(term);
}
public void AddSeparator(TermSeparator termSeparator)
{
switch (termSeparator)
{
case (TermSeparator.Comma):
{
AddSeparator(GrammarSegment.Comma);
break;
}
case (TermSeparator.Space):
{
AddSeparator(GrammarSegment.Whitespace);
break;
}
}
}
internal void AddSeparator(GrammarSegment termSeparator)
{
if (_items.Count != _separator.Count + 1)
{
throw new NotSupportedException("Must call AddTerm AddSeparator in that order");
}
_separator.Add(termSeparator);
}
public int Length
{
get { return _items.Count; }
}
[IndexerName("ListItems")]
public Term this[int index]
{
//return index >= 0 && index < _items.Count ? _items[index] : null;
get { return _items[index]; }
}
public Term Item(int index)
{
return this[index];
}
public override string ToString()
{
var builder = new StringBuilder();
for (var i = 0; i < _items.Count; i++)
{
builder.Append(_items[i]);
if (i == _separator.Count)
break;
switch (_separator[i])
{
case GrammarSegment.Whitespace:
builder.Append(" ");
break;
case GrammarSegment.Comma:
builder.Append(",");
break;
default:
throw new NotImplementedException();
}
}
return builder.ToString();
}
/// <summary>
/// exposed enumeration for the adding of separators into term lists
/// </summary>
public enum TermSeparator
{
Comma,
Space
}
internal void SetLastTerm(Term term)
{
if (Length == 0)
AddTerm(term);
else
_items[Length - 1] = term;
}
}
}

859
Source/External/ExCSS/Parser.Blocks.cs поставляемый
Просмотреть файл

@ -1,859 +0,0 @@
using System;
using System.Text;
using System.Collections.Generic;
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.TextBlocks;
namespace Svg.ExCSS
{
public partial class Parser
{
private bool ParseTokenBlock(Block token)
{
switch (_parsingContext)
{
case ParsingContext.DataBlock:
return ParseSymbol(token);
case ParsingContext.InSelector:
return ParseSelector(token);
case ParsingContext.InDeclaration:
return ParseDeclaration(token);
case ParsingContext.AfterProperty:
return ParsePostProperty(token);
case ParsingContext.BeforeValue:
return ParseValue(token);
case ParsingContext.InValuePool:
return ParseValuePool(token);
case ParsingContext.InValueList:
return ParseValueList(token);
case ParsingContext.InSingleValue:
return ParseSingleValue(token);
case ParsingContext.ValueImportant:
return ParseImportant(token);
case ParsingContext.AfterValue:
return ParsePostValue(token);
case ParsingContext.InMediaList:
return ParseMediaList(token);
case ParsingContext.InMediaValue:
return ParseMediaValue(token);
case ParsingContext.BeforeImport:
return ParseImport(token);
case ParsingContext.AfterInstruction:
return ParsePostInstruction(token);
case ParsingContext.BeforeCharset:
return ParseCharacterSet(token);
case ParsingContext.BeforeNamespacePrefix:
return ParseLeadingPrefix(token);
case ParsingContext.AfterNamespacePrefix:
return ParseNamespace(token);
case ParsingContext.InCondition:
return ParseCondition(token);
case ParsingContext.InUnknown:
return ParseUnknown(token);
case ParsingContext.InKeyframeText:
return ParseKeyframeText(token);
case ParsingContext.BeforePageSelector:
return ParsePageSelector(token);
case ParsingContext.BeforeDocumentFunction:
return ParsePreDocumentFunction(token);
case ParsingContext.InDocumentFunction:
return ParseDocumentFunction(token);
case ParsingContext.AfterDocumentFunction:
return ParsePostDocumentFunction(token);
case ParsingContext.BetweenDocumentFunctions:
return ParseDocumentFunctions(token);
case ParsingContext.BeforeKeyframesName:
return ParseKeyframesName(token);
case ParsingContext.BeforeKeyframesData:
return ParsePreKeyframesData(token);
case ParsingContext.KeyframesData:
return ParseKeyframesData(token);
case ParsingContext.BeforeFontFace:
return ParseFontface(token);
case ParsingContext.InHexValue:
return ParseHexValue(token);
case ParsingContext.InFunction:
return ParseValueFunction(token);
default:
return false;
}
}
private bool ParseSymbol(Block token)
{
if (token.GrammarSegment == GrammarSegment.AtRule)
{
switch (((SymbolBlock)token).Value)
{
case RuleTypes.Media:
{
AddRuleSet(new MediaRule());
SetParsingContext(ParsingContext.InMediaList);
break;
}
case RuleTypes.Page:
{
AddRuleSet(new PageRule());
//SetParsingContext(ParsingContext.InSelector);
SetParsingContext(ParsingContext.BeforePageSelector);
break;
}
case RuleTypes.Import:
{
AddRuleSet(new ImportRule());
SetParsingContext(ParsingContext.BeforeImport);
break;
}
case RuleTypes.FontFace:
{
AddRuleSet(new FontFaceRule());
//SetParsingContext(ParsingContext.InDeclaration);
SetParsingContext(ParsingContext.BeforeFontFace);
break;
}
case RuleTypes.CharacterSet:
{
AddRuleSet(new CharacterSetRule());
SetParsingContext(ParsingContext.BeforeCharset);
break;
}
case RuleTypes.Namespace:
{
AddRuleSet(new NamespaceRule());
SetParsingContext(ParsingContext.BeforeNamespacePrefix);
break;
}
case RuleTypes.Supports:
{
_buffer = new StringBuilder();
AddRuleSet(new SupportsRule());
SetParsingContext(ParsingContext.InCondition);
break;
}
case RuleTypes.Keyframes:
{
AddRuleSet(new KeyframesRule());
SetParsingContext(ParsingContext.BeforeKeyframesName);
break;
}
case RuleTypes.Document:
{
AddRuleSet(new DocumentRule());
SetParsingContext(ParsingContext.BeforeDocumentFunction);
break;
}
default:
{
_buffer = new StringBuilder();
AddRuleSet(new GenericRule());
SetParsingContext(ParsingContext.InUnknown);
ParseUnknown(token);
break;
}
}
return true;
}
if (token.GrammarSegment == GrammarSegment.CurlyBracketClose)
{
return FinalizeRule();
}
AddRuleSet(new StyleRule());
SetParsingContext(ParsingContext.InSelector);
ParseSelector(token);
return true;
}
private bool ParseUnknown(Block token)
{
switch (token.GrammarSegment)
{
case GrammarSegment.Semicolon:
CastRuleSet<GenericRule>().SetInstruction(_buffer.ToString());
SetParsingContext(ParsingContext.DataBlock);
return FinalizeRule();
case GrammarSegment.CurlyBraceOpen:
CastRuleSet<GenericRule>().SetCondition(_buffer.ToString());
SetParsingContext(ParsingContext.DataBlock);
break;
default:
_buffer.Append(token);
break;
}
return true;
}
private bool ParseSelector(Block token)
{
switch (token.GrammarSegment)
{
case GrammarSegment.CurlyBraceOpen:
{
var rule = CurrentRule as ISupportsSelector;
if (rule != null)
{
rule.Selector = _selectorFactory.GetSelector();
}
SetParsingContext(CurrentRule is StyleRule
? ParsingContext.InDeclaration
: ParsingContext.DataBlock);
}
break;
case GrammarSegment.CurlyBracketClose:
return false;
default:
_selectorFactory.Apply(token);
break;
}
return true;
}
private bool ParseDeclaration(Block token)
{
if (token.GrammarSegment == GrammarSegment.CurlyBracketClose)
{
FinalizeProperty();
SetParsingContext(CurrentRule is KeyframeRule ? ParsingContext.KeyframesData : ParsingContext.DataBlock);
return FinalizeRule();
}
if (token.GrammarSegment != GrammarSegment.Ident)
{
return false;
}
AddProperty(new Property(((SymbolBlock)token).Value));
SetParsingContext(ParsingContext.AfterProperty);
return true;
}
private bool ParsePostInstruction(Block token)
{
if (token.GrammarSegment != GrammarSegment.Semicolon)
{
return false;
}
SetParsingContext(ParsingContext.DataBlock);
return FinalizeRule();
}
private bool ParseCondition(Block token)
{
switch (token.GrammarSegment)
{
case GrammarSegment.CurlyBraceOpen:
CastRuleSet<SupportsRule>().Condition = _buffer.ToString();
SetParsingContext(ParsingContext.DataBlock);
break;
default:
_buffer.Append(token);
break;
}
return true;
}
private bool ParseLeadingPrefix(Block token)
{
if (token.GrammarSegment == GrammarSegment.Ident)
{
CastRuleSet<NamespaceRule>().Prefix = ((SymbolBlock)token).Value;
SetParsingContext(ParsingContext.AfterNamespacePrefix);
return true;
}
if (token.GrammarSegment == GrammarSegment.String || token.GrammarSegment == GrammarSegment.Url)
{
CastRuleSet<NamespaceRule>().Uri = ((StringBlock)token).Value;
return true;
}
SetParsingContext(ParsingContext.AfterInstruction);
return ParsePostInstruction(token);
}
private bool ParsePostProperty(Block token)
{
if (token.GrammarSegment == GrammarSegment.Colon)
{
_isFraction = false;
SetParsingContext(ParsingContext.BeforeValue);
return true;
}
if (token.GrammarSegment == GrammarSegment.Semicolon || token.GrammarSegment == GrammarSegment.CurlyBracketClose)
{
ParsePostValue(token);
}
return false;
}
private bool ParseValue(Block token)
{
switch (token.GrammarSegment)
{
case GrammarSegment.Semicolon:
// the value is empty - remove the property to use the default value
RemoveCurrentProperty();
SetParsingContext(ParsingContext.InDeclaration);
return true;
case GrammarSegment.CurlyBracketClose:
ParseDeclaration(token);
break;
default:
SetParsingContext(ParsingContext.InSingleValue);
return ParseSingleValue(token);
}
return false;
}
private bool ParseSingleValue(Block token)
{
switch (token.GrammarSegment)
{
case GrammarSegment.Dimension: // "3px"
return AddTerm(new PrimitiveTerm(((UnitBlock)token).Unit, ((UnitBlock)token).Value));
case GrammarSegment.Hash:// "#ffffff"
return ParseSingleValueHexColor(((SymbolBlock)token).Value);
case GrammarSegment.Delimiter: // "#"
return ParseValueDelimiter((DelimiterBlock)token);
case GrammarSegment.Ident: // "auto"
return ParseSingleValueIdent((SymbolBlock)token);
case GrammarSegment.String:// "'some value'"
return AddTerm(new PrimitiveTerm(UnitType.String, ((StringBlock)token).Value));
case GrammarSegment.Url:// "url('http://....')"
return AddTerm(new PrimitiveTerm(UnitType.Uri, ((StringBlock)token).Value));
case GrammarSegment.Percentage: // "10%"
return AddTerm(new PrimitiveTerm(UnitType.Percentage, ((UnitBlock)token).Value));
case GrammarSegment.Number: // "123"
return AddTerm(new PrimitiveTerm(UnitType.Number, ((NumericBlock)token).Value));
case GrammarSegment.Whitespace: // " "
_terms.AddSeparator(GrammarSegment.Whitespace);
SetParsingContext(ParsingContext.InValueList);
return true;
case GrammarSegment.Function: // rgba(...)
_functionBuffers.Push(new FunctionBuffer(((SymbolBlock)token).Value));
SetParsingContext(ParsingContext.InFunction);
return true;
case GrammarSegment.Comma: // ","
_terms.AddSeparator(GrammarSegment.Comma);
SetParsingContext(ParsingContext.InValuePool);
return true;
case GrammarSegment.Semicolon: // ";"
case GrammarSegment.CurlyBracketClose: // "}"
return ParsePostValue(token);
default:
return false;
}
}
private bool ParseValueFunction(Block token)
{
switch (token.GrammarSegment)
{
case GrammarSegment.ParenClose:
SetParsingContext(ParsingContext.InSingleValue);
return AddTerm(_functionBuffers.Pop().Done());
case GrammarSegment.Comma:
_functionBuffers.Peek().Include();
return true;
default:
return ParseSingleValue(token);
}
}
private bool ParseValueList(Block token)
{
switch (token.GrammarSegment)
{
case GrammarSegment.CurlyBracketClose:
case GrammarSegment.Semicolon:
ParsePostValue(token);
break;
case GrammarSegment.Comma:
SetParsingContext(ParsingContext.InValuePool);
break;
default:
SetParsingContext(ParsingContext.InSingleValue);
return ParseSingleValue(token);
}
return true;
}
private bool ParseValuePool(Block token)
{
if (token.GrammarSegment == GrammarSegment.Semicolon || token.GrammarSegment == GrammarSegment.CurlyBracketClose)
{
ParsePostValue(token);
}
else
{
SetParsingContext(ParsingContext.InSingleValue);
return ParseSingleValue(token);
}
return false;
}
private bool ParseHexValue(Block token)
{
switch (token.GrammarSegment)
{
case GrammarSegment.Number:
case GrammarSegment.Dimension:
case GrammarSegment.Ident:
var rest = token.ToString();
if (_buffer.Length + rest.Length <= 6)
{
_buffer.Append(rest);
return true;
}
break;
}
SetParsingContext(ParsingContext.InSingleValue);
ParseSingleValueHexColor(_buffer.ToString());
return ParseSingleValue(token);
}
private bool ParsePostValue(Block token)
{
if (token.GrammarSegment == GrammarSegment.Semicolon)
{
FinalizeProperty();
SetParsingContext(ParsingContext.InDeclaration);
return true;
}
if (token.GrammarSegment == GrammarSegment.CurlyBracketClose)
{
return ParseDeclaration(token);
}
return false;
}
private bool ParseImportant(Block token)
{
if (token.GrammarSegment != GrammarSegment.Ident || ((SymbolBlock)token).Value != "important")
{
return ParsePostValue(token);
}
SetParsingContext(ParsingContext.AfterValue);
_property.Important = true;
return true;
}
private bool ParseValueDelimiter(DelimiterBlock token)
{
switch (token.Value)
{
case Specification.Em:
SetParsingContext(ParsingContext.ValueImportant);
return true;
case Specification.Hash:
_buffer = new StringBuilder();
SetParsingContext(ParsingContext.InHexValue);
return true;
case Specification.Solidus:
_isFraction = true;
return true;
default:
return false;
}
}
private bool ParseSingleValueIdent(SymbolBlock token)
{
if (token.Value != "inherit")
{
return AddTerm(new PrimitiveTerm(UnitType.Ident, token.Value));
}
_terms.AddTerm(Term.Inherit);
SetParsingContext(ParsingContext.AfterValue);
return true;
}
private bool ParseSingleValueHexColor(string color)
{
HtmlColor htmlColor;
if (HtmlColor.TryFromHex(color, out htmlColor))
return AddTerm(htmlColor);
else
// the value is invalid - remove the property to use the default value
RemoveCurrentProperty();
return true;
}
#region Namespace
private bool ParseNamespace(Block token)
{
SetParsingContext(ParsingContext.AfterInstruction);
if (token.GrammarSegment != GrammarSegment.String)
{
return ParsePostInstruction(token);
}
CastRuleSet<NamespaceRule>().Uri = ((StringBlock)token).Value;
return true;
}
#endregion
#region Charset
private bool ParseCharacterSet(Block token)
{
SetParsingContext(ParsingContext.AfterInstruction);
if (token.GrammarSegment != GrammarSegment.String)
{
return ParsePostInstruction(token);
}
CastRuleSet<CharacterSetRule>().Encoding = ((StringBlock)token).Value;
return true;
}
#endregion
#region Import
private bool ParseImport(Block token)
{
if (token.GrammarSegment == GrammarSegment.String || token.GrammarSegment == GrammarSegment.Url)
{
CastRuleSet<ImportRule>().Href = ((StringBlock)token).Value;
SetParsingContext(ParsingContext.InMediaList);
return true;
}
SetParsingContext(ParsingContext.AfterInstruction);
return false;
}
#endregion
#region Font Face
private bool ParseFontface(Block token)
{
if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen)
{
SetParsingContext(ParsingContext.InDeclaration);
return true;
}
return false;
}
#endregion
#region Keyframes
private bool ParseKeyframesName(Block token)
{
//SetParsingContext(ParsingContext.BeforeKeyframesData);
if (token.GrammarSegment == GrammarSegment.Ident)
{
CastRuleSet<KeyframesRule>().Identifier = ((SymbolBlock)token).Value;
return true;
}
if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen)
{
SetParsingContext(ParsingContext.KeyframesData);
return true;
}
return false;
}
private bool ParsePreKeyframesData(Block token)
{
if (token.GrammarSegment != GrammarSegment.CurlyBraceOpen)
{
return false;
}
SetParsingContext(ParsingContext.BeforeKeyframesData);
return true;
}
private bool ParseKeyframesData(Block token)
{
if (token.GrammarSegment == GrammarSegment.CurlyBracketClose)
{
SetParsingContext(ParsingContext.DataBlock);
return FinalizeRule();
}
_buffer = new StringBuilder();
return ParseKeyframeText(token);
}
private bool ParseKeyframeText(Block token)
{
if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen)
{
SetParsingContext(ParsingContext.InDeclaration);
return true;
}
if (token.GrammarSegment == GrammarSegment.CurlyBracketClose)
{
ParseKeyframesData(token);
return false;
}
var frame = new KeyframeRule
{
Value = token.ToString()
};
CastRuleSet<KeyframesRule>().Declarations.Add(frame);
_activeRuleSets.Push(frame);
return true;
}
#endregion
#region Page
private bool ParsePageSelector(Block token)
{
if (token.GrammarSegment == GrammarSegment.Colon || token.GrammarSegment == GrammarSegment.Whitespace)
{
return true;
}
if (token.GrammarSegment == GrammarSegment.Ident)
{
CastRuleSet<PageRule>().Selector = new SimpleSelector(token.ToString());
return true;
}
if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen)
{
SetParsingContext(ParsingContext.InDeclaration);
return true;
}
return false;
}
#endregion
#region Document
private bool ParsePreDocumentFunction(Block token)
{
switch (token.GrammarSegment)
{
case GrammarSegment.Url:
CastRuleSet<DocumentRule>().Conditions.Add(new KeyValuePair<DocumentFunction, string>(DocumentFunction.Url, ((StringBlock)token).Value));
break;
case GrammarSegment.UrlPrefix:
CastRuleSet<DocumentRule>().Conditions.Add(new KeyValuePair<DocumentFunction, string>(DocumentFunction.UrlPrefix, ((StringBlock)token).Value));
break;
case GrammarSegment.Domain:
CastRuleSet<DocumentRule>().Conditions.Add(new KeyValuePair<DocumentFunction, string>(DocumentFunction.Domain, ((StringBlock)token).Value));
break;
case GrammarSegment.Function:
if (string.Compare(((SymbolBlock)token).Value, "regexp", StringComparison.OrdinalIgnoreCase) == 0)
{
SetParsingContext(ParsingContext.InDocumentFunction);
return true;
}
SetParsingContext(ParsingContext.AfterDocumentFunction);
return false;
default:
SetParsingContext(ParsingContext.DataBlock);
return false;
}
SetParsingContext(ParsingContext.BetweenDocumentFunctions);
return true;
}
private bool ParseDocumentFunction(Block token)
{
SetParsingContext(ParsingContext.AfterDocumentFunction);
if (token.GrammarSegment != GrammarSegment.String) return false;
CastRuleSet<DocumentRule>().Conditions.Add(new KeyValuePair<DocumentFunction, string>(DocumentFunction.RegExp, ((StringBlock)token).Value));
return true;
}
private bool ParsePostDocumentFunction(Block token)
{
SetParsingContext(ParsingContext.BetweenDocumentFunctions);
return token.GrammarSegment == GrammarSegment.ParenClose;
}
private bool ParseDocumentFunctions(Block token)
{
if (token.GrammarSegment == GrammarSegment.Comma)
{
SetParsingContext(ParsingContext.BeforeDocumentFunction);
return true;
}
if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen)
{
SetParsingContext(ParsingContext.DataBlock);
return true;
}
SetParsingContext(ParsingContext.DataBlock);
return false;
}
#endregion
#region Media
private bool ParseMediaList(Block token)
{
if (token.GrammarSegment == GrammarSegment.Semicolon)
{
FinalizeRule();
SetParsingContext(ParsingContext.DataBlock);
return true;
}
_buffer = new StringBuilder();
SetParsingContext(ParsingContext.InMediaValue);
return ParseMediaValue(token);
}
private bool ParseMediaValue(Block token)
{
switch (token.GrammarSegment)
{
case GrammarSegment.CurlyBraceOpen:
case GrammarSegment.Semicolon:
{
var container = CurrentRule as ISupportsMedia;
var medium = _buffer.ToString();
if (container != null)
{
container.Media.AppendMedium(medium);
}
if (CurrentRule is ImportRule)
{
return ParsePostInstruction(token);
}
SetParsingContext(ParsingContext.DataBlock);
return token.GrammarSegment == GrammarSegment.CurlyBraceOpen;
}
case GrammarSegment.Comma:
{
var container = CurrentRule as ISupportsMedia;
if (container != null)
{
container.Media.AppendMedium(_buffer.ToString());
}
_buffer.Length = 0;
return true;
}
case GrammarSegment.Whitespace:
{
_buffer.Append(' ');
return true;
}
default:
{
_buffer.Append(token);
return true;
}
}
}
#endregion
}
}

292
Source/External/ExCSS/Parser.cs поставляемый
Просмотреть файл

@ -1,292 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Svg.ExCSS.Model;
using Svg.ExCSS.Model.TextBlocks;
// ReSharper disable once CheckNamespace
using System;
//The MIT License (MIT)
//Copyright (c) [year] [fullname]
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
namespace Svg.ExCSS
{
internal delegate void ParseErrorEventHandler(StylesheetParseError e);
public sealed partial class Parser
{
private SelectorFactory _selectorFactory;
private Stack<FunctionBuffer> _functionBuffers;
private Lexer _lexer;
private bool _isFraction;
private Property _property;
private TermList _terms = new TermList();
private StyleSheet _styleSheet;
private Stack<RuleSet> _activeRuleSets;
private StringBuilder _buffer;
private ParsingContext _parsingContext;
public StyleSheet Parse(string css)
{
_selectorFactory = new SelectorFactory();
_functionBuffers = new Stack<FunctionBuffer>();
_styleSheet = new StyleSheet();
_activeRuleSets = new Stack<RuleSet>();
_lexer = new Lexer(new StylesheetReader(css)) { ErrorHandler = HandleLexerError };
SetParsingContext(ParsingContext.DataBlock);
var tokens = _lexer.Tokens;
foreach (var token in tokens)
{
if (ParseTokenBlock(token))
{
continue;
}
HandleLexerError(ParserError.UnexpectedLineBreak, ErrorMessages.Default);
}
if (_property != null)
{
ParseTokenBlock(SpecialCharacter.Semicolon);
}
return _styleSheet;
}
internal static BaseSelector ParseSelector(string selector)
{
var tokenizer = new Lexer(new StylesheetReader(selector));
var tokens = tokenizer.Tokens;
var selctor = new SelectorFactory();
foreach (var token in tokens)
{
selctor.Apply(token);
}
var result = selctor.GetSelector();
return result;
}
internal static RuleSet ParseRule(string css)
{
var parser = new Parser();
var styleSheet = parser.Parse(css);
return styleSheet.Rules.Count > 0
? styleSheet.Rules[0]
: null;
}
internal static StyleDeclaration ParseDeclarations(string declarations, bool quirksMode = false)
{
var decl = new StyleDeclaration();
AppendDeclarations(decl, declarations, quirksMode);
return decl;
}
internal static void AppendDeclarations(StyleDeclaration list, string css, bool quirksMode = false)
{
var parser = new Parser();//(new StyleSheet(), new StylesheetReader(declarations))
parser.AddRuleSet(list.ParentRule ?? new StyleRule(list));
parser._parsingContext = ParsingContext.InDeclaration;
parser.Parse(css);
}
internal void HandleLexerError(ParserError error, string message)
{
_styleSheet.Errors.Add(new StylesheetParseError(error, message, _lexer.Stream.Line, _lexer.Stream.Column));
}
private bool AddTerm(Term value)
{
var added = true;
if (_isFraction)
{
if (_terms.Length > 0)
{
value = new PrimitiveTerm(UnitType.Unknown, _terms[_terms.Length - 1] + "/" + value);
}
_terms.SetLastTerm(value);
_isFraction = false;
}
else if (_functionBuffers.Count > 0)
{
_functionBuffers.Peek().TermList.Add(value);
}
else if (_terms.Length == 0)
{
_terms.AddTerm(value);
}
else if (_parsingContext == ParsingContext.InSingleValue)
{
_terms.AddTerm(value);
}
else
{
added = false;
}
return added;
}
private void FinalizeProperty()
{
if (_property != null)
{
if (_terms.Length > 1)
{
_property.Term = _terms;
}
else if (_terms.Length == 0)
{
RemoveCurrentProperty();
}
else
{
_property.Term = _terms[0];
}
}
_terms = new TermList();
_property = null;
}
private bool FinalizeRule()
{
if (_activeRuleSets.Count <= 0)
{
return false;
}
_activeRuleSets.Pop();
return true;
}
private void AddRuleSet(RuleSet rule)
{
//rule.ParentStyleSheet = _styleSheet;
if (_activeRuleSets.Count > 0)
{
var container = _activeRuleSets.Peek() as ISupportsRuleSets;
if (container != null)
{
container.RuleSets.Add(rule);
}
}
else
{
_styleSheet.Rules.Add(rule);
}
_activeRuleSets.Push(rule);
}
private void AddProperty(Property property)
{
_property = property;
var rule = CurrentRule as ISupportsDeclarations;
if (rule != null)
{
rule.Declarations.Add(property);
}
}
private void RemoveCurrentProperty()
{
if (_property != null)
{
var rule = CurrentRule as ISupportsDeclarations;
if (rule != null)
{
rule.Declarations.Remove(_property);
}
_property = null;
}
}
private T CastRuleSet<T>() where T : RuleSet
{
if (_activeRuleSets.Count > 0)
{
return _activeRuleSets.Peek() as T;
}
return default(T);
}
private void SetParsingContext(ParsingContext newState)
{
switch (newState)
{
case ParsingContext.InSelector:
_lexer.IgnoreComments = true;
_lexer.IgnoreWhitespace = false;
_selectorFactory.ResetFactory();
break;
case ParsingContext.InHexValue:
case ParsingContext.InUnknown:
case ParsingContext.InCondition:
case ParsingContext.InSingleValue:
case ParsingContext.InMediaValue:
_lexer.IgnoreComments = true;
_lexer.IgnoreWhitespace = false;
break;
default:
_lexer.IgnoreComments = true;
_lexer.IgnoreWhitespace = true;
break;
}
_parsingContext = newState;
}
internal RuleSet CurrentRule
{
get
{
return _activeRuleSets.Count > 0
? _activeRuleSets.Peek()
: null;
}
}
}
}

2791
Source/External/ExCSS/Parser.generated.cs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

1425
Source/External/ExCSS/ParserX.cs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

146
Source/External/ExCSS/StyleSheet.cs поставляемый
Просмотреть файл

@ -1,146 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Svg.ExCSS.Model.Extensions;
// ReSharper disable once CheckNamespace
namespace Svg.ExCSS
{
public sealed class StyleSheet
{
private readonly List<RuleSet> _rules;
public StyleSheet()
{
_rules = new List<RuleSet>();
Errors = new List<StylesheetParseError>();
}
public List<RuleSet> Rules
{
get { return _rules; }
}
public StyleSheet RemoveRule(int index)
{
if (index >= 0 && index < _rules.Count)
{
_rules.RemoveAt(index);
}
return this;
}
public StyleSheet InsertRule(string rule, int index)
{
if (index < 0 || index > _rules.Count)
{
return this;
}
var value = Parser.ParseRule(rule);
_rules.Insert(index, value);
return this;
}
public IList<StyleRule> StyleRules
{
get
{
return Rules.Where(r => r is StyleRule).Cast<StyleRule>().ToList();
}
}
public IList<CharacterSetRule> CharsetDirectives
{
get
{
return GetDirectives<CharacterSetRule>(RuleType.Charset);
}
}
public IList<ImportRule> ImportDirectives
{
get
{
return GetDirectives<ImportRule>(RuleType.Import);
}
}
public IList<FontFaceRule> FontFaceDirectives
{
get
{
return GetDirectives<FontFaceRule>(RuleType.FontFace);
}
}
public IList<KeyframesRule> KeyframeDirectives
{
get
{
return GetDirectives<KeyframesRule>(RuleType.Keyframes);
}
}
public IList<MediaRule> MediaDirectives
{
get
{
return GetDirectives<MediaRule>(RuleType.Media);
}
}
public IList<PageRule> PageDirectives
{
get
{
return GetDirectives<PageRule>(RuleType.Page);
}
}
public IList<SupportsRule> SupportsDirectives
{
get
{
return GetDirectives<SupportsRule>(RuleType.Supports);
}
}
public IList<NamespaceRule> NamespaceDirectives
{
get
{
return GetDirectives<NamespaceRule>(RuleType.Namespace);
}
}
private IList<T> GetDirectives<T>(RuleType ruleType)
{
return Rules.Where(r => r.RuleType == ruleType).Cast<T>().ToList();
}
public List<StylesheetParseError> Errors { get; private set; }
public override string ToString()
{
return ToString(false);
}
public string ToString(bool friendlyFormat, int indentation = 0)
{
var builder = new StringBuilder();
foreach (var rule in _rules)
{
builder.Append(rule.ToString(friendlyFormat, indentation).TrimStart() + (friendlyFormat ? Environment.NewLine : ""));
}
return builder.TrimFirstLine().TrimLastLine().ToString();
}
}
}

27
Source/External/ExCSS/StylesheetParseError.cs поставляемый
Просмотреть файл

@ -1,27 +0,0 @@

namespace Svg.ExCSS
{
public sealed class StylesheetParseError
{
public StylesheetParseError(ParserError error, string errorMessage, int line, int column)
{
ParserError = error;
Message = errorMessage;
Line = line;
Column = column;
}
public ParserError ParserError { get; set; }
public int Line { get; set; }
public int Column { get; set; }
public string Message { get; private set; }
public override string ToString()
{
return string.Format("Line {0}, Column {1}: {2}.", Line, Column, Message);
}
}
}

186
Source/External/ExCSS/StylesheetReader.cs поставляемый
Просмотреть файл

@ -1,186 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using Svg.ExCSS.Model;
namespace Svg.ExCSS
{
internal class StylesheetReader
{
private int _insertion;
private readonly Stack<int> _collengths;
private TextReader _reader;
private readonly StringBuilder _buffer;
private bool _lineWithReturn;
StylesheetReader()
{
_buffer = new StringBuilder();
_collengths = new Stack<int>();
Column = 1;
Line = 1;
}
internal StylesheetReader(string styleText) : this()
{
_reader = new StringReader(styleText);
ReadCurrent();
}
internal StylesheetReader(Stream styleStream) : this()
{
_reader = new StreamReader(styleStream, true);
ReadCurrent();
}
internal bool IsBeginning
{
get { return _insertion < 2; }
}
internal int Line { get; private set; }
internal int Column { get; private set; }
internal bool IsEnded { get; private set; }
internal bool IsEnding
{
get { return Current == Specification.EndOfFile; }
}
internal char Current { get; private set; }
internal char Next
{
get
{
Advance();
return Current;
}
}
internal char Previous
{
get
{
Back();
return Current;
}
}
internal void Advance()
{
if (!IsEnding)
{
AdvanceUnsafe();
}
else if (!IsEnded)
{
IsEnded = true;
}
}
internal void Advance(int positions)
{
while (positions-- > 0 && !IsEnding)
{
AdvanceUnsafe();
}
}
internal void Back()
{
IsEnded = false;
if (!IsBeginning)
{
BackUnsafe();
}
}
internal void Back(int positions)
{
IsEnded = false;
while (positions-- > 0 && !IsBeginning)
{
BackUnsafe();
}
}
private void ReadCurrent()
{
if (_insertion < _buffer.Length)
{
Current = _buffer[_insertion];
_insertion++;
return;
}
var nextPosition = _reader.Read();
Current = nextPosition == -1 ? Specification.EndOfFile : (char)nextPosition;
if (Current == Specification.CarriageReturn)
{
Current = Specification.LineFeed;
_lineWithReturn = true;
}
else if (_lineWithReturn)
{
_lineWithReturn = false;
if (Current == Specification.LineFeed)
{
ReadCurrent();
return;
}
}
_buffer.Append(Current);
_insertion++;
}
private void AdvanceUnsafe()
{
if (Current.IsLineBreak())
{
_collengths.Push(Column);
Column = 1;
Line++;
}
else
{
Column++;
}
ReadCurrent();
}
private void BackUnsafe()
{
_insertion--;
if (_insertion == 0)
{
Column = 0;
Current = Specification.Null;
return;
}
Current = _buffer[_insertion - 1];
if (Current.IsLineBreak())
{
Column = _collengths.Count != 0 ? _collengths.Pop() : 1;
Line--;
}
else
{
Column--;
}
}
}
}

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

@ -114,10 +114,15 @@ namespace Svg
throw new SvgException("Colour is in an invalid format: '" + colour + "'");
}
}
else if (colour.StartsWith("#", StringComparison.InvariantCulture) && colour.Length == 4)
else if (colour.StartsWith("#", StringComparison.InvariantCulture))
{
colour = string.Format(culture, "#{0}{0}{1}{1}{2}{2}", colour[1], colour[2], colour[3]);
return base.ConvertFrom(context, culture, colour);
if (colour.Length == 4)
{
colour = string.Format(culture, "#{0}{0}{1}{1}{2}{2}", colour[1], colour[2], colour[3]);
return base.ConvertFrom(context, culture, colour);
}
else if (colour.Length != 7)
return SvgPaintServer.NotSet;
}
#if !NO_SDC

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

@ -123,13 +123,12 @@
</ItemGroup>
<ItemGroup>
<Compile Remove=".\External\ExCSS\Parser.generated.cs" />
<Compile Remove=".\External\ExCSS\ParserX.cs" />
<Compile Remove=".\Resources\svg11.dtd" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="ExCSS" Version="4.1.4" />
<PackageReference Include="Fizzler" Version="1.2.1" />
<PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37">
<PrivateAssets>all</PrivateAssets>

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

@ -7,11 +7,11 @@ using System.IO;
using System.Text;
using System.Xml;
using System.Linq;
using Svg.ExCSS;
using Svg.Css;
using System.Threading;
using System.Globalization;
using System.Runtime.InteropServices;
using ExCSS;
namespace Svg
{
@ -444,30 +444,26 @@ namespace Svg
if (styles.Any())
{
var cssTotal = string.Join(Environment.NewLine, styles.Select(s => s.Content).ToArray());
var cssParser = new Parser();
var sheet = cssParser.Parse(cssTotal ?? string.Empty);
var stylesheetParser = new StylesheetParser(true, true);
var stylesheet = stylesheetParser.Parse(cssTotal);
foreach (var rule in sheet.StyleRules)
{
foreach (var rule in stylesheet.StyleRules)
try
{
var rootNode = new NonSvgElement();
rootNode.Children.Add(svgDocument);
var elemsToStyle = rootNode.QuerySelectorAll(rule.Selector.ToString(), elementFactory);
var elemsToStyle = rootNode.QuerySelectorAll(rule.Selector.Text, elementFactory);
foreach (var elem in elemsToStyle)
{
foreach (var decl in rule.Declarations)
foreach (var declaration in rule.Style)
{
elem.AddStyle(decl.Name, decl.Term.ToString(), rule.Selector.GetSpecificity());
elem.AddStyle(declaration.Name, declaration.Value, rule.Selector.GetSpecificity());
}
}
}
catch (Exception ex)
{
Trace.TraceWarning(ex.Message);
}
}
}
svgDocument?.FlushStyles(true);

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

@ -5,7 +5,7 @@ using System.Xml;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using Svg.ExCSS;
using ExCSS;
namespace Svg
{
@ -52,7 +52,7 @@ namespace Svg
private static readonly Dictionary<string, ElementInfo> availableElementsWithoutSvg;
private static readonly List<ElementInfo> availableElements;
#endif
private readonly Parser cssParser = new Parser();
private readonly StylesheetParser stylesheetParser = new StylesheetParser(true, true);
/// <summary>
/// Gets a list of available types that can be used when creating an <see cref="SvgElement"/>.
@ -183,14 +183,10 @@ namespace Svg
}
if (localName.Equals("style") && !(element is NonSvgElement))
{
var inlineSheet = cssParser.Parse("#a{" + reader.Value + "}");
var inlineSheet = stylesheetParser.Parse("#a{" + reader.Value + "}");
foreach (var rule in inlineSheet.StyleRules)
{
foreach (var decl in rule.Declarations)
{
element.AddStyle(decl.Name, decl.Term.ToString(), SvgElement.StyleSpecificity_InlineStyle);
}
}
foreach (var declaration in rule.Style)
element.AddStyle(declaration.Name, declaration.Value, SvgElement.StyleSpecificity_InlineStyle);
}
else if (prefix.Length == 0 && IsStyleAttribute(localName))
{

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

@ -1,6 +1,8 @@
using System.Text;
using System.Linq;
using System.Text;
using Svg.Css;
using NUnit.Framework;
using ExCSS;
namespace Svg.UnitTests
{
@ -49,9 +51,9 @@ namespace Svg.UnitTests
private void TestSelectorSpecificity(string selector, int specificity)
{
var parser = new ExCSS.Parser();
var sheet = parser.Parse(selector + " {color:black}");
Assert.AreEqual(specificity, CssQuery.GetSpecificity(sheet.StyleRules[0].Selector));
var stylesheetParser = new StylesheetParser(true, true);
var stylesheet = stylesheetParser.Parse(selector + " {color:black}");
Assert.AreEqual(specificity, CssQuery.GetSpecificity(stylesheet.StyleRules.First().Selector));
}
/// <summary>
@ -78,7 +80,7 @@ namespace Svg.UnitTests
[TestCase("a[id=\"a-02\"]", 0x0110)]
[TestCase("ul#nav li.active a", 0x1130)]
[TestCase("body.ie7 .col_3 h2 ~ h2", 0x0230)]
[TestCase("#footer *:not(nav) li", 0x1020)]
[TestCase("#footer *:not(nav) li", 0x1110)]
[TestCase("ul > li ul li ol li:first-letter", 0x0070)]
public void RunSpecificityTests(string selector, int specifity)
{
@ -86,19 +88,19 @@ namespace Svg.UnitTests
}
[Test]
[TestCase("font-size:13;", "font-size:13;")]
[TestCase("font-size:13;font-style:normal;", "font-size:13;font-style:normal;")]
[TestCase("font-size:13;font-style:normal;font-weight:bold;", "font-size:13;font-style:normal;font-weight:bold;")]
[TestCase("font-family:Nimbus Sans L,'Arial Narrow',sans-serif;Sans L',sans-serif;", "font-family:Nimbus Sans L,'Arial Narrow',sans-serif;")]
[TestCase("font-size:13px;", "font-size:13px;")]
[TestCase("font-size:13px;font-style:normal;", "font-size:13px;font-style:normal;")]
[TestCase("font-size:13px;font-style:normal;font-weight:bold;", "font-size:13px;font-style:normal;font-weight:bold;")]
[TestCase("font-family:Nimbus Sans L,'Arial Narrow',sans-serif;Sans L',sans-serif;", "font-family:Nimbus Sans L, \"Arial Narrow\", sans-serif;")]
public void TestStyleDeclarations(string style, string expected)
{
var actual = new StringBuilder();
var cssParser = new ExCSS.Parser();
var inlineSheet = cssParser.Parse("#a{" + style + "}");
foreach (var rule in inlineSheet.StyleRules)
foreach (var decl in rule.Declarations)
actual.Append(decl.Name).Append(":").Append(decl.Term.ToString()).Append(";");
var stylesheetParser = new StylesheetParser(true, true);
var stylesheet = stylesheetParser.Parse("#a{" + style + "}");
foreach (var rule in stylesheet.StyleRules)
foreach (var declaration in rule.Style)
actual.Append(declaration.Name).Append(":").Append(declaration.Value).Append(";");
Assert.AreEqual(expected, actual.ToString());
}

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

@ -21,7 +21,7 @@ viewBox="0 0 210 297"
.str0 {stroke:#2B2A29;stroke-width:0.0762}
.fil1 {fill:#1F1A17}
.fil0 {fill:url(#id1)}
.fnt0 {font-weight:normal;font-size:8.4667;font-family:'Comic Sans MS'}
.fnt0 {font-weight:normal;font-family:'Comic Sans MS'}
]]>
</style>
<clipPath id="id0">

До

Ширина:  |  Высота:  |  Размер: 8.0 KiB

После

Ширина:  |  Высота:  |  Размер: 8.0 KiB

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

@ -12,6 +12,9 @@ The release versions are NuGet releases.
### Fixes
* fixed out of memory in Svg 3.4.2 (see [#989](https://github.com/svg-net/SVG/issues/989))
### Infrastructures
* the ExCSS library is now included via NuGet instead of copying the sources
## [Version 3.4.2](https://www.nuget.org/packages/Svg/3.4.2) (2022-04-11)
### Changes