зеркало из https://github.com/wieslawsoltes/SVG.git
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:
Родитель
aee2e93fa5
Коммит
8c9b1f2b6d
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
namespace Svg.ExCSS
|
||||
{
|
||||
public interface IToString
|
||||
{
|
||||
string ToString(bool friendlyFormat, int indentation = 0);
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Svg.ExCSS.Model
|
||||
{
|
||||
interface ISupportsRuleSets
|
||||
{
|
||||
List<RuleSet> RuleSets { get; }
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Svg.ExCSS
|
||||
{
|
||||
public abstract class Term
|
||||
{
|
||||
public static readonly InheritTerm Inherit = new InheritTerm();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче