Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/AngleSharp.Css/Converters/DictionaryValueConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public ICssValue Convert(StringSource source)

if (ident != null && _values.TryGetValue(ident, out mode))
{
return new CssConstantValue<T>(ident.ToLowerInvariant(), mode);
return new CssConstantValue<T>(ident.ToLowerFast(), mode);
}

source.BackTo(pos);
Expand Down
5 changes: 5 additions & 0 deletions src/AngleSharp.Css/Converters/PeriodicValueConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public ICssValue Convert(StringSource source)

if (length > 0)
{
if (length == 4)
{
return new CssPeriodicValue(options);
}

var values = new ICssValue[length];
Array.Copy(options, values, length);
return new CssPeriodicValue(values);
Expand Down
2 changes: 1 addition & 1 deletion src/AngleSharp.Css/Dom/Internal/CssProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal class CssProperty : ICssProperty

internal CssProperty(String name, IValueConverter converter, PropertyFlags flags = PropertyFlags.None, ICssValue value = null, Boolean important = false)
{
_name = name.StartsWith("--") ? name : name.ToLowerInvariant();
_name = name.StartsWith("--") ? name : name.ToLowerFast();
_converter = converter;
_flags = flags;
_value = value;
Expand Down
92 changes: 68 additions & 24 deletions src/AngleSharp.Css/Dom/Internal/CssStyleDeclaration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ sealed class CssStyleDeclaration : ICssStyleDeclaration
#region Fields

private readonly List<ICssProperty> _declarations;
private readonly Dictionary<String, Int32> _declarationIndex;
private readonly IBrowsingContext _context;
private ICssRule _parent;
private Boolean _updating;
Expand All @@ -36,6 +37,7 @@ sealed class CssStyleDeclaration : ICssStyleDeclaration
public CssStyleDeclaration(IBrowsingContext context)
{
_declarations = new List<ICssProperty>();
_declarationIndex = new Dictionary<String, Int32>(StringComparer.OrdinalIgnoreCase);
_context = context;
}

Expand Down Expand Up @@ -77,9 +79,9 @@ public String CssText

public ICssProperty GetProperty(String name)
{
for (var i = 0; i < _declarations.Count; i++)
if (_declarationIndex.TryGetValue(name, out var index) && index < _declarations.Count)
{
var declaration = _declarations[i];
var declaration = _declarations[index];

if (declaration.Name.Isi(name))
{
Expand All @@ -100,6 +102,7 @@ public void Update(String value)
if (!_updating)
{
_declarations.Clear();
_declarationIndex.Clear();

if (!String.IsNullOrEmpty(value))
{
Expand All @@ -109,6 +112,7 @@ public void Update(String value)
if (decl != null)
{
_declarations.AddRange(decl);
RebuildIndex();
}
}
}
Expand Down Expand Up @@ -304,12 +308,14 @@ public void SetProperty(String propertyName, String propertyValue, String priori

public void AddProperty(ICssProperty declaration)
{
_declarationIndex[declaration.Name] = _declarations.Count;
_declarations.Add(declaration);
}

public void RemoveProperty(ICssProperty declaration)
{
_declarations.Remove(declaration);
RebuildIndex();
}

#endregion
Expand Down Expand Up @@ -359,14 +365,24 @@ private void RemovePropertyByName(String propertyName)
var info = _context.GetDeclarationInfo(propertyName);
var longhands = info.Longhands;

for (var i = 0; i < _declarations.Count; i++)
if (_declarationIndex.TryGetValue(propertyName, out var index) && index < _declarations.Count &&
_declarations[index].Name.Is(propertyName))
{
var declaration = _declarations[i];

if (declaration.Name.Is(propertyName))
_declarations.RemoveAt(index);
RebuildIndex();
}
else
{
for (var i = 0; i < _declarations.Count; i++)
{
_declarations.RemoveAt(i);
break;
var declaration = _declarations[i];

if (declaration.Name.Is(propertyName))
{
_declarations.RemoveAt(i);
RebuildIndex();
break;
}
}
}

Expand All @@ -389,23 +405,39 @@ private void ChangeDeclarations(IEnumerable<ICssProperty> decls, Predicate<ICssP
{
var skip = defaultSkip(newdecl);

for (var i = 0; i < _declarations.Count; i++)
if (_declarationIndex.TryGetValue(newdecl.Name, out var idx) && idx < _declarations.Count &&
_declarations[idx].Name.Is(newdecl.Name))
{
var olddecl = _declarations[i];

if (olddecl.Name.Is(newdecl.Name))
if (removeExisting.Invoke(_declarations[idx], newdecl))
{
if (removeExisting.Invoke(olddecl, newdecl))
{
_declarations.RemoveAt(i);
skip = false;
}
else
_declarations.RemoveAt(idx);
skip = false;
}
else
{
skip = true;
}
}
else
{
for (var i = 0; i < _declarations.Count; i++)
{
var olddecl = _declarations[i];

if (olddecl.Name.Is(newdecl.Name))
{
skip = true;
}
if (removeExisting.Invoke(olddecl, newdecl))
{
_declarations.RemoveAt(i);
skip = false;
}
else
{
skip = true;
}

break;
break;
}
}
}

Expand All @@ -416,13 +448,14 @@ private void ChangeDeclarations(IEnumerable<ICssProperty> decls, Predicate<ICssP
}

_declarations.AddRange(declarations);
RebuildIndex();
}

private void SetLonghand(ICssProperty property)
{
for (var i = 0; i < _declarations.Count; i++)
if (_declarationIndex.TryGetValue(property.Name, out var index) && index < _declarations.Count)
{
var declaration = _declarations[i];
var declaration = _declarations[index];

if (declaration.Name.Is(property.Name))
{
Expand All @@ -431,11 +464,12 @@ private void SetLonghand(ICssProperty property)
return;
}

_declarations[i] = property;
_declarations[index] = property;
return;
}
}

_declarationIndex[property.Name] = _declarations.Count;
_declarations.Add(property);
}

Expand All @@ -452,6 +486,16 @@ private void SetShorthand(ICssProperty shorthand)
}
}

private void RebuildIndex()
{
_declarationIndex.Clear();

for (var i = 0; i < _declarations.Count; i++)
{
_declarationIndex[_declarations[i].Name] = i;
}
}

private void RaiseChanged()
{
if (!_updating)
Expand Down
19 changes: 19 additions & 0 deletions src/AngleSharp.Css/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,24 @@ public static String CssUrl(this String value)
var argument = value.CssString();
return Keywords.Url.CssFunction(argument);
}

/// <summary>
/// Converts to lowercase, returning the original string if it is already lowercase.
/// Avoids allocation for the common case of already-lowercase CSS identifiers.
/// </summary>
internal static String ToLowerFast(this String value)
{
for (var i = 0; i < value.Length; i++)
{
var c = value[i];

if (c >= 'A' && c <= 'Z')
{
return value.ToLowerInvariant();
}
}

return value;
}
}
}
109 changes: 47 additions & 62 deletions src/AngleSharp.Css/Parser/CssBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#nullable disable
namespace AngleSharp.Css.Parser
{
using AngleSharp.Common;
using AngleSharp.Css.Dom;
using AngleSharp.Css.Parser.Tokens;
using AngleSharp.Dom;
using AngleSharp.Text;
using System;
using System.Collections.Generic;

/// <summary>
/// See http://dev.w3.org/csswg/css-syntax/#parsing for details.
Expand All @@ -14,6 +16,22 @@ sealed class CssBuilder
{
#region Fields

private static readonly Dictionary<String, Int32> AtRuleMap = new Dictionary<String, Int32>(StringComparer.OrdinalIgnoreCase)
{
{ RuleNames.Media, 1 },
{ RuleNames.FontFace, 2 },
{ RuleNames.Keyframes, 3 },
{ RuleNames.Import, 4 },
{ RuleNames.Charset, 5 },
{ RuleNames.Namespace, 6 },
{ RuleNames.Page, 7 },
{ RuleNames.Supports, 8 },
{ RuleNames.ViewPort, 9 },
{ RuleNames.Document, 10 },
{ RuleNames.CounterStyle, 11 },
{ RuleNames.FontFeatureValues, 12 },
};

private readonly CssTokenizer _tokenizer;
private readonly CssParserOptions _options;
private readonly IBrowsingContext _context;
Expand Down Expand Up @@ -67,67 +85,26 @@ private ICssRule CreateStyleRule(ICssStyleSheet sheet, CssToken token)

private ICssRule CreateAtRule(ICssStyleSheet sheet, CssToken token)
{
if (token.Data.Is(RuleNames.Media))
{
var rule = new CssMediaRule(sheet);
return CreateMedia(rule, token);
}
else if (token.Data.Is(RuleNames.FontFace))
{
var rule = new CssFontFaceRule(sheet);
return CreateFontFace(rule, token);
}
else if (token.Data.Is(RuleNames.Keyframes))
{
var rule = new CssKeyframesRule(sheet);
return CreateKeyframes(rule, token);
}
else if (token.Data.Is(RuleNames.Import))
{
var rule = new CssImportRule(sheet);
return CreateImport(rule, token);
}
else if (token.Data.Is(RuleNames.Charset))
{
var rule = new CssCharsetRule(sheet);
return CreateCharset(rule, token);
}
else if (token.Data.Is(RuleNames.Namespace))
{
var rule = new CssNamespaceRule(sheet);
return CreateNamespace(rule, token);
}
else if (token.Data.Is(RuleNames.Page))
{
var rule = new CssPageRule(sheet);
return CreatePage(rule, token);
}
else if (token.Data.Is(RuleNames.Supports))
if (AtRuleMap.TryGetValue(token.Data, out var ruleId))
{
var rule = new CssSupportsRule(sheet);
return CreateSupports(rule, token);
}
else if (token.Data.Is(RuleNames.ViewPort))
{
var rule = new CssViewportRule(sheet);
return CreateViewport(rule, token);
}
else if (token.Data.Is(RuleNames.Document))
{
var rule = new CssDocumentRule(sheet);
return CreateDocument(rule, token);
}
else if (token.Data.Is(RuleNames.CounterStyle))
{
var rule = new CssCounterStyleRule(sheet);
return CreateCounterStyle(rule, token);
}
else if (token.Data.Is(RuleNames.FontFeatureValues))
{
var rule = new CssFontFeatureValuesRule(sheet);
return CreateFontFeatureValues(rule, token);
switch (ruleId)
{
case 1: return CreateMedia(new CssMediaRule(sheet), token);
case 2: return CreateFontFace(new CssFontFaceRule(sheet), token);
case 3: return CreateKeyframes(new CssKeyframesRule(sheet), token);
case 4: return CreateImport(new CssImportRule(sheet), token);
case 5: return CreateCharset(new CssCharsetRule(sheet), token);
case 6: return CreateNamespace(new CssNamespaceRule(sheet), token);
case 7: return CreatePage(new CssPageRule(sheet), token);
case 8: return CreateSupports(new CssSupportsRule(sheet), token);
case 9: return CreateViewport(new CssViewportRule(sheet), token);
case 10: return CreateDocument(new CssDocumentRule(sheet), token);
case 11: return CreateCounterStyle(new CssCounterStyleRule(sheet), token);
case 12: return CreateFontFeatureValues(new CssFontFeatureValuesRule(sheet), token);
}
}
else if (_options.IsIncludingUnknownRules)

if (_options.IsIncludingUnknownRules)
{
return CreateUnknownAtRule(sheet, token);
}
Expand Down Expand Up @@ -556,10 +533,18 @@ public void CreateDeclarationWith(ICssProperties properties, ref CssToken token)
{
var name = token.Data;

while (token.Type == CssTokenType.Delim)
if (token.Type == CssTokenType.Delim)
{
token = NextToken();
name += token.Data;
var sb = StringBuilderPool.Obtain();
sb.Append(name);

while (token.Type == CssTokenType.Delim)
{
token = NextToken();
sb.Append(token.Data);
}

name = sb.ToPool();
}

token = NextToken();
Expand Down
Loading
Loading