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
125 changes: 125 additions & 0 deletions src/AngleSharp.Css.Tests/Declarations/CssBorderProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -586,5 +586,130 @@ public void CssBorderAggregation()
style.SetBorderColor("black");
Assert.AreEqual(expectedCss, style.CssText);
}

[Test]
public void CssBorderInheritShouldResolveToParentValues()
{
var source = @"<!DOCTYPE html>
<html>
<head><style>
table { border: 3px solid; }
table * { border: inherit; }
</style></head>
<body>
<table><tr><td>Cell</td></tr></table>
</body>
</html>";
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
var td = document.QuerySelector("td");
var style = td.ComputeCurrentStyle();
Assert.AreEqual("solid", style.GetBorderTopStyle());
Assert.AreEqual("3px", style.GetBorderTopWidth());
}

[Test]
public void CssBorderInheritShouldResolveAllSides()
{
var source = @"<!DOCTYPE html>
<html>
<head><style>
div.parent { border: 2px dashed; }
div.child { border: inherit; }
</style></head>
<body>
<div class='parent'><div class='child'>Content</div></div>
</body>
</html>";
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
var child = document.QuerySelector("div.child");
var style = child.ComputeCurrentStyle();
Assert.AreEqual("dashed", style.GetBorderTopStyle());
Assert.AreEqual("dashed", style.GetBorderBottomStyle());
Assert.AreEqual("dashed", style.GetBorderLeftStyle());
Assert.AreEqual("dashed", style.GetBorderRightStyle());
Assert.AreEqual("2px", style.GetBorderTopWidth());
Assert.AreEqual("2px", style.GetBorderBottomWidth());
}

[Test]
public void CssBorderStyleInheritShouldResolveToParentValues()
{
var source = @"<!DOCTYPE html>
<html>
<head><style>
div.parent { border-style: dotted; }
div.child { border-style: inherit; }
</style></head>
<body>
<div class='parent'><div class='child'>Content</div></div>
</body>
</html>";
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
var child = document.QuerySelector("div.child");
var style = child.ComputeCurrentStyle();
Assert.AreEqual("dotted", style.GetBorderTopStyle());
Assert.AreEqual("dotted", style.GetBorderRightStyle());
}

[Test]
public void CssBorderWidthInheritShouldResolveToParentValues()
{
var source = @"<!DOCTYPE html>
<html>
<head><style>
div.parent { border-width: 5px; }
div.child { border-width: inherit; }
</style></head>
<body>
<div class='parent'><div class='child'>Content</div></div>
</body>
</html>";
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
var child = document.QuerySelector("div.child");
var style = child.ComputeCurrentStyle();
Assert.AreEqual("5px", style.GetBorderTopWidth());
Assert.AreEqual("5px", style.GetBorderLeftWidth());
}

[Test]
public void CssBorderInheritThroughMultipleLevels()
{
var source = @"<!DOCTYPE html>
<html>
<head><style>
div.root { border: 4px solid; }
div.root * { border: inherit; }
</style></head>
<body>
<div class='root'><div class='mid'><div class='inner'>Deep</div></div></div>
</body>
</html>";
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
var inner = document.QuerySelector("div.inner");
var style = inner.ComputeCurrentStyle();
Assert.AreEqual("solid", style.GetBorderTopStyle());
Assert.AreEqual("4px", style.GetBorderTopWidth());
}

[Test]
public void CssBorderInheritWithExplicitChildOverride()
{
var source = @"<!DOCTYPE html>
<html>
<head><style>
div.parent { border: 3px solid; }
div.child { border: inherit; border-top-style: dotted; }
</style></head>
<body>
<div class='parent'><div class='child'>Content</div></div>
</body>
</html>";
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
var child = document.QuerySelector("div.child");
var style = child.ComputeCurrentStyle();
Assert.AreEqual("dotted", style.GetBorderTopStyle());
Assert.AreEqual("solid", style.GetBorderBottomStyle());
Assert.AreEqual("3px", style.GetBorderTopWidth());
}
}
}
79 changes: 79 additions & 0 deletions src/AngleSharp.Css.Tests/Library/ComputedStyle.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
namespace AngleSharp.Css.Tests.Library
{
using AngleSharp.Css.Dom;
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
using NUnit.Framework;
using System.Threading.Tasks;
using static CssConstructionFunctions;

[TestFixture]
public class ComputedStyleTests
Expand All @@ -25,5 +27,82 @@ public async Task TransformEmToPx_Issue136()

Assert.AreEqual("24px", fontSize.Value);
}

[Test]
public void MarginInheritShouldResolveToParentValues()
{
var source = @"<!DOCTYPE html>
<html>
<head><style>
div.parent { margin: 10px 20px; }
div.child { margin: inherit; }
</style></head>
<body>
<div class='parent'><div class='child'>Content</div></div>
</body>
</html>";
var document = ParseDocument(source);
var child = document.QuerySelector("div.child");
var style = child.ComputeCurrentStyle();
Assert.AreEqual("10px", style.GetMarginTop());
Assert.AreEqual("20px", style.GetMarginRight());
Assert.AreEqual("10px", style.GetMarginBottom());
Assert.AreEqual("20px", style.GetMarginLeft());
}

[Test]
public void PaddingInheritShouldResolveToParentValues()
{
var source = @"<!DOCTYPE html>
<html>
<head><style>
div.parent { padding: 5px 15px 10px; }
div.child { padding: inherit; }
</style></head>
<body>
<div class='parent'><div class='child'>Content</div></div>
</body>
</html>";
var document = ParseDocument(source);
var child = document.QuerySelector("div.child");
var style = child.ComputeCurrentStyle();
Assert.AreEqual("5px", style.GetPaddingTop());
Assert.AreEqual("15px", style.GetPaddingRight());
Assert.AreEqual("10px", style.GetPaddingBottom());
Assert.AreEqual("15px", style.GetPaddingLeft());
}

[Test]
public void InheritOnNonInheritablePropertyShouldResolveFromParent()
{
var source = @"<!DOCTYPE html>
<html>
<head><style>
div.parent { border: 1px solid; padding: 8px; }
div.child { border: inherit; padding: inherit; }
</style></head>
<body>
<div class='parent'><div class='child'>Content</div></div>
</body>
</html>";
var document = ParseDocument(source);
var child = document.QuerySelector("div.child");
var style = child.ComputeCurrentStyle();
Assert.AreEqual("solid", style.GetBorderTopStyle());
Assert.AreEqual("1px", style.GetBorderTopWidth());
Assert.AreEqual("8px", style.GetPaddingTop());
}

[Test]
public void BorderInheritShouldSerializeCorrectly()
{
var html = @"<style>div { border: inherit }</style>";
var dom = ParseDocument(html);
var styleSheet = dom.StyleSheets[0] as ICssStyleSheet;
var rule = styleSheet.Rules[0] as ICssStyleRule;
Assert.AreEqual("inherit", rule.Style.GetPropertyValue("border-top-style"));
Assert.AreEqual("inherit", rule.Style.GetPropertyValue("border-top-width"));
Assert.AreEqual("inherit", rule.Style.GetPropertyValue("border-top-color"));
}
}
}
2 changes: 1 addition & 1 deletion src/AngleSharp.Css/DeclarationInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class DeclarationInfo
public DeclarationInfo(String name, IValueConverter converter, PropertyFlags flags = PropertyFlags.None, ICssValue initialValue = null, String[] shorthands = null, String[] longhands = null)
{
Name = name;
Converter = initialValue != null ? Or(converter, AssignInitial(initialValue)) : converter;
Converter = initialValue != null || longhands?.Length > 0 ? Or(AssignInitial(initialValue), converter) : converter;
Aggregator = converter as IValueAggregator;
Flags = flags;
InitialValue = initialValue;
Expand Down
1 change: 1 addition & 0 deletions src/AngleSharp.Css/Dom/Internal/CssStyleDeclaration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ private void ChangeDeclarations(IEnumerable<ICssProperty> decls, Predicate<ICssP
if (removeExisting.Invoke(olddecl, newdecl))
{
_declarations.RemoveAt(i);
skip = false;
}
else
{
Expand Down
19 changes: 19 additions & 0 deletions src/AngleSharp.Css/Extensions/DeclarationInfoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ public static ICssValue Collapse(this DeclarationInfo info, IDeclarationFactory
var initial = true;
var unset = true;
var child = true;
var inherit = true;

foreach (var longhand in longhands)
{
initial = initial && longhand is CssInitialValue;
unset = unset && longhand is CssUnsetValue;
child = child && longhand is CssChildValue;
inherit = inherit && longhand is CssInheritValue;
}

if (initial)
Expand All @@ -32,6 +34,10 @@ public static ICssValue Collapse(this DeclarationInfo info, IDeclarationFactory
{
return new CssUnsetValue(info.InitialValue);
}
else if (inherit)
{
return CssInheritValue.Instance;
}
else if (child)
{
return ((CssChildValue)longhands[0]).Parent;
Expand All @@ -58,6 +64,19 @@ public static ICssValue[] Expand(this DeclarationInfo info, IDeclarationFactory
.OfType<ICssValue>()
.ToArray();
}
else if (value is CssInheritValue)
{
return Enumerable
.Repeat(value, longhands.Length)
.ToArray();
}
else if (value is CssUnsetValue)
{
return longhands
.Select(name => new CssUnsetValue(factory.Create(name)?.InitialValue))
.OfType<ICssValue>()
.ToArray();
}

return info.Aggregator?.Split(value);
}
Expand Down
Loading