Skip to content

Commit 580bab1

Browse files
jhaygood86eXpl0it3r
authored andcommitted
CSS engine: sync CSS logical box-model properties
Adds CSS Logical Properties and Values Level 1 from PeachPDF v0.9.6 (upstream 2fdde30): margin-block/-inline, padding-block/-inline, inset and its block/ inline forms, and the border-block/-inline width/style/colour family, with all their per-edge longhands. Layout here is always LTR / horizontal-tb, so each logical property is registered against the existing *physical* property class - margin-inline-start produces margin-left, inset-block-start produces top, and so on. StyleDeclaration keys by the produced property's name, so these land in the cascade as the physical longhands that the box model already consumes: no downstream change, and no renderer work needed for them to take effect. The logical shorthands are registered through a new AddLogicalShorthand, which also records them in _logicalShorthands so GetShorthands skips them when reconstructing shorthand text. Without that, the serializer could collapse margin-top + margin-bottom into `margin-block` and change existing output.
1 parent 0186430 commit 580bab1

16 files changed

Lines changed: 385 additions & 1 deletion

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

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ internal sealed class PropertyFactory
1818

1919
private readonly Dictionary<string, ShorthandCreator> _shorthandsBuilder = new Dictionary<string, ShorthandCreator>(StringComparer.OrdinalIgnoreCase);
2020

21+
// Shorthands that parse and expand normally but are excluded from serialization reconstruction:
22+
// the logical shorthands, whose longhands are the physical ones (margin-top/-bottom/…), so letting
23+
// the serializer collapse e.g. margin-top+margin-bottom into `margin-block` would change existing
24+
// output. Excluded from GetShorthands (the serialization query) only; CreateShorthand,
25+
// GetLonghands and IsShorthand still work.
26+
private readonly HashSet<string> _logicalShorthands = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
27+
2128
private readonly Dictionary<string, LonghandCreator> _fonts;
2229

2330
// @property descriptors (syntax / initial-value / inherits). Their values have no fixed CSS grammar
@@ -357,6 +364,124 @@ private PropertyFactory()
357364
_fontsBuilder.Add(PropertyNames.Src, () => new SrcProperty());
358365
_fontsBuilder.Add(PropertyNames.UnicodeRange, () => new UnicodeRangeProperty());
359366

367+
// CSS Logical Properties and Values Level 1. Layout here is always LTR / horizontal-tb,
368+
// so each logical property is registered to produce/export the existing physical
369+
// longhands (block-start = top, block-end = bottom, inline-start = left,
370+
// inline-end = right). Nothing downstream needs to change, since it already handles
371+
// every physical longhand.
372+
373+
// Logical margin longhands (aliases to the physical longhand classes).
374+
AddLonghand(PropertyNames.MarginBlockStart, () => new MarginTopProperty(), true);
375+
AddLonghand(PropertyNames.MarginBlockEnd, () => new MarginBottomProperty(), true);
376+
AddLonghand(PropertyNames.MarginInlineStart, () => new MarginLeftProperty(), true);
377+
AddLonghand(PropertyNames.MarginInlineEnd, () => new MarginRightProperty(), true);
378+
// Logical margin shorthands.
379+
AddLogicalShorthand(PropertyNames.MarginBlock, () => new MarginBlockProperty(),
380+
PropertyNames.MarginTop,
381+
PropertyNames.MarginBottom);
382+
AddLogicalShorthand(PropertyNames.MarginInline, () => new MarginInlineProperty(),
383+
PropertyNames.MarginLeft,
384+
PropertyNames.MarginRight);
385+
386+
// Logical padding longhands (aliases to the physical longhand classes).
387+
AddLonghand(PropertyNames.PaddingBlockStart, () => new PaddingTopProperty(), true);
388+
AddLonghand(PropertyNames.PaddingBlockEnd, () => new PaddingBottomProperty(), true);
389+
AddLonghand(PropertyNames.PaddingInlineStart, () => new PaddingLeftProperty(), true);
390+
AddLonghand(PropertyNames.PaddingInlineEnd, () => new PaddingRightProperty(), true);
391+
// Logical padding shorthands.
392+
AddLogicalShorthand(PropertyNames.PaddingBlock, () => new PaddingBlockProperty(),
393+
PropertyNames.PaddingTop,
394+
PropertyNames.PaddingBottom);
395+
AddLogicalShorthand(PropertyNames.PaddingInline, () => new PaddingInlineProperty(),
396+
PropertyNames.PaddingLeft,
397+
PropertyNames.PaddingRight);
398+
399+
// Logical inset longhands (aliases to the physical coordinate longhand classes).
400+
AddLonghand(PropertyNames.InsetBlockStart, () => new TopProperty(), true);
401+
AddLonghand(PropertyNames.InsetBlockEnd, () => new BottomProperty(), true);
402+
AddLonghand(PropertyNames.InsetInlineStart, () => new LeftProperty(), true);
403+
AddLonghand(PropertyNames.InsetInlineEnd, () => new RightProperty(), true);
404+
// Inset shorthands.
405+
AddLogicalShorthand(PropertyNames.Inset, () => new InsetProperty(),
406+
PropertyNames.Top,
407+
PropertyNames.Right,
408+
PropertyNames.Bottom,
409+
PropertyNames.Left);
410+
AddLogicalShorthand(PropertyNames.InsetBlock, () => new InsetBlockProperty(),
411+
PropertyNames.Top,
412+
PropertyNames.Bottom);
413+
AddLogicalShorthand(PropertyNames.InsetInline, () => new InsetInlineProperty(),
414+
PropertyNames.Left,
415+
PropertyNames.Right);
416+
417+
// Logical per-edge border longhands (aliases to the physical longhand classes).
418+
AddLonghand(PropertyNames.BorderBlockStartWidth, () => new BorderTopWidthProperty(), true);
419+
AddLonghand(PropertyNames.BorderBlockStartStyle, () => new BorderTopStyleProperty());
420+
AddLonghand(PropertyNames.BorderBlockStartColor, () => new BorderTopColorProperty(), true);
421+
AddLonghand(PropertyNames.BorderBlockEndWidth, () => new BorderBottomWidthProperty(), true);
422+
AddLonghand(PropertyNames.BorderBlockEndStyle, () => new BorderBottomStyleProperty());
423+
AddLonghand(PropertyNames.BorderBlockEndColor, () => new BorderBottomColorProperty(), true);
424+
AddLonghand(PropertyNames.BorderInlineStartWidth, () => new BorderLeftWidthProperty(), true);
425+
AddLonghand(PropertyNames.BorderInlineStartStyle, () => new BorderLeftStyleProperty());
426+
AddLonghand(PropertyNames.BorderInlineStartColor, () => new BorderLeftColorProperty(), true);
427+
AddLonghand(PropertyNames.BorderInlineEndWidth, () => new BorderRightWidthProperty(), true);
428+
AddLonghand(PropertyNames.BorderInlineEndStyle, () => new BorderRightStyleProperty());
429+
AddLonghand(PropertyNames.BorderInlineEndColor, () => new BorderRightColorProperty(), true);
430+
431+
// Logical per-edge border shorthands (aliases to the physical edge shorthand classes).
432+
AddLogicalShorthand(PropertyNames.BorderBlockStart, () => new BorderTopProperty(),
433+
PropertyNames.BorderTopWidth,
434+
PropertyNames.BorderTopStyle,
435+
PropertyNames.BorderTopColor);
436+
AddLogicalShorthand(PropertyNames.BorderBlockEnd, () => new BorderBottomProperty(),
437+
PropertyNames.BorderBottomWidth,
438+
PropertyNames.BorderBottomStyle,
439+
PropertyNames.BorderBottomColor);
440+
AddLogicalShorthand(PropertyNames.BorderInlineStart, () => new BorderLeftProperty(),
441+
PropertyNames.BorderLeftWidth,
442+
PropertyNames.BorderLeftStyle,
443+
PropertyNames.BorderLeftColor);
444+
AddLogicalShorthand(PropertyNames.BorderInlineEnd, () => new BorderRightProperty(),
445+
PropertyNames.BorderRightWidth,
446+
PropertyNames.BorderRightStyle,
447+
PropertyNames.BorderRightColor);
448+
449+
// Logical two-edge border shorthands (both block/inline edges the same value).
450+
AddLogicalShorthand(PropertyNames.BorderBlock, () => new BorderBlockProperty(),
451+
PropertyNames.BorderTopWidth,
452+
PropertyNames.BorderTopStyle,
453+
PropertyNames.BorderTopColor,
454+
PropertyNames.BorderBottomWidth,
455+
PropertyNames.BorderBottomStyle,
456+
PropertyNames.BorderBottomColor);
457+
AddLogicalShorthand(PropertyNames.BorderInline, () => new BorderInlineProperty(),
458+
PropertyNames.BorderLeftWidth,
459+
PropertyNames.BorderLeftStyle,
460+
PropertyNames.BorderLeftColor,
461+
PropertyNames.BorderRightWidth,
462+
PropertyNames.BorderRightStyle,
463+
PropertyNames.BorderRightColor);
464+
465+
// Logical two-edge border width/style/color shorthands.
466+
AddLogicalShorthand(PropertyNames.BorderBlockWidth, () => new BorderBlockWidthProperty(),
467+
PropertyNames.BorderTopWidth,
468+
PropertyNames.BorderBottomWidth);
469+
AddLogicalShorthand(PropertyNames.BorderBlockStyle, () => new BorderBlockStyleProperty(),
470+
PropertyNames.BorderTopStyle,
471+
PropertyNames.BorderBottomStyle);
472+
AddLogicalShorthand(PropertyNames.BorderBlockColor, () => new BorderBlockColorProperty(),
473+
PropertyNames.BorderTopColor,
474+
PropertyNames.BorderBottomColor);
475+
AddLogicalShorthand(PropertyNames.BorderInlineWidth, () => new BorderInlineWidthProperty(),
476+
PropertyNames.BorderLeftWidth,
477+
PropertyNames.BorderRightWidth);
478+
AddLogicalShorthand(PropertyNames.BorderInlineStyle, () => new BorderInlineStyleProperty(),
479+
PropertyNames.BorderLeftStyle,
480+
PropertyNames.BorderRightStyle);
481+
AddLogicalShorthand(PropertyNames.BorderInlineColor, () => new BorderInlineColorProperty(),
482+
PropertyNames.BorderLeftColor,
483+
PropertyNames.BorderRightColor);
484+
360485
_fonts = _fontsBuilder;
361486

362487
_propertyDescriptors = new Dictionary<string, LonghandCreator>(StringComparer.OrdinalIgnoreCase)
@@ -379,6 +504,14 @@ private void AddShorthand(string name, ShorthandCreator creator, params string[]
379504
_mappingsBuilder.Add(name, longhands);
380505
}
381506

507+
// A logical shorthand: registered for parsing/expansion, but excluded from serialization
508+
// reconstruction (see the _logicalShorthands field comment).
509+
private void AddLogicalShorthand(string name, ShorthandCreator creator, params string[] longhands)
510+
{
511+
AddShorthand(name, creator, longhands);
512+
_logicalShorthands.Add(name);
513+
}
514+
382515
private void AddLonghand(string name, LonghandCreator creator, bool animatable = false, bool font = false)
383516
{
384517
_longhandsBuilder.Add(name, creator);
@@ -458,7 +591,10 @@ public string[] GetLonghands(string name)
458591

459592
public IEnumerable<string> GetShorthands(string name)
460593
{
461-
return from mapping in _mappings where mapping.Value.Contains(name, StringComparison.OrdinalIgnoreCase) select mapping.Key;
594+
return from mapping in _mappings
595+
where !_logicalShorthands.Contains(mapping.Key)
596+
&& mapping.Value.Contains(name, StringComparison.OrdinalIgnoreCase)
597+
select mapping.Key;
462598
}
463599

464600
private delegate Property LonghandCreator();
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
2+
{
3+
internal sealed class BorderBlockColorProperty : ShorthandProperty
4+
{
5+
private static readonly IValueConverter StyleConverter = Converters.CurrentColorConverter.Periodic(
6+
PropertyNames.BorderTopColor, PropertyNames.BorderBottomColor).OrDefault();
7+
8+
internal BorderBlockColorProperty()
9+
: base(PropertyNames.BorderBlockColor, PropertyFlags.Hashless | PropertyFlags.Animatable)
10+
{
11+
}
12+
13+
internal override IValueConverter Converter => StyleConverter;
14+
}
15+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
2+
{
3+
using static Converters;
4+
5+
internal sealed class BorderBlockProperty : ShorthandProperty
6+
{
7+
private static readonly IValueConverter StyleConverter = WithAny(
8+
LineWidthConverter.Option()
9+
.For(PropertyNames.BorderTopWidth, PropertyNames.BorderBottomWidth),
10+
LineStyleConverter.Option()
11+
.For(PropertyNames.BorderTopStyle, PropertyNames.BorderBottomStyle),
12+
CurrentColorConverter.Option()
13+
.For(PropertyNames.BorderTopColor, PropertyNames.BorderBottomColor)
14+
).OrDefault();
15+
16+
internal BorderBlockProperty()
17+
: base(PropertyNames.BorderBlock, PropertyFlags.Animatable)
18+
{
19+
}
20+
21+
internal override IValueConverter Converter => StyleConverter;
22+
}
23+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
2+
{
3+
internal sealed class BorderBlockStyleProperty : ShorthandProperty
4+
{
5+
private static readonly IValueConverter StyleConverter = Converters.LineStyleConverter.Periodic(
6+
PropertyNames.BorderTopStyle, PropertyNames.BorderBottomStyle).OrDefault();
7+
8+
internal BorderBlockStyleProperty()
9+
: base(PropertyNames.BorderBlockStyle)
10+
{
11+
}
12+
13+
internal override IValueConverter Converter => StyleConverter;
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
2+
{
3+
internal sealed class BorderBlockWidthProperty : ShorthandProperty
4+
{
5+
private static readonly IValueConverter StyleConverter = Converters.LineWidthConverter.Periodic(
6+
PropertyNames.BorderTopWidth, PropertyNames.BorderBottomWidth).OrDefault();
7+
8+
internal BorderBlockWidthProperty()
9+
: base(PropertyNames.BorderBlockWidth, PropertyFlags.Animatable)
10+
{
11+
}
12+
13+
internal override IValueConverter Converter => StyleConverter;
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
2+
{
3+
internal sealed class BorderInlineColorProperty : ShorthandProperty
4+
{
5+
private static readonly IValueConverter StyleConverter = Converters.CurrentColorConverter.Periodic(
6+
PropertyNames.BorderLeftColor, PropertyNames.BorderRightColor).OrDefault();
7+
8+
internal BorderInlineColorProperty()
9+
: base(PropertyNames.BorderInlineColor, PropertyFlags.Hashless | PropertyFlags.Animatable)
10+
{
11+
}
12+
13+
internal override IValueConverter Converter => StyleConverter;
14+
}
15+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
2+
{
3+
using static Converters;
4+
5+
internal sealed class BorderInlineProperty : ShorthandProperty
6+
{
7+
private static readonly IValueConverter StyleConverter = WithAny(
8+
LineWidthConverter.Option()
9+
.For(PropertyNames.BorderLeftWidth, PropertyNames.BorderRightWidth),
10+
LineStyleConverter.Option()
11+
.For(PropertyNames.BorderLeftStyle, PropertyNames.BorderRightStyle),
12+
CurrentColorConverter.Option()
13+
.For(PropertyNames.BorderLeftColor, PropertyNames.BorderRightColor)
14+
).OrDefault();
15+
16+
internal BorderInlineProperty()
17+
: base(PropertyNames.BorderInline, PropertyFlags.Animatable)
18+
{
19+
}
20+
21+
internal override IValueConverter Converter => StyleConverter;
22+
}
23+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
2+
{
3+
internal sealed class BorderInlineStyleProperty : ShorthandProperty
4+
{
5+
private static readonly IValueConverter StyleConverter = Converters.LineStyleConverter.Periodic(
6+
PropertyNames.BorderLeftStyle, PropertyNames.BorderRightStyle).OrDefault();
7+
8+
internal BorderInlineStyleProperty()
9+
: base(PropertyNames.BorderInlineStyle)
10+
{
11+
}
12+
13+
internal override IValueConverter Converter => StyleConverter;
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
2+
{
3+
internal sealed class BorderInlineWidthProperty : ShorthandProperty
4+
{
5+
private static readonly IValueConverter StyleConverter = Converters.LineWidthConverter.Periodic(
6+
PropertyNames.BorderLeftWidth, PropertyNames.BorderRightWidth).OrDefault();
7+
8+
internal BorderInlineWidthProperty()
9+
: base(PropertyNames.BorderInlineWidth, PropertyFlags.Animatable)
10+
{
11+
}
12+
13+
internal override IValueConverter Converter => StyleConverter;
14+
}
15+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace TheArtOfDev.HtmlRenderer.Core.CssEngine
2+
{
3+
internal sealed class InsetBlockProperty : ShorthandProperty
4+
{
5+
private static readonly IValueConverter StyleConverter = Converters.AutoLengthOrPercentConverter.Periodic(
6+
PropertyNames.Top, PropertyNames.Bottom)
7+
.OrDefault(Keywords.Auto);
8+
9+
internal InsetBlockProperty()
10+
: base(PropertyNames.InsetBlock)
11+
{
12+
}
13+
14+
internal override IValueConverter Converter => StyleConverter;
15+
}
16+
}

0 commit comments

Comments
 (0)