Skip to content

Commit f280135

Browse files
committed
Support different border radiuses. Add tests.
DEVSIX-1569
1 parent 8d32a78 commit f280135

28 files changed

+1328
-22
lines changed

src/main/java/com/itextpdf/html2pdf/css/CssConstants.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ public class CssConstants {
102102
/** The Constant BORDER_BOTTOM_COLOR. */
103103
public static final String BORDER_BOTTOM_COLOR = "border-bottom-color";
104104

105+
/** The Constant BORDER_BOTTOM_LEFT_RADIUS. */
106+
public static final String BORDER_BOTTOM_LEFT_RADIUS= "border-bottom-left-radius";
107+
108+
/** The Constant BORDER_BOTTOM_RIGHT_RADIUS. */
109+
public static final String BORDER_BOTTOM_RIGHT_RADIUS= "border-bottom-right-radius";
110+
105111
/** The Constant BORDER_BOTTOM_STYLE. */
106112
public static final String BORDER_BOTTOM_STYLE = "border-bottom-style";
107113

@@ -156,6 +162,12 @@ public class CssConstants {
156162
/** The Constant BORDER_TOP_COLOR. */
157163
public static final String BORDER_TOP_COLOR = "border-top-color";
158164

165+
/** The Constant BORDER_TOP_LEFT_RADIUS. */
166+
public static final String BORDER_TOP_LEFT_RADIUS= "border-top-left-radius";
167+
168+
/** The Constant BORDER_TOP_RIGHT_RADIUS. */
169+
public static final String BORDER_TOP_RIGHT_RADIUS= "border-top-right-radius";
170+
159171
/** The Constant BORDER_TOP_STYLE. */
160172
public static final String BORDER_TOP_STYLE = "border-top-style";
161173

src/main/java/com/itextpdf/html2pdf/css/apply/util/BorderStyleApplierUtil.java

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ This file is part of the iText (R) project.
5858
import com.itextpdf.layout.border.OutsetBorder;
5959
import com.itextpdf.layout.border.RidgeBorder;
6060
import com.itextpdf.layout.border.SolidBorder;
61+
import com.itextpdf.layout.property.BorderRadius;
6162
import com.itextpdf.layout.property.Property;
6263
import com.itextpdf.layout.property.UnitValue;
6364
import org.slf4j.Logger;
@@ -69,8 +70,10 @@ This file is part of the iText (R) project.
6970
* Utilities class to apply border styles.
7071
*/
7172
public class BorderStyleApplierUtil {
72-
73-
/** The logger. */
73+
74+
/**
75+
* The logger.
76+
*/
7477
private static final Logger LOGGER = LoggerFactory.getLogger(BorderStyleApplierUtil.class);
7578

7679
/**
@@ -83,8 +86,8 @@ private BorderStyleApplierUtil() {
8386
* Applies borders to an element.
8487
*
8588
* @param cssProps the CSS properties
86-
* @param context the Processor context
87-
* @param element the element
89+
* @param context the Processor context
90+
* @param element the element
8891
*/
8992
public static void applyBorders(Map<String, String> cssProps, ProcessorContext context, IPropertyContainer element) {
9093
float em = CssUtils.parseAbsoluteLength(cssProps.get(CssConstants.FONT_SIZE));
@@ -102,23 +105,35 @@ public static void applyBorders(Map<String, String> cssProps, ProcessorContext c
102105
if (bordersArray[2] != null) {
103106
element.setProperty(Property.BORDER_BOTTOM, bordersArray[2]);
104107
}
105-
108+
106109
if (bordersArray[3] != null) {
107110
element.setProperty(Property.BORDER_LEFT, bordersArray[3]);
108111
}
109112

110-
UnitValue radius = getBorderRadius(cssProps, em, rem);
111-
if (null != radius) {
112-
element.setProperty(Property.BORDER_RADIUS, radius);
113+
BorderRadius[] borderRadii = getBorderRadiiArray(cssProps, em, rem);
114+
if (borderRadii[0] != null) {
115+
element.setProperty(Property.BORDER_TOP_LEFT_RADIUS, borderRadii[0]);
116+
}
117+
118+
if (borderRadii[1] != null) {
119+
element.setProperty(Property.BORDER_TOP_RIGHT_RADIUS, borderRadii[1]);
120+
}
121+
122+
if (borderRadii[2] != null) {
123+
element.setProperty(Property.BORDER_BOTTOM_RIGHT_RADIUS, borderRadii[2]);
124+
}
125+
126+
if (borderRadii[3] != null) {
127+
element.setProperty(Property.BORDER_BOTTOM_LEFT_RADIUS, borderRadii[3]);
113128
}
114129
}
115-
130+
116131
/**
117132
* Gets the array that defines the borders.
118133
*
119134
* @param styles the styles mapping
120-
* @param em the em value
121-
* @param rem the root em value
135+
* @param em the em value
136+
* @param rem the root em value
122137
* @return the borders array
123138
*/
124139
public static Border[] getBordersArray(Map<String, String> styles, float em, float rem) {
@@ -130,15 +145,15 @@ public static Border[] getBordersArray(Map<String, String> styles, float em, flo
130145
Border rightBorder = getCertainBorder(styles.get(CssConstants.BORDER_RIGHT_WIDTH),
131146
styles.get(CssConstants.BORDER_RIGHT_STYLE), getSpecificBorderColorOrDefaultColor(styles, CssConstants.BORDER_RIGHT_COLOR), em, rem);
132147
borders[1] = rightBorder;
133-
148+
134149
Border bottomBorder = getCertainBorder(styles.get(CssConstants.BORDER_BOTTOM_WIDTH),
135150
styles.get(CssConstants.BORDER_BOTTOM_STYLE), getSpecificBorderColorOrDefaultColor(styles, CssConstants.BORDER_BOTTOM_COLOR), em, rem);
136151
borders[2] = bottomBorder;
137152

138153
Border leftBorder = getCertainBorder(styles.get(CssConstants.BORDER_LEFT_WIDTH),
139154
styles.get(CssConstants.BORDER_LEFT_STYLE), getSpecificBorderColorOrDefaultColor(styles, CssConstants.BORDER_LEFT_COLOR), em, rem);
140155
borders[3] = leftBorder;
141-
156+
142157
return borders;
143158
}
144159

@@ -148,8 +163,8 @@ public static Border[] getBordersArray(Map<String, String> styles, float em, flo
148163
* @param borderWidth the border width
149164
* @param borderStyle the border style
150165
* @param borderColor the border color
151-
* @param em the em value
152-
* @param rem the root em value
166+
* @param em the em value
167+
* @param rem the root em value
153168
* @return the border
154169
*/
155170
public static Border getCertainBorder(String borderWidth, String borderStyle, String borderColor, float em, float rem) {
@@ -194,7 +209,7 @@ public static Border getCertainBorder(String borderWidth, String borderStyle, St
194209
} else {
195210
opacity = 0f;
196211
}
197-
} else if (CssConstants.GROOVE.equals(borderStyle) || CssConstants.RIDGE.equals(borderStyle)
212+
} else if (CssConstants.GROOVE.equals(borderStyle) || CssConstants.RIDGE.equals(borderStyle)
198213
|| CssConstants.INSET.equals(borderStyle) || CssConstants.OUTSET.equals(borderStyle)) {
199214
color = new DeviceRgb(212, 208, 200);
200215
}
@@ -235,10 +250,49 @@ public static Border getCertainBorder(String borderWidth, String borderStyle, St
235250
* Gets the array that defines the borders.
236251
*
237252
* @param styles the styles mapping
238-
* @param em the em value
239-
* @param rem the root em value
253+
* @param em the em value
254+
* @param rem the root em value
255+
* @return the borders array
256+
*/
257+
public static BorderRadius[] getBorderRadiiArray(Map<String, String> styles, float em, float rem) {
258+
BorderRadius[] borderRadii = new BorderRadius[4];
259+
260+
BorderRadius borderRadius = null;
261+
UnitValue borderRadiusUV = CssUtils.parseLengthValueToPt(styles.get(CssConstants.BORDER_RADIUS), em, rem);
262+
if (null != borderRadiusUV) {
263+
borderRadius = new BorderRadius(borderRadiusUV);
264+
}
265+
266+
UnitValue[] borderTopLeftRadiusUV = CssUtils.parseSpecificCornerBorderRadius(styles.get(CssConstants.BORDER_TOP_LEFT_RADIUS), em, rem);
267+
borderRadii[0] = null == borderTopLeftRadiusUV
268+
? borderRadius
269+
: new BorderRadius(borderTopLeftRadiusUV[0], borderTopLeftRadiusUV[1]);
270+
UnitValue[] borderTopRightRadiusUV = CssUtils.parseSpecificCornerBorderRadius(styles.get(CssConstants.BORDER_TOP_RIGHT_RADIUS), em, rem);
271+
borderRadii[1] = null == borderTopRightRadiusUV
272+
? borderRadius
273+
: new BorderRadius(borderTopRightRadiusUV[0], borderTopRightRadiusUV[1]);
274+
UnitValue[] borderBottomRightRadiusUV = CssUtils.parseSpecificCornerBorderRadius(styles.get(CssConstants.BORDER_BOTTOM_RIGHT_RADIUS), em, rem);
275+
borderRadii[2] = null == borderBottomRightRadiusUV
276+
? borderRadius
277+
: new BorderRadius(borderBottomRightRadiusUV[0], borderBottomRightRadiusUV[1]);
278+
UnitValue[] borderBottomLeftRadiusUV = CssUtils.parseSpecificCornerBorderRadius(styles.get(CssConstants.BORDER_BOTTOM_LEFT_RADIUS), em, rem);
279+
borderRadii[3] = null == borderBottomLeftRadiusUV
280+
? borderRadius
281+
: new BorderRadius(borderBottomLeftRadiusUV[0], borderBottomLeftRadiusUV[1]);
282+
283+
return borderRadii;
284+
}
285+
286+
/**
287+
* Gets the array that defines the borders.
288+
*
289+
* @param styles the styles mapping
290+
* @param em the em value
291+
* @param rem the root em value
240292
* @return the borders array
293+
* @deprecated use {@link #getBorderRadiiArray(Map, float, float)} instead
241294
*/
295+
@Deprecated
242296
public static UnitValue getBorderRadius(Map<String, String> styles, float em, float rem) {
243297
String borderRadius = styles.get(CssConstants.BORDER_RADIUS);
244298
return CssUtils.parseLengthValueToPt(borderRadius, em, rem);

src/main/java/com/itextpdf/html2pdf/css/resolve/shorthand/ShorthandResolverFactory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ This file is part of the iText (R) project.
4747
import com.itextpdf.html2pdf.css.resolve.shorthand.impl.BorderBottomShorthandResolver;
4848
import com.itextpdf.html2pdf.css.resolve.shorthand.impl.BorderColorShorthandResolver;
4949
import com.itextpdf.html2pdf.css.resolve.shorthand.impl.BorderLeftShorthandResolver;
50+
import com.itextpdf.html2pdf.css.resolve.shorthand.impl.BorderRadiusShorthandResolver;
5051
import com.itextpdf.html2pdf.css.resolve.shorthand.impl.BorderRightShorthandResolver;
5152
import com.itextpdf.html2pdf.css.resolve.shorthand.impl.BorderShorthandResolver;
5253
import com.itextpdf.html2pdf.css.resolve.shorthand.impl.BorderStyleShorthandResolver;
@@ -74,6 +75,7 @@ public class ShorthandResolverFactory {
7475
shorthandResolvers.put(CssConstants.BORDER_BOTTOM, new BorderBottomShorthandResolver());
7576
shorthandResolvers.put(CssConstants.BORDER_COLOR, new BorderColorShorthandResolver());
7677
shorthandResolvers.put(CssConstants.BORDER_LEFT, new BorderLeftShorthandResolver());
78+
shorthandResolvers.put(CssConstants.BORDER_RADIUS, new BorderRadiusShorthandResolver());
7779
shorthandResolvers.put(CssConstants.BORDER_RIGHT, new BorderRightShorthandResolver());
7880
shorthandResolvers.put(CssConstants.BORDER_STYLE, new BorderStyleShorthandResolver());
7981
shorthandResolvers.put(CssConstants.BORDER_TOP, new BorderTopShorthandResolver());
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2017 iText Group NV
4+
Authors: Bruno Lowagie, Paulo Soares, et al.
5+
6+
This program is free software; you can redistribute it and/or modify
7+
it under the terms of the GNU Affero General Public License version 3
8+
as published by the Free Software Foundation with the addition of the
9+
following permission added to Section 15 as permitted in Section 7(a):
10+
FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
11+
ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
12+
OF THIRD PARTY RIGHTS
13+
14+
This program is distributed in the hope that it will be useful, but
15+
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16+
or FITNESS FOR A PARTICULAR PURPOSE.
17+
See the GNU Affero General Public License for more details.
18+
You should have received a copy of the GNU Affero General Public License
19+
along with this program; if not, see http://www.gnu.org/licenses or write to
20+
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21+
Boston, MA, 02110-1301 USA, or download the license from the following URL:
22+
http://itextpdf.com/terms-of-use/
23+
24+
The interactive user interfaces in modified source and object code versions
25+
of this program must display Appropriate Legal Notices, as required under
26+
Section 5 of the GNU Affero General Public License.
27+
28+
In accordance with Section 7(b) of the GNU Affero General Public License,
29+
a covered work must retain the producer line in every PDF that is created
30+
or manipulated using iText.
31+
32+
You can be released from the requirements of the license by purchasing
33+
a commercial license. Buying such a license is mandatory as soon as you
34+
develop commercial activities involving the iText software without
35+
disclosing the source code of your own applications.
36+
These activities include: offering paid services to customers as an ASP,
37+
serving PDFs on the fly in a web application, shipping iText with a closed
38+
source product.
39+
40+
For more information, please contact iText Software Corp. at this
41+
42+
*/
43+
package com.itextpdf.html2pdf.css.resolve.shorthand.impl;
44+
45+
import com.itextpdf.html2pdf.css.CssDeclaration;
46+
import com.itextpdf.html2pdf.css.resolve.shorthand.IShorthandResolver;
47+
import com.itextpdf.io.util.MessageFormatUtil;
48+
49+
import java.util.ArrayList;
50+
import java.util.List;
51+
52+
/**
53+
* Abstract {@link IShorthandResolver} implementation for corners definitions.
54+
*/
55+
public abstract class AbstractCornersShorthandResolver implements IShorthandResolver {
56+
57+
/**
58+
* The template for -bottom-left properties.
59+
*/
60+
private static final String _0_BOTTOM_LEFT_1 = "{0}-bottom-left{1}";
61+
62+
/**
63+
* The template for -bottom-right properties.
64+
*/
65+
private static final String _0_BOTTOM_RIGHT_1 = "{0}-bottom-right{1}";
66+
67+
/**
68+
* The template for -top-left properties.
69+
*/
70+
private static final String _0_TOP_LEFT_1 = "{0}-top-left{1}";
71+
72+
/**
73+
* The template for -top-right properties.
74+
*/
75+
private static final String _0_TOP_RIGHT_1 = "{0}-top-right{1}";
76+
77+
/**
78+
* Gets the prefix of a property.
79+
*
80+
* @return the prefix
81+
*/
82+
protected abstract String getPrefix();
83+
84+
/**
85+
* Gets the postfix of a property.
86+
*
87+
* @return the postfix
88+
*/
89+
protected abstract String getPostfix();
90+
91+
/* (non-Javadoc)
92+
* @see com.itextpdf.html2pdf.css.resolve.shorthand.IShorthandResolver#resolveShorthand(java.lang.String)
93+
*/
94+
@Override
95+
public List<CssDeclaration> resolveShorthand(String shorthandExpression) {
96+
String[] props = shorthandExpression.split("\\s*\\/\\s*");
97+
String[][] properties = new String[props.length][];
98+
for (int i = 0; i < props.length; i++) {
99+
properties[i] = props[i].split("\\s+");
100+
}
101+
102+
String[] resultExpressions = new String[4];
103+
for (int i = 0; i < resultExpressions.length; i++) {
104+
resultExpressions[i] = "";
105+
}
106+
107+
List<CssDeclaration> resolvedDecl = new ArrayList<>();
108+
String topLeftProperty = MessageFormatUtil.format(_0_TOP_LEFT_1, getPrefix(), getPostfix());
109+
String topRightProperty = MessageFormatUtil.format(_0_TOP_RIGHT_1, getPrefix(), getPostfix());
110+
String bottomRightProperty = MessageFormatUtil.format(_0_BOTTOM_RIGHT_1, getPrefix(), getPostfix());
111+
String bottomLeftProperty = MessageFormatUtil.format(_0_BOTTOM_LEFT_1, getPrefix(), getPostfix());
112+
113+
for (int i = 0; i < properties.length; i++) {
114+
if (properties[i].length == 1) {
115+
resultExpressions[0] += properties[i][0] + " ";
116+
resultExpressions[1] += properties[i][0] + " ";
117+
resultExpressions[2] += properties[i][0] + " ";
118+
resultExpressions[3] += properties[i][0] + " ";
119+
} else if (properties[i].length == 2) {
120+
resultExpressions[0] += properties[i][0] + " ";
121+
resultExpressions[1] += properties[i][1] + " ";
122+
resultExpressions[2] += properties[i][0] + " ";
123+
resultExpressions[3] += properties[i][1] + " ";
124+
} else if (properties[i].length == 3) {
125+
resultExpressions[0] += properties[i][0] + " ";
126+
resultExpressions[1] += properties[i][1] + " ";
127+
resultExpressions[2] += properties[i][2] + " ";
128+
resultExpressions[3] += properties[i][1] + " ";
129+
} else if (properties[i].length == 4) {
130+
resultExpressions[0] += properties[i][0] + " ";
131+
resultExpressions[1] += properties[i][1] + " ";
132+
resultExpressions[2] += properties[i][2] + " ";
133+
resultExpressions[3] += properties[i][3] + " ";
134+
}
135+
}
136+
137+
resolvedDecl.add(new CssDeclaration(topLeftProperty, resultExpressions[0]));
138+
resolvedDecl.add(new CssDeclaration(topRightProperty, resultExpressions[1]));
139+
resolvedDecl.add(new CssDeclaration(bottomRightProperty, resultExpressions[2]));
140+
resolvedDecl.add(new CssDeclaration(bottomLeftProperty, resultExpressions[3]));
141+
return resolvedDecl;
142+
}
143+
}

0 commit comments

Comments
 (0)