Skip to content

Commit 691a79d

Browse files
committed
Fixes #752, fixes #310, fixes #755, works on #635 - Add property to disable bevels on borders.
Doing so avoids ugly anti-aliasing effects, especially on tables. Property is: -fs-border-rendering: no-bevel and inherits so can be set at the table level to apply to all cells. This commit is a better alternative to the work in #755.
1 parent b87ef1f commit 691a79d

File tree

11 files changed

+236
-70
lines changed

11 files changed

+236
-70
lines changed

openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/CSSName.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,20 @@ public final class CSSName implements Comparable<CSSName> {
219219
new PrimitivePropertyBuilders.BorderCollapse()
220220
);
221221

222+
/**
223+
* If this property is set to no-bevel then borders are rendered without
224+
* bevels. This can be useful to avoid anti-aliasing.
225+
*/
226+
public final static CSSName FS_BORDER_RENDERING =
227+
addProperty(
228+
"-fs-border-rendering",
229+
PRIMITIVE,
230+
"auto",
231+
INHERITS,
232+
new PrimitivePropertyBuilders.FSBorderRendering()
233+
);
234+
235+
222236
/**
223237
* Unique CSSName instance for fictitious property.
224238
*/

openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/constants/IdentValue.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.Map;
2424

2525
import com.openhtmltopdf.css.parser.FSColor;
26+
import com.openhtmltopdf.css.parser.property.PrimitivePropertyBuilders;
2627
import com.openhtmltopdf.css.style.CssContext;
2728
import com.openhtmltopdf.css.style.FSDerivedValue;
2829
import com.openhtmltopdf.util.XRRuntimeException;
@@ -262,6 +263,12 @@ public class IdentValue implements FSDerivedValue {
262263
public static final IdentValue FOOTNOTE = addValue("footnote");
263264
public static final IdentValue FS_FOOTNOTE_BODY = addValue("-fs-footnote-body");
264265

266+
/**
267+
* Value for the -fs-border-rendering property.
268+
* See {@link CSSName#FS_BORDER_RENDERING}
269+
*/
270+
public static final IdentValue NO_BEVEL = addValue("no-bevel");
271+
265272
/**
266273
* Constructor for the IdentValue object
267274
*

openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/parser/property/PrimitivePropertyBuilders.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.*;
2828

2929
public class PrimitivePropertyBuilders {
30+
3031
// none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset
3132
public static final BitSet BORDER_STYLES = setFor(
3233
new IdentValue[] { IdentValue.NONE, IdentValue.HIDDEN, IdentValue.DOTTED,
@@ -112,7 +113,7 @@ public class PrimitivePropertyBuilders {
112113
public static final PropertyBuilder MARGIN = new LengthLikeWithAuto();
113114
public static final PropertyBuilder PADDING = new NonNegativeLengthLike();
114115

115-
static BitSet setFor(IdentValue[] values) {
116+
static BitSet setFor(IdentValue... values) {
116117
BitSet result = new BitSet(IdentValue.getIdentCount());
117118
for (int i = 0; i < values.length; i++) {
118119
IdentValue ident = values[i];
@@ -530,6 +531,16 @@ protected BitSet getAllowed() {
530531
}
531532
}
532533

534+
public static class FSBorderRendering extends SingleIdent {
535+
final BitSet ALLOWED = setFor(IdentValue.AUTO, IdentValue.NO_BEVEL);
536+
537+
@Override
538+
protected BitSet getAllowed() {
539+
return ALLOWED;
540+
}
541+
}
542+
543+
533544
public static class BorderTopColor extends GenericColor {
534545
}
535546

openhtmltopdf-core/src/main/java/com/openhtmltopdf/css/style/derived/BorderPropertySet.java

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,11 @@
99
import com.openhtmltopdf.css.style.CssContext;
1010
import com.openhtmltopdf.newtable.CollapsedBorderValue;
1111

12-
/**
13-
* Created by IntelliJ IDEA.
14-
* User: patrick
15-
* Date: Oct 21, 2005
16-
* Time: 3:24:04 PM
17-
* To change this template use File | Settings | File Templates.
18-
*/
1912
public class BorderPropertySet extends RectPropertySet {
20-
public static final BorderPropertySet EMPTY_BORDER = new BorderPropertySet(0.0f, 0.0f, 0.0f, 0.0f);
21-
13+
public static final BorderPropertySet EMPTY_BORDER = new BorderPropertySet(true, 0.0f, 0.0f, 0.0f, 0.0f);
14+
15+
private boolean _allowBevel;
16+
2217
private IdentValue _topStyle;
2318
private IdentValue _rightStyle;
2419
private IdentValue _bottomStyle;
@@ -34,8 +29,9 @@ public class BorderPropertySet extends RectPropertySet {
3429
private BorderRadiusCorner _bottomRight;
3530
private BorderRadiusCorner _bottomLeft;
3631

37-
public BorderPropertySet(BorderPropertySet border) {
38-
this(border.top(), border.right(), border.bottom(), border.left());
32+
private BorderPropertySet(BorderPropertySet border) {
33+
this(border.isBevelAllowed(), border.top(), border.right(), border.bottom(), border.left());
34+
3935
this._topStyle = border.topStyle();
4036
this._rightStyle = border.rightStyle();
4137
this._bottomStyle = border.bottomStyle();
@@ -45,13 +41,15 @@ public BorderPropertySet(BorderPropertySet border) {
4541
this._rightColor = border.rightColor();
4642
this._bottomColor = border.bottomColor();
4743
this._leftColor = border.leftColor();
48-
44+
4945
this._topLeft = border._topLeft;
5046
this._topRight = border._topRight;
5147
this._bottomLeft = border._bottomLeft;
5248
this._bottomRight = border._bottomRight;
5349
}
54-
public BorderPropertySet(
50+
51+
private BorderPropertySet(
52+
boolean allowBevel,
5553
float top,
5654
float right,
5755
float bottom,
@@ -61,45 +59,52 @@ public BorderPropertySet(
6159
BorderRadiusCorner bottomRightCorner,
6260
BorderRadiusCorner bottomLeftCorner
6361
) {
62+
this._allowBevel = allowBevel;
63+
6464
this._top = top;
6565
this._right = right;
6666
this._bottom = bottom;
6767
this._left = left;
68-
68+
6969
this._topLeft = topLeftCorner;
7070
this._topRight = topRightCorner;
7171
this._bottomLeft = bottomLeftCorner;
7272
this._bottomRight = bottomRightCorner;
7373
}
7474

7575
public BorderPropertySet(
76+
boolean allowBevel,
7677
float top,
7778
float right,
7879
float bottom,
7980
float left
8081
) {
82+
this._allowBevel = allowBevel;
83+
8184
this._top = top;
8285
this._right = right;
8386
this._bottom = bottom;
8487
this._left = left;
85-
88+
8689
this._topLeft = new BorderRadiusCorner();
8790
this._topRight = new BorderRadiusCorner();
8891
this._bottomLeft = new BorderRadiusCorner();
8992
this._bottomRight = new BorderRadiusCorner();
9093
}
91-
94+
9295
public BorderPropertySet(
96+
boolean allowBevel,
9397
CollapsedBorderValue top,
9498
CollapsedBorderValue right,
9599
CollapsedBorderValue bottom,
96100
CollapsedBorderValue left
97101
) {
98-
this( top.width(),
102+
this(allowBevel,
103+
top.width(),
99104
right.width(),
100105
bottom.width(),
101106
left.width());
102-
107+
103108
this._topStyle = top.style();
104109
this._rightStyle = right.style();
105110
this._bottomStyle = bottom.style();
@@ -108,8 +113,8 @@ public BorderPropertySet(
108113
this._topColor = top.color();
109114
this._rightColor = right.color();
110115
this._bottomColor = bottom.color();
111-
this._leftColor = left.color();
112-
116+
this._leftColor = left.color();
117+
113118
this._topLeft = new BorderRadiusCorner();
114119
this._topRight = new BorderRadiusCorner();
115120
this._bottomLeft = new BorderRadiusCorner();
@@ -120,6 +125,8 @@ private BorderPropertySet(
120125
CalculatedStyle style,
121126
CssContext ctx
122127
) {
128+
_allowBevel = style.isIdent(CSSName.FS_BORDER_RENDERING, IdentValue.AUTO);
129+
123130
_top = ( style.isIdent(CSSName.BORDER_TOP_STYLE, IdentValue.NONE) ||
124131
style.isIdent(CSSName.BORDER_TOP_STYLE, IdentValue.HIDDEN)
125132
?
@@ -136,7 +143,7 @@ private BorderPropertySet(
136143
style.isIdent(CSSName.BORDER_LEFT_STYLE, IdentValue.HIDDEN)
137144
?
138145
0 : style.getFloatPropertyProportionalHeight(CSSName.BORDER_LEFT_WIDTH, 0, ctx));
139-
146+
140147
_topColor = style.asColor(CSSName.BORDER_TOP_COLOR);
141148
_rightColor = style.asColor(CSSName.BORDER_RIGHT_COLOR);
142149
_bottomColor = style.asColor(CSSName.BORDER_BOTTOM_COLOR);
@@ -146,12 +153,7 @@ private BorderPropertySet(
146153
_rightStyle = style.getIdent(CSSName.BORDER_RIGHT_STYLE);
147154
_bottomStyle = style.getIdent(CSSName.BORDER_BOTTOM_STYLE);
148155
_leftStyle = style.getIdent(CSSName.BORDER_LEFT_STYLE);
149-
/*
150-
_topLeft = new BorderRadiusCorner(style.valueByName(CSSName.BORDER_TOP_LEFT_RADIUS), ctx);
151-
_topRight = new BorderRadiusCorner(style.valueByName(CSSName.BORDER_TOP_RIGHT_RADIUS), ctx);
152-
_bottomLeft = new BorderRadiusCorner(style.valueByName(CSSName.BORDER_BOTTOM_LEFT_RADIUS), ctx);
153-
_bottomRight = new BorderRadiusCorner(style.valueByName(CSSName.BORDER_BOTTOM_RIGHT_RADIUS), ctx);
154-
*/
156+
155157
_topLeft = new BorderRadiusCorner(CSSName.BORDER_TOP_LEFT_RADIUS, style, ctx);
156158
_topRight = new BorderRadiusCorner(CSSName.BORDER_TOP_RIGHT_RADIUS, style, ctx);
157159
_bottomLeft = new BorderRadiusCorner(CSSName.BORDER_BOTTOM_LEFT_RADIUS, style, ctx);
@@ -200,6 +202,13 @@ public String toString() {
200202
return "BorderPropertySet[top=" + _top + ",right=" + _right + ",bottom=" + _bottom + ",left=" + _left + "]";
201203
}
202204

205+
/**
206+
* See {@link CSSName#FS_BORDER_RENDERING}
207+
*/
208+
public boolean isBevelAllowed() {
209+
return this._allowBevel;
210+
}
211+
203212
public boolean noTop() {
204213
return this._topStyle == IdentValue.NONE || (int) _top == 0;
205214
}
@@ -247,16 +256,16 @@ public FSColor bottomColor() {
247256
public FSColor leftColor() {
248257
return _leftColor;
249258
}
250-
259+
251260
public boolean hasHidden() {
252261
return _topStyle == IdentValue.HIDDEN || _rightStyle == IdentValue.HIDDEN ||
253262
_bottomStyle == IdentValue.HIDDEN || _leftStyle == IdentValue.HIDDEN;
254-
}
255-
263+
}
264+
256265
public boolean hasBorderRadius() {
257266
return getTopLeft().hasRadius() || getTopRight().hasRadius() || getBottomLeft().hasRadius() || getBottomRight().hasRadius();
258267
}
259-
268+
260269
public BorderRadiusCorner getBottomRight() {
261270
return _bottomRight;
262271
}
@@ -288,10 +297,10 @@ public BorderRadiusCorner getTopLeft() {
288297
public void setTopLeft(BorderRadiusCorner topLeft) {
289298
this._topLeft = topLeft;
290299
}
291-
300+
292301
public BorderPropertySet normalizedInstance(Rectangle bounds) {
293302
float factor = 1;
294-
303+
295304
// top
296305
factor = Math.min(factor, bounds.width / getSideWidth(_topLeft, _topRight, bounds.width));
297306
// bottom
@@ -300,36 +309,32 @@ public BorderPropertySet normalizedInstance(Rectangle bounds) {
300309
factor = Math.min(factor, bounds.height / getSideWidth(_topRight, _bottomRight, bounds.height));
301310
// left
302311
factor = Math.min(factor, bounds.height / getSideWidth(_bottomLeft, _bottomRight, bounds.height));
303-
304-
BorderPropertySet newPropSet = new BorderPropertySet(_top, _right, _bottom, _left,
312+
313+
BorderPropertySet newPropSet = new BorderPropertySet(true, _top, _right, _bottom, _left,
305314
new BorderRadiusCorner(factor*_topLeft.getMaxLeft(bounds.height), factor*_topLeft.getMaxRight(bounds.width)),
306315
new BorderRadiusCorner(factor*_topRight.getMaxLeft(bounds.width), factor*_topRight.getMaxRight(bounds.height)),
307316
new BorderRadiusCorner(factor*_bottomRight.getMaxLeft(bounds.height), factor*_bottomRight.getMaxRight(bounds.width)),
308317
new BorderRadiusCorner(factor*_bottomLeft.getMaxLeft(bounds.width), factor*_bottomLeft.getMaxRight(bounds.height)));
309-
318+
310319
newPropSet._topColor = _topColor;
311320
newPropSet._rightColor = _rightColor;
312321
newPropSet._bottomColor = _bottomColor;
313322
newPropSet._leftColor = _leftColor;
314-
323+
315324
newPropSet._topStyle = _topStyle;
316325
newPropSet._rightStyle = _rightStyle;
317326
newPropSet._bottomStyle = _bottomStyle;
318327
newPropSet._leftStyle = _leftStyle;
319-
328+
320329
return newPropSet;
321330
}
322331

323332
/**
324-
* helper function for normalizeBorderRadius. Gets the max side width for each of the corners or the side width whichever is larger
325-
* @param left
326-
* @param right
327-
* @param sideWidth
328-
* @return
333+
* Helper function for normalizeBorderRadius. Gets the max side width for each
334+
* of the corners or the side width whichever is larger.
329335
*/
330336
private float getSideWidth(BorderRadiusCorner left, BorderRadiusCorner right, float sideWidth) {
331337
return Math.max(sideWidth, left.getMaxRight(sideWidth) + right.getMaxLeft(sideWidth));
332338
}
333339

334340
}
335-

openhtmltopdf-core/src/main/java/com/openhtmltopdf/newtable/TableCellBox.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,19 @@ public void calcCollapsedBorder(CssContext c) {
106106
CollapsedBorderValue right = collapsedRightBorder(c);
107107
CollapsedBorderValue bottom = collapsedBottomBorder(c);
108108
CollapsedBorderValue left = collapsedLeftBorder(c);
109-
110-
_collapsedPaintingBorder = new BorderPropertySet(top, right, bottom, left);
111-
109+
110+
boolean allowBevel = getStyle().isIdent(CSSName.FS_BORDER_RENDERING, IdentValue.AUTO);
111+
112+
_collapsedPaintingBorder = new BorderPropertySet(allowBevel, top, right, bottom, left);
113+
112114
// Give the extra pixel to top and left.
113115
top.setWidth((top.width()+1)/2);
114116
right.setWidth(right.width()/2);
115117
bottom.setWidth(bottom.width()/2);
116118
left.setWidth((left.width()+1)/2);
117-
118-
_collapsedLayoutBorder = new BorderPropertySet(top, right, bottom, left);
119-
119+
120+
_collapsedLayoutBorder = new BorderPropertySet(allowBevel, top, right, bottom, left);
121+
120122
_collapsedBorderTop = top;
121123
_collapsedBorderRight = right;
122124
_collapsedBorderBottom = bottom;

0 commit comments

Comments
 (0)