Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: resolve css variables #2

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,22 @@ public virtual void HtmlStylesConvertingTest11() {
, "font-family: times");
}

[NUnit.Framework.TestCase("cssVariablesTest01.html", "30px", "30px")]
[NUnit.Framework.TestCase("cssVariablesTest02.html", "50px", "30px")]
[NUnit.Framework.TestCase("cssVariablesTest03.html", "35px", "35px")]
public virtual void CssVariablesTest1(string fileName, string expectedMargin, string expectedVarValue) {
Test(fileName, "html body div",
"display: block",
$"--test-var: {expectedVarValue}",
$"margin-top: {expectedMargin}",
$"margin-right: {expectedMargin}",
$"margin-bottom: {expectedMargin}",
$"margin-left: {expectedMargin}",
"font-family: times",
"font-size: 12pt"
);
}

private void ResolveStylesForTree(INode node, ICssResolver cssResolver, CssContext context) {
if (node is IElementNode) {
IElementNode element = (IElementNode)node;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<html>
<head>
<style type="text/css">
div {
--test-var: 30px;
}

div.a {
margin: var(--test-var,40px);
}

div.b {
margin: var(--other-var,50px);
}

div.c {
--test-var: 35px;
}

div.c.d {
margin: var(--test-var,40px);
}
</style>
</head>
<body>
<div class="a">
This is a div text with margin 30px
</div>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<html>
<head>
<style type="text/css">
div {
--test-var: 30px;
}

div.a {
margin: var(--test-var,40px);
}

div.b {
margin: var(--other-var,50px);
}

div.c {
--test-var: 35px;
}

div.c.d {
margin: var(--test-var,40px);
}
</style>
</head>
<body>
<div class="b">
This is a div text with margin 50px
</div>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<html>
<head>
<style type="text/css">
div {
--test-var: 30px;
}

div.a {
margin: var(--test-var,40px);
}

div.b {
margin: var(--other-var,50px);
}

div.c {
--test-var: 35px;
}

div.c.d {
margin: var(--test-var,40px);
}
</style>
</head>
<body>
<div class="c d">
This is a div text with margin 35px
</div>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ You should have received a copy of the GNU Affero General Public License
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using iText.Commons;
using iText.Html2pdf.Attach;
Expand Down Expand Up @@ -51,6 +52,8 @@ namespace iText.Html2pdf.Css.Resolve {
/// interface.
/// </summary>
public class DefaultCssResolver : ICssResolver {
private static readonly Regex CssVarDecl = new Regex(@"^\s*var\(\s*(?<decl>--.*)\)\s*$", RegexOptions.IgnoreCase | RegexOptions.Compiled);

/// <summary>The CSS style sheet.</summary>
private CssStyleSheet cssStyleSheet;

Expand Down Expand Up @@ -199,6 +202,10 @@ private IDictionary<String, String> ResolveStyles(INode element, CssContext cont
keys.Add(entry.Key);
}
}

// Resolve CSS variables
ResolveCssVariables(elementStyles);

foreach (String key in keys) {
elementStyles.Put(key, CssDefaults.GetDefaultValue(key));
}
Expand All @@ -208,6 +215,57 @@ private IDictionary<String, String> ResolveStyles(INode element, CssContext cont
return elementStyles;
}

private static bool IsCssVarDecl(string decl, out string innerDecl) {
if (decl == null) {
innerDecl = null;
return false;
}

var cssVarDecl = CssVarDecl.Match(decl);
if (cssVarDecl.Success) {
innerDecl = cssVarDecl.Groups["decl"].Value;
return true;
}

innerDecl = null;
return false;
}

private static void ResolveCssVariables(IDictionary<string, string> elementStyles) {
var varOverrides = new Dictionary<string, string>();

foreach (KeyValuePair<String, String> entry in elementStyles) {
if (IsCssVarDecl(entry.Value, out var decl)) {
var value = ResolveVariable(decl);
varOverrides.Add(entry.Key, value);
}
continue;

string ResolveVariable(string substring) {
var hasDefault = substring.IndexOf(',');
var varName = hasDefault == -1 ? substring : substring.Substring(0, hasDefault);
var dfltVal = hasDefault == -1 ? null : substring.Substring(hasDefault + 1).Trim();
if (elementStyles.TryGetValue(varName, out var variable)) {
return variable;
}

if (dfltVal is null) {
return null;
}

if (IsCssVarDecl(dfltVal, out var innerDecl)) {
return ResolveVariable(innerDecl);
}

return dfltVal;
}
}

foreach (var varOverride in varOverrides) {
elementStyles.Put(varOverride.Key, varOverride.Value);
}
}

private IDictionary<String, String> ResolveElementsStyles(INode element) {
IList<CssRuleSet> ruleSets = new List<CssRuleSet>();
ruleSets.Add(new CssRuleSet(null, UserAgentCss.GetStyles(element)));
Expand Down