Skip to content

Commit d5b380e

Browse files
committed
Support property line-height #52
1 parent 4d80693 commit d5b380e

File tree

11 files changed

+88
-37
lines changed

11 files changed

+88
-37
lines changed

examples/Demo/Program.cs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,7 @@ static async Task Main(string[] args)
1717
const string filename = "test.docx";
1818
string html = ResourceHelper.GetString("Resources.CompleteRunTest.html");
1919
if (File.Exists(filename)) File.Delete(filename);
20-
const string preformattedText = @"
21-
^__^
22-
(oo)\_______
23-
(__)\ )\/\
24-
||----w |
25-
|| ||";
2620

27-
html = @$"<pre role='img' aria-label='ASCII COW'>
28-
{preformattedText}</pre>";
2921
using (MemoryStream generatedDocument = new MemoryStream())
3022
{
3123
// Uncomment and comment the second using() to open an existing template document
@@ -53,7 +45,7 @@ static async Task Main(string[] args)
5345
await converter.ParseHtml(html);
5446
mainPart.Document.Save();
5547

56-
//AssertThatOpenXmlDocumentIsValid(package);
48+
AssertThatOpenXmlDocumentIsValid(package);
5749
}
5850

5951
File.WriteAllBytes(filename, generatedDocument.ToArray());

src/Html2OpenXml/Collections/HtmlAttributeCollection.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ public HtmlColor GetColor(string name)
7171
/// Gets an attribute representing an unit: 120px, 10pt, 5em, 20%, ...
7272
/// </summary>
7373
/// <returns>If the attribute is misformed, the <see cref="Unit.IsValid"/> property is set to false.</returns>
74-
public Unit GetUnit(string name)
74+
public Unit GetUnit(string name, UnitMetric defaultMetric = UnitMetric.Unitless)
7575
{
76-
return Unit.Parse(this[name]);
76+
return Unit.Parse(this[name], defaultMetric);
7777
}
7878

7979
/// <summary>
@@ -86,13 +86,13 @@ public Margin GetMargin(string name)
8686
Margin margin = Margin.Parse(this[name]);
8787
Unit u;
8888

89-
u = GetUnit(name + "-top");
89+
u = GetUnit(name + "-top", UnitMetric.Pixel);
9090
if (u.IsValid) margin.Top = u;
91-
u = GetUnit(name + "-right");
91+
u = GetUnit(name + "-right", UnitMetric.Pixel);
9292
if (u.IsValid) margin.Right = u;
93-
u = GetUnit(name + "-bottom");
93+
u = GetUnit(name + "-bottom", UnitMetric.Pixel);
9494
if (u.IsValid) margin.Bottom = u;
95-
u = GetUnit(name + "-left");
95+
u = GetUnit(name + "-left", UnitMetric.Pixel);
9696
if (u.IsValid) margin.Left = u;
9797

9898
return margin;

src/Html2OpenXml/Expressions/BlockElementExpression.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,44 @@ protected override void ComposeStyles (ParsingContext context)
198198

199199
paraProperties.Indentation = indentation;
200200
}
201+
202+
var lineHeight = styleAttributes.GetUnit("line-height");
203+
if (!lineHeight.IsValid
204+
&& "normal".Equals(styleAttributes["line-height"], StringComparison.OrdinalIgnoreCase))
205+
{
206+
// if `normal` is specified, reset any values
207+
lineHeight = new Unit(UnitMetric.Unitless, 1);
208+
}
209+
210+
if (lineHeight.IsValid)
211+
{
212+
if (lineHeight.Type == UnitMetric.Unitless)
213+
{
214+
// auto should be considered as 240ths of a line
215+
// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.spacingbetweenlines.line?view=openxml-3.0.1
216+
paraProperties.SpacingBetweenLines = new() {
217+
LineRule = LineSpacingRuleValues.Auto,
218+
Line = Math.Round(lineHeight.Value * 240).ToString(CultureInfo.InvariantCulture)
219+
};
220+
}
221+
else if (lineHeight.Type == UnitMetric.Percent)
222+
{
223+
// percentage depends on the font size which is hard to determine here
224+
// let's rely this to "auto" behaviour
225+
paraProperties.SpacingBetweenLines = new() {
226+
LineRule = LineSpacingRuleValues.Auto,
227+
Line = Math.Round(lineHeight.Value / 100 * 240).ToString(CultureInfo.InvariantCulture)
228+
};
229+
}
230+
else
231+
{
232+
// twentieths of a point
233+
paraProperties.SpacingBetweenLines = new() {
234+
LineRule = LineSpacingRuleValues.Exact,
235+
Line = Math.Round(lineHeight.ValueInPoint * 20).ToString(CultureInfo.InvariantCulture)
236+
};
237+
}
238+
}
201239
}
202240

203241
/// <summary>

src/Html2OpenXml/Expressions/Table/TableExpression.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ protected override void ComposeStyles (ParsingContext context)
168168
tableProperties.TableStyle = context.DocumentStyle.GetTableStyle(context.DocumentStyle.DefaultStyles.TableStyle);
169169

170170
styleAttributes = node.GetStyles();
171-
var width = styleAttributes.GetUnit("width");
172-
if (!width.IsValid) width = Unit.Parse(node.GetAttribute("width"));
171+
var width = styleAttributes.GetUnit("width", UnitMetric.Pixel);
172+
if (!width.IsValid) width = Unit.Parse(node.GetAttribute("width"), UnitMetric.Pixel);
173173
if (!width.IsValid) width = new Unit(UnitMetric.Percent, 100);
174174

175175
switch (width.Type)

src/Html2OpenXml/Expressions/Table/TableRowExpression.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ protected override void ComposeStyles(ParsingContext context)
102102
{
103103
base.ComposeStyles(context);
104104

105-
Unit unit = styleAttributes!.GetUnit("height");
106-
if (!unit.IsValid) unit = Unit.Parse(rowNode.GetAttribute("height"));
105+
Unit unit = styleAttributes!.GetUnit("height", UnitMetric.Pixel);
106+
if (!unit.IsValid) unit = Unit.Parse(rowNode.GetAttribute("height"), UnitMetric.Pixel);
107107

108108
switch (unit.Type)
109109
{

src/Html2OpenXml/Primitives/Margin.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,28 +57,28 @@ public static Margin Parse(string? str)
5757
{
5858
case 1:
5959
{
60-
Unit all = Unit.Parse(parts[0]);
60+
Unit all = Unit.Parse(parts[0], UnitMetric.Pixel);
6161
return new Margin(all, all, all, all);
6262
}
6363
case 2:
6464
{
65-
Unit u1 = Unit.Parse(parts[0]);
66-
Unit u2 = Unit.Parse(parts[1]);
65+
Unit u1 = Unit.Parse(parts[0], UnitMetric.Pixel);
66+
Unit u2 = Unit.Parse(parts[1], UnitMetric.Pixel);
6767
return new Margin(u1, u2, u1, u2);
6868
}
6969
case 3:
7070
{
71-
Unit u1 = Unit.Parse(parts[0]);
72-
Unit u2 = Unit.Parse(parts[1]);
73-
Unit u3 = Unit.Parse(parts[2]);
71+
Unit u1 = Unit.Parse(parts[0], UnitMetric.Pixel);
72+
Unit u2 = Unit.Parse(parts[1], UnitMetric.Pixel);
73+
Unit u3 = Unit.Parse(parts[2], UnitMetric.Pixel);
7474
return new Margin(u1, u2, u3, u2);
7575
}
7676
case 4:
7777
{
78-
Unit u1 = Unit.Parse(parts[0]);
79-
Unit u2 = Unit.Parse(parts[1]);
80-
Unit u3 = Unit.Parse(parts[2]);
81-
Unit u4 = Unit.Parse(parts[3]);
78+
Unit u1 = Unit.Parse(parts[0], UnitMetric.Pixel);
79+
Unit u2 = Unit.Parse(parts[1], UnitMetric.Pixel);
80+
Unit u3 = Unit.Parse(parts[2], UnitMetric.Pixel);
81+
Unit u4 = Unit.Parse(parts[3], UnitMetric.Pixel);
8282
return new Margin(u1, u2, u3, u4);
8383
}
8484
}

src/Html2OpenXml/Primitives/SideBorder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public static SideBorder Parse(string? str)
8787

8888
internal static Unit ParseWidth(string? borderWidth)
8989
{
90-
Unit bu = Unit.Parse(borderWidth);
90+
Unit bu = Unit.Parse(borderWidth, UnitMetric.Pixel);
9191
if (bu.IsValid)
9292
{
9393
if (bu.Value > 0 && bu.Type == UnitMetric.Pixel)

src/Html2OpenXml/Primitives/Unit.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ readonly struct Unit
3030
private readonly long valueInEmus;
3131

3232

33-
public Unit(UnitMetric type, Double value)
33+
public Unit(UnitMetric type, double value)
3434
{
3535
this.type = type;
3636
this.value = value;
3737
this.valueInEmus = ComputeInEmus(type, value);
3838
}
3939

40-
public static Unit Parse(string? str)
40+
public static Unit Parse(string? str, UnitMetric defaultMetric = UnitMetric.Unitless)
4141
{
4242
if (str == null) return Unit.Empty;
4343

@@ -62,15 +62,15 @@ public static Unit Parse(string? str)
6262
if (digitLength < length - 1)
6363
type = Converter.ToUnitMetric(str.Substring(digitLength + 1).Trim());
6464
else
65-
type = UnitMetric.Pixel;
65+
type = defaultMetric;
6666

6767
string v = str.Substring(0, digitLength + 1);
6868
double value;
6969
try
7070
{
7171
value = Convert.ToDouble(v, CultureInfo.InvariantCulture);
7272

73-
if (value < Int16.MinValue || value > Int16.MaxValue)
73+
if (value < short.MinValue || value > short.MaxValue)
7474
return Unit.Empty;
7575
}
7676
catch (FormatException)
@@ -106,6 +106,7 @@ private static Int64 ComputeInEmus(UnitMetric type, double value)
106106
switch (type)
107107
{
108108
case UnitMetric.Auto:
109+
case UnitMetric.Unitless:
109110
case UnitMetric.Percent: return 0L; // not applicable
110111
case UnitMetric.Emus: return (long) value;
111112
case UnitMetric.Inch: return (long) (value * 914400L);

src/Html2OpenXml/Primitives/UnitMetric.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,7 @@ enum UnitMetric
3434
Emus,
3535

3636
/// <summary>Not convertible to any other units.</summary>
37-
Auto
37+
Auto,
38+
/// <summary>Raw value, not convertible to any other units</summary>
39+
Unitless
3840
}

src/Html2OpenXml/Utilities/Converter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public static Unit ToFontSize(string? htmlSize)
7676
case "xx-large": return new Unit(UnitMetric.Point, 72);
7777
default:
7878
// the font-size is specified in positive half-points
79-
Unit unit = Unit.Parse(htmlSize);
79+
Unit unit = Unit.Parse(htmlSize, UnitMetric.Pixel);
8080
if (!unit.IsValid || unit.Value <= 0)
8181
return Unit.Empty;
8282

@@ -162,7 +162,7 @@ public static BorderValues ToBorderStyle(string? borderStyle)
162162

163163
public static UnitMetric ToUnitMetric(string? type)
164164
{
165-
if (type == null) return UnitMetric.Unknown;
165+
if (type == null) return UnitMetric.Unitless;
166166
return type.ToLowerInvariant() switch
167167
{
168168
"%" => UnitMetric.Percent,

0 commit comments

Comments
 (0)