This commit is contained in:
Florian Rappl 2019-05-12 00:58:04 +02:00
Родитель 6d6af09004
Коммит 062d85e74c
8 изменённых файлов: 109 добавлений и 183 удалений

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

@ -59,6 +59,22 @@ namespace AngleSharp.Css
return factory.Create(propertyName);
}
internal static ICssProperty CreateShorthand(this IBrowsingContext context, String name, ICssValue[] longhands, Boolean important)
{
var factory = context.GetFactory<IDeclarationFactory>();
var info = factory.Create(name);
var value = info.Combine(longhands);
return new CssProperty(name, info.Converter, info.Flags, value, important);
}
internal static ICssProperty[] CreateLonghands(this IBrowsingContext context, ICssProperty shorthand)
{
var factory = context.GetFactory<IDeclarationFactory>();
var info = factory.Create(shorthand.Name);
var values = info.Seperate(factory, shorthand.RawValue);
return factory.CreateProperties(info.Longhands, values, shorthand.IsImportant);
}
internal static CssProperty CreateProperty(this IBrowsingContext context, String propertyName)
{
var info = context.GetDeclarationInfo(propertyName);
@ -75,7 +91,25 @@ namespace AngleSharp.Css
private static Boolean IsAllowingUnknownDeclarations(this IBrowsingContext context)
{
var parser = context.GetProvider<CssParser>();
return parser != null ? parser.Options.IsIncludingUnknownDeclarations : true;
return parser?.Options.IsIncludingUnknownDeclarations ?? true;
}
private static ICssProperty[] CreateProperties(this IDeclarationFactory factory, String[] names, ICssValue[] values, Boolean important)
{
if (values != null && values.Length == names.Length)
{
var properties = new ICssProperty[names.Length];
for (var i = 0; i < names.Length; i++)
{
var info = factory.Create(names[i]);
properties[i] = new CssProperty(names[i], info.Converter, info.Flags, values[i], important);
}
return properties;
}
return null;
}
}
}

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

@ -21,7 +21,8 @@ namespace AngleSharp.Css
public DeclarationInfo(String name, IValueConverter converter, PropertyFlags flags = PropertyFlags.None, ICssValue initialValue = null, String[] shorthands = null, String[] longhands = null)
{
Name = name;
Converter = Or(converter, AssignInitial(initialValue));
Converter = initialValue != null ? Or(converter, AssignInitial(initialValue)) : converter;
Aggregator = converter as IValueAggregator;
Flags = flags;
InitialValue = initialValue;
Shorthands = shorthands ?? Array.Empty<String>();
@ -43,6 +44,11 @@ namespace AngleSharp.Css
/// </summary>
public IValueConverter Converter { get; }
/// <summary>
/// Gets the value aggregator, if any.
/// </summary>
public IValueAggregator Aggregator { get; }
/// <summary>
/// Gets the flags of the declaration.
/// </summary>

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

@ -30,7 +30,7 @@ namespace AngleSharp.Css.Declarations
PropertyNames.AnimationName,
};
sealed class AnimationConverter : IValueConverter
sealed class AnimationAggregator : IValueAggregator, IValueConverter
{
private static readonly IValueConverter ListConverter = WithAny(
TimeConverter.Option(),
@ -43,13 +43,6 @@ namespace AngleSharp.Css.Declarations
IdentifierConverter.Option()).FromList();
public ICssValue Convert(StringSource source) => ListConverter.Convert(source);
}
sealed class AnimationAggregator : IValueAggregator, IValueConverter
{
private static readonly IValueConverter converter = new AnimationConverter();
public ICssValue Convert(StringSource source) => converter.Convert(source);
public ICssValue Merge(ICssValue[] values)
{
@ -72,9 +65,7 @@ namespace AngleSharp.Css.Declarations
public ICssValue[] Split(ICssValue value)
{
var list = value as CssListValue;
if (list != null)
if (value is CssListValue list)
{
return new[]
{

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

@ -221,7 +221,7 @@ namespace AngleSharp.Css.Declarations
foreach (var list in lists)
{
count = Math.Max(count, list.Count);
count = Math.Max(count, list?.Count ?? 0);
}
return count;

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

@ -39,7 +39,7 @@ namespace AngleSharp.Css.Declarations
public ICssValue Merge(ICssValue[] values)
{
if (values.Length > 0)
if (values[0] != null)
{
return new CssPeriodicValue(values);
}

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

@ -39,7 +39,7 @@ namespace AngleSharp.Css.Declarations
public ICssValue Merge(ICssValue[] values)
{
if (values.Length > 0)
if (values[0] != null)
{
return new CssPeriodicValue(values);
}

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

@ -2,7 +2,6 @@ namespace AngleSharp.Css.Dom
{
using AngleSharp.Css;
using AngleSharp.Css.Parser;
using AngleSharp.Css.Values;
using AngleSharp.Dom;
using AngleSharp.Text;
using System;
@ -75,11 +74,8 @@ namespace AngleSharp.Css.Dom
#region Methods
public void SetParent(ICssRule parent)
{
_parent = parent;
}
public void SetParent(ICssRule parent) => _parent = parent;
public void Update(String value)
{
if (IsReadOnly)
@ -102,22 +98,22 @@ namespace AngleSharp.Css.Dom
}
}
private ICssProperty TryCreateShorthand(String shorthandName, IEnumerable<String> serialized, List<String> usedProperties)
private ICssProperty TryCreateShorthand(String shorthandName, IEnumerable<String> serialized, List<String> usedProperties, Boolean force)
{
var longhands = Declarations.Where(m => !serialized.Contains(m.Name)).ToList();
var shorthand = _context.GetDeclarationInfo(shorthandName);
var factory = _context.GetFactory<IDeclarationFactory>();
var shorthand = factory.Create(shorthandName);
var requiredProperties = shorthand.Longhands;
var values = new ICssValue[requiredProperties.Length];
var important = 0;
var count = 0;
var aggregator = shorthand.Converter as IValueAggregator;
for (var i = 0; i < values.Length; i++)
{
var name = requiredProperties[i];
var propInfo = _context.GetDeclarationInfo(name);
var propInfo = factory.Create(name);
var property = propInfo.Longhands.Any() ?
TryCreateShorthand(name, serialized, usedProperties) :
TryCreateShorthand(name, serialized, usedProperties, force) :
longhands.Where(m => m.Name == name).FirstOrDefault();
if (property != null)
@ -129,23 +125,16 @@ namespace AngleSharp.Css.Dom
}
}
if (count == values.Length && aggregator != null && (important == 0 || important == count))
{
var value = aggregator.Merge(values);
if (value != null)
{
return CreateNewProperty(shorthandName, value, important != 0);
}
}
return null;
var valid = count == values.Length && (important == 0 || important == count);
var result = force || valid ? _context.CreateShorthand(shorthandName, values, important != 0) : null;
return force || result?.RawValue != null ? result : null;
}
public String ToCssBlock(IStyleFormatter formatter)
{
var list = new List<ICssProperty>();
var serialized = new List<String>();
var factory = _context.GetFactory<IDeclarationFactory>();
foreach (var declaration in Declarations)
{
@ -153,17 +142,17 @@ namespace AngleSharp.Css.Dom
if (!serialized.Contains(property))
{
var info = _context.GetDeclarationInfo(property);
var info = factory.Create(property);
var shorthands = info.Shorthands;
if (shorthands.Any())
{
var sortedShorthands = shorthands.OrderByDescending(shorthand => _context.GetDeclarationInfo(property).Longhands.Length);
var sortedShorthands = shorthands.OrderByDescending(shorthand => factory.Create(property).Longhands.Length);
foreach (var shorthandName in sortedShorthands)
{
var usedProperties = new List<String>();
var shorthand = TryCreateShorthand(shorthandName, serialized, usedProperties);
var shorthand = TryCreateShorthand(shorthandName, serialized, usedProperties, false);
if (shorthand != null)
{
@ -190,11 +179,8 @@ namespace AngleSharp.Css.Dom
return formatter.BlockDeclarations(list);
}
public void ToCss(TextWriter writer, IStyleFormatter formatter)
{
var block = ToCssBlock(formatter);
writer.Write(block.Trim(' ', '\t', '\r', '\n', '{', '}'));
}
public void ToCss(TextWriter writer, IStyleFormatter formatter) =>
writer.Write(ToCssBlock(formatter).Trim(' ', '\t', '\r', '\n', '{', '}'));
public String RemoveProperty(String propertyName)
{
@ -235,29 +221,11 @@ namespace AngleSharp.Css.Dom
return CssKeywords.Important;
}
public String GetPropertyValue(String propertyName)
{
var property = GetProperty(propertyName);
public String GetPropertyValue(String propertyName) =>
GetProperty(propertyName)?.Value ?? String.Empty;
if (property == null)
{
var value = GetShorthandInfo(propertyName).Value;
if (value != null)
{
return value.CssText;
}
return String.Empty;
}
return property.Value;
}
public void SetPropertyValue(String propertyName, String propertyValue)
{
public void SetPropertyValue(String propertyName, String propertyValue) =>
SetProperty(propertyName, propertyValue);
}
public void SetPropertyPriority(String propertyName, String priority)
{
@ -327,12 +295,8 @@ namespace AngleSharp.Css.Dom
return GetPropertyShorthand(name);
}
private ICssProperty GetPropertyShorthand(String name)
{
var result = GetShorthandInfo(name);
var decl = result.Declaration;
return new CssProperty(name, decl.Converter, decl.Flags, result.Value, result.IsImportant);
}
private ICssProperty GetPropertyShorthand(String name) =>
TryCreateShorthand(name, Enumerable.Empty<String>(), new List<String>(), true);
internal void SetDeclarations(IEnumerable<ICssProperty> decls) =>
ChangeDeclarations(decls, m => false, (o, n) => !o.IsImportant || n.IsImportant);
@ -344,79 +308,9 @@ namespace AngleSharp.Css.Dom
#region Helpers
struct ShorthandInfo
{
public DeclarationInfo Declaration;
public ICssValue Value;
public Boolean IsImportant;
}
private ShorthandInfo GetShorthandInfo(String propertyName)
{
var info = _context.GetDeclarationInfo(propertyName);
var important = false;
if (info.Converter is IValueAggregator aggregator)
{
var declarations = info.Longhands;
var values = new ICssValue[declarations.Length];
for (var i = 0; i < values.Length; i++)
{
var prop = GetProperty(declarations[i]);
if (prop != null)
{
var value = prop.RawValue;
important = important || prop.IsImportant;
if (value is CssChildValue child)
{
return new ShorthandInfo
{
Value = child.Parent,
IsImportant = important,
Declaration = info,
};
}
values[i] = value;
}
}
if (values.Any(m => m != null))
{
var value = aggregator.Merge(values);
if (value != null)
{
return new ShorthandInfo
{
Value = value,
IsImportant = important,
Declaration = info,
};
}
}
}
return new ShorthandInfo
{
Value = null,
IsImportant = important,
Declaration = info,
};
}
private ICssProperty CreateProperty(String propertyName) =>
GetProperty(propertyName) ?? _context.CreateProperty(propertyName);
private ICssProperty CreateNewProperty(String propertyName, ICssValue value, Boolean important = false)
{
var info = _context.GetDeclarationInfo(propertyName);
return new CssProperty(propertyName, info.Converter, info.Flags, value, important);
}
private void SetProperty(ICssProperty property)
{
if (property.IsShorthand)
@ -505,17 +399,12 @@ namespace AngleSharp.Css.Dom
private void SetShorthand(ICssProperty shorthand)
{
var info = _context.GetDeclarationInfo(shorthand.Name);
var properties = info.CreateLonghands(shorthand.RawValue, (name, value) =>
{
return CreateNewProperty(name, value, shorthand.IsImportant);
});
var properties = _context.CreateLonghands(shorthand);
if (properties != null)
{
foreach (var property in properties)
{
property.IsImportant = shorthand.IsImportant;
SetProperty(property);
}
}
@ -535,15 +424,9 @@ namespace AngleSharp.Css.Dom
#region Interface implementation
public IEnumerator<ICssProperty> GetEnumerator()
{
return Declarations.GetEnumerator();
}
public IEnumerator<ICssProperty> GetEnumerator() => Declarations.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
#endregion
}

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

@ -8,41 +8,53 @@ namespace AngleSharp.Css
static class DeclarationInfoExtensions
{
public static ICssProperty[] CreateLonghands(this DeclarationInfo info, ICssValue value, Func<String, ICssValue, ICssProperty> createProperty)
public static IEnumerable<String> GetMappings(this DeclarationInfo info) =>
info.Longhands.Length > 0 ? info.Longhands : Enumerable.Repeat(info.Name, 1);
public static ICssValue Combine(this DeclarationInfo info, ICssValue[] longhands)
{
var initial = true;
var unset = true;
var child = true;
foreach (var longhand in longhands)
{
initial = initial && longhand is CssInitialValue;
unset = unset && longhand is CssUnsetValue;
child = child && longhand is CssChildValue;
}
if (initial)
{
return new CssInitialValue(info.InitialValue);
}
else if (unset)
{
return new CssUnsetValue(info.InitialValue);
}
else if (child)
{
return ((CssChildValue)longhands[0]).Parent;
}
return info.Aggregator?.Merge(longhands);
}
public static ICssValue[] Seperate(this DeclarationInfo info, IDeclarationFactory factory, ICssValue value)
{
var aggregator = info.Converter as IValueAggregator;
var longhands = info.Longhands;
if (value is ICssRawValue)
if (value is ICssRawValue || value is CssChildValue)
{
var child = new CssChildValue(value);
var values = Enumerable.Repeat(child, longhands.Length).ToArray();
return CreateProperties(longhands, values, createProperty);
return Enumerable.Repeat(child, longhands.Length).ToArray();
}
return CreateProperties(longhands, aggregator?.Split(value), createProperty);
}
public static IEnumerable<String> GetMappings(this DeclarationInfo info)
{
return info.Longhands.Length > 0 ? info.Longhands : Enumerable.Repeat(info.Name, 1);
}
private static ICssProperty[] CreateProperties(String[] names, ICssValue[] values, Func<String, ICssValue, ICssProperty> createProperty)
{
if (values != null && values.Length == names.Length)
else if (value is CssInitialValue)
{
var properties = new ICssProperty[names.Length];
for (var i = 0; i < names.Length; i++)
{
properties[i] = createProperty(names[i], values[i]);
}
return properties;
return longhands.Select(name => factory.Create(name)?.InitialValue).ToArray();
}
return null;
return info.Aggregator?.Split(value);
}
}
}