|
@@ -11,10 +11,12 @@ public struct StyleContext
|
|
public SvgProperty<SvgNumericUnit> StrokeWidth { get; }
|
|
public SvgProperty<SvgNumericUnit> StrokeWidth { get; }
|
|
public SvgProperty<SvgColorUnit> Stroke { get; }
|
|
public SvgProperty<SvgColorUnit> Stroke { get; }
|
|
public SvgProperty<SvgColorUnit> Fill { get; }
|
|
public SvgProperty<SvgColorUnit> Fill { get; }
|
|
|
|
+ public SvgProperty<SvgNumericUnit> FillOpacity { get; }
|
|
public SvgProperty<SvgTransformUnit> Transform { get; }
|
|
public SvgProperty<SvgTransformUnit> Transform { get; }
|
|
public SvgProperty<SvgEnumUnit<SvgStrokeLineCap>> StrokeLineCap { get; }
|
|
public SvgProperty<SvgEnumUnit<SvgStrokeLineCap>> StrokeLineCap { get; }
|
|
public SvgProperty<SvgEnumUnit<SvgStrokeLineJoin>> StrokeLineJoin { get; }
|
|
public SvgProperty<SvgEnumUnit<SvgStrokeLineJoin>> StrokeLineJoin { get; }
|
|
public SvgProperty<SvgNumericUnit> Opacity { get; }
|
|
public SvgProperty<SvgNumericUnit> Opacity { get; }
|
|
|
|
+ public SvgProperty<SvgStyleUnit> InlineStyle { get; set; }
|
|
public VecD ViewboxOrigin { get; set; }
|
|
public VecD ViewboxOrigin { get; set; }
|
|
|
|
|
|
public StyleContext()
|
|
public StyleContext()
|
|
@@ -22,78 +24,89 @@ public struct StyleContext
|
|
StrokeWidth = new("stroke-width");
|
|
StrokeWidth = new("stroke-width");
|
|
Stroke = new("stroke");
|
|
Stroke = new("stroke");
|
|
Fill = new("fill");
|
|
Fill = new("fill");
|
|
|
|
+ FillOpacity = new("fill-opacity");
|
|
Fill.Unit = new SvgColorUnit?(new SvgColorUnit("black"));
|
|
Fill.Unit = new SvgColorUnit?(new SvgColorUnit("black"));
|
|
Transform = new("transform");
|
|
Transform = new("transform");
|
|
StrokeLineCap = new("stroke-linecap");
|
|
StrokeLineCap = new("stroke-linecap");
|
|
StrokeLineJoin = new("stroke-linejoin");
|
|
StrokeLineJoin = new("stroke-linejoin");
|
|
Opacity = new("opacity");
|
|
Opacity = new("opacity");
|
|
|
|
+ InlineStyle = new("style");
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public StyleContext(SvgDocument document)
|
|
public StyleContext(SvgDocument document)
|
|
{
|
|
{
|
|
- StrokeWidth = document.StrokeWidth;
|
|
|
|
- Stroke = document.Stroke;
|
|
|
|
- Fill = document.Fill;
|
|
|
|
- Transform = document.Transform;
|
|
|
|
- StrokeLineCap = document.StrokeLineCap;
|
|
|
|
- StrokeLineJoin = document.StrokeLineJoin;
|
|
|
|
- Opacity = document.Opacity;
|
|
|
|
|
|
+ StrokeWidth = FallbackToCssStyle(document.StrokeWidth, document.Style);
|
|
|
|
+ Stroke = FallbackToCssStyle(document.Stroke, document.Style);
|
|
|
|
+ Fill = FallbackToCssStyle(document.Fill, document.Style, new SvgColorUnit("black"));
|
|
|
|
+ FillOpacity = FallbackToCssStyle(document.FillOpacity, document.Style);
|
|
|
|
+ Transform = FallbackToCssStyle(document.Transform, document.Style, new SvgTransformUnit(Matrix3X3.Identity));
|
|
|
|
+ StrokeLineCap = FallbackToCssStyle(document.StrokeLineCap, document.Style);
|
|
|
|
+ StrokeLineJoin = FallbackToCssStyle(document.StrokeLineJoin, document.Style);
|
|
|
|
+ Opacity = FallbackToCssStyle(document.Opacity, document.Style);
|
|
ViewboxOrigin = new VecD(
|
|
ViewboxOrigin = new VecD(
|
|
document.ViewBox.Unit.HasValue ? -document.ViewBox.Unit.Value.Value.X : 0,
|
|
document.ViewBox.Unit.HasValue ? -document.ViewBox.Unit.Value.Value.X : 0,
|
|
document.ViewBox.Unit.HasValue ? -document.ViewBox.Unit.Value.Value.Y : 0);
|
|
document.ViewBox.Unit.HasValue ? -document.ViewBox.Unit.Value.Value.Y : 0);
|
|
|
|
+ InlineStyle = document.Style;
|
|
}
|
|
}
|
|
|
|
|
|
public StyleContext WithElement(SvgElement element)
|
|
public StyleContext WithElement(SvgElement element)
|
|
{
|
|
{
|
|
StyleContext styleContext = Copy();
|
|
StyleContext styleContext = Copy();
|
|
|
|
|
|
|
|
+ styleContext.InlineStyle = MergeInlineStyle(element.Style, InlineStyle);
|
|
|
|
+
|
|
if (element is ITransformable transformableElement)
|
|
if (element is ITransformable transformableElement)
|
|
{
|
|
{
|
|
if (styleContext.Transform.Unit == null)
|
|
if (styleContext.Transform.Unit == null)
|
|
{
|
|
{
|
|
- styleContext.Transform.Unit = transformableElement.Transform.Unit;
|
|
|
|
|
|
+ styleContext.Transform.Unit =
|
|
|
|
+ FallbackToCssStyle(transformableElement.Transform, styleContext.Transform, styleContext.InlineStyle)
|
|
|
|
+ .Unit;
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
styleContext.Transform.Unit = new SvgTransformUnit(
|
|
styleContext.Transform.Unit = new SvgTransformUnit(
|
|
styleContext.Transform.Unit.Value.MatrixValue.Concat(
|
|
styleContext.Transform.Unit.Value.MatrixValue.Concat(
|
|
- transformableElement.Transform.Unit?.MatrixValue ?? Matrix3X3.Identity));
|
|
|
|
|
|
+ FallbackToCssStyle(transformableElement.Transform, styleContext.InlineStyle).Unit
|
|
|
|
+ ?.MatrixValue ??
|
|
|
|
+ Matrix3X3.Identity));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (element is IFillable { Fill.Unit: not null } fillableElement)
|
|
|
|
|
|
+ if (element is IFillable fillableElement)
|
|
{
|
|
{
|
|
- styleContext.Fill.Unit = fillableElement.Fill.Unit;
|
|
|
|
|
|
+ styleContext.Fill.Unit = FallbackToCssStyle(fillableElement.Fill, styleContext.Fill,
|
|
|
|
+ styleContext.InlineStyle, new SvgColorUnit("black")).Unit;
|
|
|
|
+ styleContext.FillOpacity.Unit =
|
|
|
|
+ FallbackToCssStyle(fillableElement.FillOpacity, styleContext.FillOpacity, styleContext.InlineStyle)
|
|
|
|
+ .Unit;
|
|
}
|
|
}
|
|
|
|
|
|
if (element is IStrokable strokableElement)
|
|
if (element is IStrokable strokableElement)
|
|
{
|
|
{
|
|
- if (strokableElement.Stroke.Unit != null)
|
|
|
|
- {
|
|
|
|
- styleContext.Stroke.Unit = strokableElement.Stroke.Unit;
|
|
|
|
- }
|
|
|
|
|
|
+ styleContext.Stroke.Unit =
|
|
|
|
+ FallbackToCssStyle(strokableElement.Stroke, styleContext.Stroke, styleContext.InlineStyle).Unit;
|
|
|
|
|
|
- if (strokableElement.StrokeWidth.Unit != null)
|
|
|
|
- {
|
|
|
|
- styleContext.StrokeWidth.Unit = strokableElement.StrokeWidth.Unit;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (strokableElement.StrokeLineCap.Unit != null)
|
|
|
|
- {
|
|
|
|
- styleContext.StrokeLineCap.Unit = strokableElement.StrokeLineCap.Unit;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (strokableElement.StrokeLineJoin.Unit != null)
|
|
|
|
- {
|
|
|
|
- styleContext.StrokeLineJoin.Unit = strokableElement.StrokeLineJoin.Unit;
|
|
|
|
- }
|
|
|
|
|
|
+ styleContext.StrokeWidth.Unit =
|
|
|
|
+ FallbackToCssStyle(strokableElement.StrokeWidth, styleContext.StrokeWidth, styleContext.InlineStyle)
|
|
|
|
+ .Unit;
|
|
|
|
+
|
|
|
|
+ styleContext.StrokeLineCap.Unit =
|
|
|
|
+ FallbackToCssStyle(strokableElement.StrokeLineCap, styleContext.StrokeLineCap, styleContext.InlineStyle)
|
|
|
|
+ .Unit;
|
|
|
|
+
|
|
|
|
+ styleContext.StrokeLineJoin.Unit =
|
|
|
|
+ FallbackToCssStyle(strokableElement.StrokeLineJoin, styleContext.StrokeLineJoin,
|
|
|
|
+ styleContext.InlineStyle).Unit;
|
|
}
|
|
}
|
|
|
|
|
|
- if(element is IOpacity opacityElement)
|
|
|
|
|
|
+ if (element is IOpacity opacityElement)
|
|
{
|
|
{
|
|
- styleContext.Opacity.Unit = opacityElement.Opacity.Unit;
|
|
|
|
|
|
+ styleContext.Opacity.Unit =
|
|
|
|
+ FallbackToCssStyle(opacityElement.Opacity, styleContext.Opacity, styleContext.InlineStyle).Unit;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
return styleContext;
|
|
return styleContext;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -115,6 +128,11 @@ public struct StyleContext
|
|
styleContext.Fill.Unit = Fill.Unit;
|
|
styleContext.Fill.Unit = Fill.Unit;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (FillOpacity.Unit != null)
|
|
|
|
+ {
|
|
|
|
+ styleContext.FillOpacity.Unit = FillOpacity.Unit;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (Transform.Unit != null)
|
|
if (Transform.Unit != null)
|
|
{
|
|
{
|
|
styleContext.Transform.Unit = Transform.Unit;
|
|
styleContext.Transform.Unit = Transform.Unit;
|
|
@@ -137,6 +155,71 @@ public struct StyleContext
|
|
|
|
|
|
styleContext.ViewboxOrigin = ViewboxOrigin;
|
|
styleContext.ViewboxOrigin = ViewboxOrigin;
|
|
|
|
|
|
|
|
+ if (InlineStyle.Unit != null)
|
|
|
|
+ {
|
|
|
|
+ styleContext.InlineStyle.Unit = InlineStyle.Unit;
|
|
|
|
+ }
|
|
|
|
+
|
|
return styleContext;
|
|
return styleContext;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ private SvgProperty<TUnit>? FallbackToCssStyle<TUnit>(
|
|
|
|
+ SvgProperty<TUnit> property,
|
|
|
|
+ SvgProperty<SvgStyleUnit> inlineStyle, TUnit? fallback = null) where TUnit : struct, ISvgUnit
|
|
|
|
+ {
|
|
|
|
+ if (property.Unit != null)
|
|
|
|
+ {
|
|
|
|
+ return property;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SvgStyleUnit? style = inlineStyle.Unit;
|
|
|
|
+ return style?.TryGetStyleFor<SvgProperty<TUnit>, TUnit>(property.SvgName)
|
|
|
|
+ ?? (fallback.HasValue
|
|
|
|
+ ? new SvgProperty<TUnit>(property.SvgName) { Unit = fallback.Value }
|
|
|
|
+ : new SvgProperty<TUnit>(property.SvgName));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private SvgProperty<TUnit>? FallbackToCssStyle<TUnit>(
|
|
|
|
+ SvgProperty<TUnit> property,
|
|
|
|
+ SvgProperty<TUnit> parentStyleProperty,
|
|
|
|
+ SvgProperty<SvgStyleUnit> inlineStyle, TUnit? fallback = null) where TUnit : struct, ISvgUnit
|
|
|
|
+ {
|
|
|
|
+ if (property.Unit != null)
|
|
|
|
+ {
|
|
|
|
+ return property;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SvgStyleUnit? style = inlineStyle.Unit;
|
|
|
|
+ var styleProp = style?.TryGetStyleFor<SvgProperty<TUnit>, TUnit>(property.SvgName);
|
|
|
|
+ if (styleProp != null) return styleProp;
|
|
|
|
+ if(parentStyleProperty.Unit != null)
|
|
|
|
+ {
|
|
|
|
+ return parentStyleProperty;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return (fallback.HasValue
|
|
|
|
+ ? new SvgProperty<TUnit>(property.SvgName) { Unit = fallback.Value }
|
|
|
|
+ : new SvgProperty<TUnit>(property.SvgName));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private SvgProperty<SvgStyleUnit> MergeInlineStyle(SvgProperty<SvgStyleUnit> elementStyle,
|
|
|
|
+ SvgProperty<SvgStyleUnit> parentStyle)
|
|
|
|
+ {
|
|
|
|
+ SvgStyleUnit? elementStyleUnit = elementStyle.Unit;
|
|
|
|
+ SvgStyleUnit? parentStyleUnit = parentStyle.Unit;
|
|
|
|
+
|
|
|
|
+ if (elementStyleUnit == null)
|
|
|
|
+ {
|
|
|
|
+ return parentStyle;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (parentStyleUnit == null)
|
|
|
|
+ {
|
|
|
|
+ return elementStyle;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SvgStyleUnit style = parentStyleUnit.Value.MergeWith(elementStyleUnit.Value);
|
|
|
|
+ return new SvgProperty<SvgStyleUnit>("style") { Unit = style };
|
|
|
|
+ }
|
|
}
|
|
}
|