Skip to content

Commit 2ae26df

Browse files
jhaygood86claude
authored andcommitted
CSS engine: sync trimming/AOT hardening and remaining property updates
The tail of the PeachPDF v0.9.6 delta (upstream d150993, e1c8d21, 71a93e2, ba7df0c, 4035e66, e0c1fd8, 731490f). - AttributeSelectorFactory: reflection-free dispatch, so the two-argument Attr*Selector constructors are statically reachable and survive trimming - PortableExtensions: the reflection-based GetProperties helper is gone, which also retires the trimming-annotation divergence the port carried - Map, ValueBuilder, and the SVG fill/stroke property updates - transform-origin now accepts a single keyword followed by a length This brings the vendored tree to exactly PeachPDF v0.9.6's 589 files, with no file missing and none extra. Map's lookup tables stay plain Dictionary rather than FrozenDictionary, which is net8-only; the comparer moves into the constructor, as elsewhere in the vendored tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 27a1638 commit 2ae26df

11 files changed

Lines changed: 36 additions & 38 deletions

File tree

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
using System;
2-
using System.Linq;
3-
using System.Reflection;
4-
51
#if !NET40 && !SL50
62

73
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
@@ -12,16 +8,7 @@ public static string ConvertFromUtf32(this int utf32)
128
{
139
return char.ConvertFromUtf32(utf32);
1410
}
15-
16-
// The [DynamicallyAccessedMembers] trimming annotation from the source this was ported from is
17-
// deliberately dropped here - it's a metadata-only hint for IL trimmers/AOT (no runtime effect),
18-
// and HTML-Renderer doesn't use trimming; keeping it would need a netstandard2.0-incompatible
19-
// reference to System.Diagnostics.CodeAnalysis's copy of the attribute.
20-
public static PropertyInfo[] GetProperties(this Type type)
21-
{
22-
return type.GetRuntimeProperties().ToArray();
23-
}
2411
}
2512
}
2613

27-
#endif
14+
#endif

‎Source/HtmlRenderer/Core/CssEngine/Factories/AttributeSelectorFactory.cs‎

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,11 @@
11
using System;
2-
using System.Collections.Generic;
32

43
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
54
{
65
internal sealed class AttributeSelectorFactory
76
{
87
private static readonly Lazy<AttributeSelectorFactory> Lazy = new Lazy<AttributeSelectorFactory>(() => new AttributeSelectorFactory());
98

10-
private readonly Dictionary<string, Type> _types = new Dictionary<string, Type>()
11-
{
12-
{ Combinators.Exactly, typeof(AttrMatchSelector) },
13-
{ Combinators.InList, typeof(AttrListSelector) },
14-
{ Combinators.InToken, typeof(AttrHyphenSelector) },
15-
{ Combinators.Begins, typeof(AttrBeginsSelector) },
16-
{ Combinators.Ends, typeof(AttrEndsSelector) },
17-
{ Combinators.InText, typeof(AttrContainsSelector) },
18-
{ Combinators.Unlike, typeof(AttrNotMatchSelector) },
19-
};
20-
219
private AttributeSelectorFactory()
2210
{
2311
}
@@ -34,9 +22,20 @@ public IAttrSelector Create(string combinator, string match, string value, strin
3422
_ = AttributeSelectorFactory.FormMatch(prefix, match);
3523
}
3624

37-
return _types.TryGetValue(combinator, out var type)
38-
? (IAttrSelector)Activator.CreateInstance(type, name, value)
39-
: new AttrAvailableSelector(name, value);
25+
// A reflection-free dispatch (no Activator.CreateInstance) so the two-arg Attr*Selector
26+
// constructors are statically reachable and survive trimming/AOT (IsTrimmable=true) - see
27+
// upstream ExCSS commit c497ca7. Unknown combinators fall back to a presence selector.
28+
switch (combinator)
29+
{
30+
case Combinators.Exactly: return new AttrMatchSelector(name, value);
31+
case Combinators.InList: return new AttrListSelector(name, value);
32+
case Combinators.InToken: return new AttrHyphenSelector(name, value);
33+
case Combinators.Begins: return new AttrBeginsSelector(name, value);
34+
case Combinators.Ends: return new AttrEndsSelector(name, value);
35+
case Combinators.InText: return new AttrContainsSelector(name, value);
36+
case Combinators.Unlike: return new AttrNotMatchSelector(name, value);
37+
default: return new AttrAvailableSelector(name, value);
38+
}
4039
}
4140

4241
private static string FormFront(string prefix, string match)

‎Source/HtmlRenderer/Core/CssEngine/Model/Map.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ internal static class Map
245245
{Keywords.Large, FontSize.Large},
246246
{Keywords.XLarge, FontSize.Big},
247247
{Keywords.XxLarge, FontSize.Huge},
248-
{Keywords.Larger, FontSize.Smaller},
249-
{Keywords.Smaller, FontSize.Larger}
248+
{Keywords.Larger, FontSize.Larger},
249+
{Keywords.Smaller, FontSize.Smaller}
250250
};
251251
public static readonly Dictionary<string, TextDecorationStyle> TextDecorationStyles =
252252
new Dictionary<string, TextDecorationStyle>(StringComparer.OrdinalIgnoreCase)

‎Source/HtmlRenderer/Core/CssEngine/Model/ValueBuilder.cs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public void Apply(Token token)
5050
case TokenType.Dimension:
5151
case TokenType.Percentage:
5252
case TokenType.Color:
53+
case TokenType.Hash:
5354
case TokenType.Delim:
5455
case TokenType.String:
5556
case TokenType.Url:
@@ -59,6 +60,17 @@ public void Apply(Token token)
5960
case TokenType.GreaterThanOrEqual:
6061
case TokenType.LessThan:
6162
case TokenType.LessThanOrEqual:
63+
case TokenType.Range:
64+
// A U+... unicode-range value (an @font-face descriptor) is a sequence of Range tokens;
65+
// without this they'd hit the default arm and mark the whole value invalid, so the
66+
// descriptor would be dropped under strict (non-tolerant) parsing - the pipeline default.
67+
Add(token);
68+
break;
69+
case TokenType.SquareBracketOpen:
70+
case TokenType.SquareBracketClose:
71+
// Square brackets are valid in a value: grid line names, e.g.
72+
// `grid-template-columns: [sidebar-start] 200px [sidebar-end]`. Without this they'd hit
73+
// the default arm and the whole declaration would be dropped under strict parsing.
6274
Add(token);
6375
break;
6476
case TokenType.Comment:

‎Source/HtmlRenderer/Core/CssEngine/StyleProperties/Fill/FillProperty.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
22
{
33
internal sealed class FillProperty : Property
44
{
5-
private static readonly IValueConverter StyleConverter = Converters.PaintConverter;
5+
private static readonly IValueConverter StyleConverter = Converters.PaintConverter.OrGlobalValue();
66

77
internal FillProperty()
88
: base(PropertyNames.Fill, PropertyFlags.Animatable)

‎Source/HtmlRenderer/Core/CssEngine/StyleProperties/Stroke/StrokeDasharrayProperty.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
22
{
33
internal sealed class StrokeDasharrayProperty : Property
44
{
5-
private static readonly IValueConverter StyleConverter = Converters.StrokeDasharrayConverter;
5+
private static readonly IValueConverter StyleConverter = Converters.StrokeDasharrayConverter.OrGlobalValue();
66

77
public StrokeDasharrayProperty()
88
: base(PropertyNames.StrokeDasharray, PropertyFlags.Animatable | PropertyFlags.Unitless)

‎Source/HtmlRenderer/Core/CssEngine/StyleProperties/Stroke/StrokeDashoffsetProperty.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
22
{
33
internal sealed class StrokeDashoffsetProperty : Property
44
{
5-
private static readonly IValueConverter StyleConverter = Converters.LengthOrPercentConverter;
5+
private static readonly IValueConverter StyleConverter = Converters.LengthOrPercentConverter.OrGlobalValue();
66

77
public StrokeDashoffsetProperty()
88
: base(PropertyNames.StrokeDashoffset, PropertyFlags.Animatable)

‎Source/HtmlRenderer/Core/CssEngine/StyleProperties/Stroke/StrokeLinejoinProperty.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
22
{
33
internal sealed class StrokeLinejoinProperty : Property
44
{
5-
private static readonly IValueConverter StyleConverter = Converters.StrokeLinejoinConverter;
5+
private static readonly IValueConverter StyleConverter = Converters.StrokeLinejoinConverter.OrGlobalValue();
66

77
public StrokeLinejoinProperty()
88
: base(PropertyNames.StrokeLinejoin, PropertyFlags.Animatable)

‎Source/HtmlRenderer/Core/CssEngine/StyleProperties/Stroke/StrokeMiterlimitProperty.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
22
{
33
internal sealed class StrokeMiterlimitProperty : Property
44
{
5-
private static readonly IValueConverter StyleConverter = Converters.StrokeMiterlimitConverter;
5+
private static readonly IValueConverter StyleConverter = Converters.StrokeMiterlimitConverter.OrGlobalValue();
66

77
public StrokeMiterlimitProperty()
88
: base(PropertyNames.StrokeMiterlimit, PropertyFlags.Animatable)

‎Source/HtmlRenderer/Core/CssEngine/StyleProperties/Stroke/StrokeProperty.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
22
{
33
internal sealed class StrokeProperty : Property
44
{
5-
private static readonly IValueConverter StyleConverter = Converters.PaintConverter;
5+
private static readonly IValueConverter StyleConverter = Converters.PaintConverter.OrGlobalValue();
66

77
internal StrokeProperty()
88
: base(PropertyNames.Stroke, PropertyFlags.Animatable)

0 commit comments

Comments
 (0)