Skip to content

Commit cc364f5

Browse files
authored
Merge pull request #203 from jafin/fix/css-inherit-shorthand-resolution
Fix/css inherit shorthand resolution
2 parents b2305f8 + 56102e0 commit cc364f5

5 files changed

Lines changed: 225 additions & 1 deletion

File tree

src/AngleSharp.Css.Tests/Declarations/CssBorderProperty.cs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,5 +586,130 @@ public void CssBorderAggregation()
586586
style.SetBorderColor("black");
587587
Assert.AreEqual(expectedCss, style.CssText);
588588
}
589+
590+
[Test]
591+
public void CssBorderInheritShouldResolveToParentValues()
592+
{
593+
var source = @"<!DOCTYPE html>
594+
<html>
595+
<head><style>
596+
table { border: 3px solid; }
597+
table * { border: inherit; }
598+
</style></head>
599+
<body>
600+
<table><tr><td>Cell</td></tr></table>
601+
</body>
602+
</html>";
603+
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
604+
var td = document.QuerySelector("td");
605+
var style = td.ComputeCurrentStyle();
606+
Assert.AreEqual("solid", style.GetBorderTopStyle());
607+
Assert.AreEqual("3px", style.GetBorderTopWidth());
608+
}
609+
610+
[Test]
611+
public void CssBorderInheritShouldResolveAllSides()
612+
{
613+
var source = @"<!DOCTYPE html>
614+
<html>
615+
<head><style>
616+
div.parent { border: 2px dashed; }
617+
div.child { border: inherit; }
618+
</style></head>
619+
<body>
620+
<div class='parent'><div class='child'>Content</div></div>
621+
</body>
622+
</html>";
623+
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
624+
var child = document.QuerySelector("div.child");
625+
var style = child.ComputeCurrentStyle();
626+
Assert.AreEqual("dashed", style.GetBorderTopStyle());
627+
Assert.AreEqual("dashed", style.GetBorderBottomStyle());
628+
Assert.AreEqual("dashed", style.GetBorderLeftStyle());
629+
Assert.AreEqual("dashed", style.GetBorderRightStyle());
630+
Assert.AreEqual("2px", style.GetBorderTopWidth());
631+
Assert.AreEqual("2px", style.GetBorderBottomWidth());
632+
}
633+
634+
[Test]
635+
public void CssBorderStyleInheritShouldResolveToParentValues()
636+
{
637+
var source = @"<!DOCTYPE html>
638+
<html>
639+
<head><style>
640+
div.parent { border-style: dotted; }
641+
div.child { border-style: inherit; }
642+
</style></head>
643+
<body>
644+
<div class='parent'><div class='child'>Content</div></div>
645+
</body>
646+
</html>";
647+
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
648+
var child = document.QuerySelector("div.child");
649+
var style = child.ComputeCurrentStyle();
650+
Assert.AreEqual("dotted", style.GetBorderTopStyle());
651+
Assert.AreEqual("dotted", style.GetBorderRightStyle());
652+
}
653+
654+
[Test]
655+
public void CssBorderWidthInheritShouldResolveToParentValues()
656+
{
657+
var source = @"<!DOCTYPE html>
658+
<html>
659+
<head><style>
660+
div.parent { border-width: 5px; }
661+
div.child { border-width: inherit; }
662+
</style></head>
663+
<body>
664+
<div class='parent'><div class='child'>Content</div></div>
665+
</body>
666+
</html>";
667+
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
668+
var child = document.QuerySelector("div.child");
669+
var style = child.ComputeCurrentStyle();
670+
Assert.AreEqual("5px", style.GetBorderTopWidth());
671+
Assert.AreEqual("5px", style.GetBorderLeftWidth());
672+
}
673+
674+
[Test]
675+
public void CssBorderInheritThroughMultipleLevels()
676+
{
677+
var source = @"<!DOCTYPE html>
678+
<html>
679+
<head><style>
680+
div.root { border: 4px solid; }
681+
div.root * { border: inherit; }
682+
</style></head>
683+
<body>
684+
<div class='root'><div class='mid'><div class='inner'>Deep</div></div></div>
685+
</body>
686+
</html>";
687+
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
688+
var inner = document.QuerySelector("div.inner");
689+
var style = inner.ComputeCurrentStyle();
690+
Assert.AreEqual("solid", style.GetBorderTopStyle());
691+
Assert.AreEqual("4px", style.GetBorderTopWidth());
692+
}
693+
694+
[Test]
695+
public void CssBorderInheritWithExplicitChildOverride()
696+
{
697+
var source = @"<!DOCTYPE html>
698+
<html>
699+
<head><style>
700+
div.parent { border: 3px solid; }
701+
div.child { border: inherit; border-top-style: dotted; }
702+
</style></head>
703+
<body>
704+
<div class='parent'><div class='child'>Content</div></div>
705+
</body>
706+
</html>";
707+
var document = source.ToHtmlDocument(Configuration.Default.WithCss());
708+
var child = document.QuerySelector("div.child");
709+
var style = child.ComputeCurrentStyle();
710+
Assert.AreEqual("dotted", style.GetBorderTopStyle());
711+
Assert.AreEqual("solid", style.GetBorderBottomStyle());
712+
Assert.AreEqual("3px", style.GetBorderTopWidth());
713+
}
589714
}
590715
}

src/AngleSharp.Css.Tests/Library/ComputedStyle.cs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
namespace AngleSharp.Css.Tests.Library
22
{
3+
using AngleSharp.Css.Dom;
34
using AngleSharp.Dom;
45
using AngleSharp.Html.Dom;
56
using NUnit.Framework;
67
using System.Threading.Tasks;
8+
using static CssConstructionFunctions;
79

810
[TestFixture]
911
public class ComputedStyleTests
@@ -25,5 +27,82 @@ public async Task TransformEmToPx_Issue136()
2527

2628
Assert.AreEqual("24px", fontSize.Value);
2729
}
30+
31+
[Test]
32+
public void MarginInheritShouldResolveToParentValues()
33+
{
34+
var source = @"<!DOCTYPE html>
35+
<html>
36+
<head><style>
37+
div.parent { margin: 10px 20px; }
38+
div.child { margin: inherit; }
39+
</style></head>
40+
<body>
41+
<div class='parent'><div class='child'>Content</div></div>
42+
</body>
43+
</html>";
44+
var document = ParseDocument(source);
45+
var child = document.QuerySelector("div.child");
46+
var style = child.ComputeCurrentStyle();
47+
Assert.AreEqual("10px", style.GetMarginTop());
48+
Assert.AreEqual("20px", style.GetMarginRight());
49+
Assert.AreEqual("10px", style.GetMarginBottom());
50+
Assert.AreEqual("20px", style.GetMarginLeft());
51+
}
52+
53+
[Test]
54+
public void PaddingInheritShouldResolveToParentValues()
55+
{
56+
var source = @"<!DOCTYPE html>
57+
<html>
58+
<head><style>
59+
div.parent { padding: 5px 15px 10px; }
60+
div.child { padding: inherit; }
61+
</style></head>
62+
<body>
63+
<div class='parent'><div class='child'>Content</div></div>
64+
</body>
65+
</html>";
66+
var document = ParseDocument(source);
67+
var child = document.QuerySelector("div.child");
68+
var style = child.ComputeCurrentStyle();
69+
Assert.AreEqual("5px", style.GetPaddingTop());
70+
Assert.AreEqual("15px", style.GetPaddingRight());
71+
Assert.AreEqual("10px", style.GetPaddingBottom());
72+
Assert.AreEqual("15px", style.GetPaddingLeft());
73+
}
74+
75+
[Test]
76+
public void InheritOnNonInheritablePropertyShouldResolveFromParent()
77+
{
78+
var source = @"<!DOCTYPE html>
79+
<html>
80+
<head><style>
81+
div.parent { border: 1px solid; padding: 8px; }
82+
div.child { border: inherit; padding: inherit; }
83+
</style></head>
84+
<body>
85+
<div class='parent'><div class='child'>Content</div></div>
86+
</body>
87+
</html>";
88+
var document = ParseDocument(source);
89+
var child = document.QuerySelector("div.child");
90+
var style = child.ComputeCurrentStyle();
91+
Assert.AreEqual("solid", style.GetBorderTopStyle());
92+
Assert.AreEqual("1px", style.GetBorderTopWidth());
93+
Assert.AreEqual("8px", style.GetPaddingTop());
94+
}
95+
96+
[Test]
97+
public void BorderInheritShouldSerializeCorrectly()
98+
{
99+
var html = @"<style>div { border: inherit }</style>";
100+
var dom = ParseDocument(html);
101+
var styleSheet = dom.StyleSheets[0] as ICssStyleSheet;
102+
var rule = styleSheet.Rules[0] as ICssStyleRule;
103+
Assert.AreEqual("inherit", rule.Style.GetPropertyValue("border-top-style"));
104+
Assert.AreEqual("inherit", rule.Style.GetPropertyValue("border-top-width"));
105+
Assert.AreEqual("inherit", rule.Style.GetPropertyValue("border-top-color"));
106+
}
28107
}
29108
}

src/AngleSharp.Css/DeclarationInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class DeclarationInfo
2121
public DeclarationInfo(String name, IValueConverter converter, PropertyFlags flags = PropertyFlags.None, ICssValue initialValue = null, String[] shorthands = null, String[] longhands = null)
2222
{
2323
Name = name;
24-
Converter = initialValue != null ? Or(converter, AssignInitial(initialValue)) : converter;
24+
Converter = initialValue != null || longhands?.Length > 0 ? Or(AssignInitial(initialValue), converter) : converter;
2525
Aggregator = converter as IValueAggregator;
2626
Flags = flags;
2727
InitialValue = initialValue;

src/AngleSharp.Css/Dom/Internal/CssStyleDeclaration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ private void ChangeDeclarations(IEnumerable<ICssProperty> decls, Predicate<ICssP
397397
if (removeExisting.Invoke(olddecl, newdecl))
398398
{
399399
_declarations.RemoveAt(i);
400+
skip = false;
400401
}
401402
else
402403
{

src/AngleSharp.Css/Extensions/DeclarationInfoExtensions.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ public static ICssValue Collapse(this DeclarationInfo info, IDeclarationFactory
1616
var initial = true;
1717
var unset = true;
1818
var child = true;
19+
var inherit = true;
1920

2021
foreach (var longhand in longhands)
2122
{
2223
initial = initial && longhand is CssInitialValue;
2324
unset = unset && longhand is CssUnsetValue;
2425
child = child && longhand is CssChildValue;
26+
inherit = inherit && longhand is CssInheritValue;
2527
}
2628

2729
if (initial)
@@ -32,6 +34,10 @@ public static ICssValue Collapse(this DeclarationInfo info, IDeclarationFactory
3234
{
3335
return new CssUnsetValue(info.InitialValue);
3436
}
37+
else if (inherit)
38+
{
39+
return CssInheritValue.Instance;
40+
}
3541
else if (child)
3642
{
3743
return ((CssChildValue)longhands[0]).Parent;
@@ -58,6 +64,19 @@ public static ICssValue[] Expand(this DeclarationInfo info, IDeclarationFactory
5864
.OfType<ICssValue>()
5965
.ToArray();
6066
}
67+
else if (value is CssInheritValue)
68+
{
69+
return Enumerable
70+
.Repeat(value, longhands.Length)
71+
.ToArray();
72+
}
73+
else if (value is CssUnsetValue)
74+
{
75+
return longhands
76+
.Select(name => new CssUnsetValue(factory.Create(name)?.InitialValue))
77+
.OfType<ICssValue>()
78+
.ToArray();
79+
}
6180

6281
return info.Aggregator?.Split(value);
6382
}

0 commit comments

Comments
 (0)