Skip to content

Commit

Permalink
Fixes #752, fixes #310, fixes #755, works on #635 - Add property to d…
Browse files Browse the repository at this point in the history
…isable 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.
  • Loading branch information
danfickle committed Sep 10, 2021
1 parent b87ef1f commit 691a79d
Show file tree
Hide file tree
Showing 11 changed files with 236 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,20 @@ public final class CSSName implements Comparable<CSSName> {
new PrimitivePropertyBuilders.BorderCollapse()
);

/**
* If this property is set to no-bevel then borders are rendered without
* bevels. This can be useful to avoid anti-aliasing.
*/
public final static CSSName FS_BORDER_RENDERING =
addProperty(
"-fs-border-rendering",
PRIMITIVE,
"auto",
INHERITS,
new PrimitivePropertyBuilders.FSBorderRendering()
);


/**
* Unique CSSName instance for fictitious property.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Map;

import com.openhtmltopdf.css.parser.FSColor;
import com.openhtmltopdf.css.parser.property.PrimitivePropertyBuilders;
import com.openhtmltopdf.css.style.CssContext;
import com.openhtmltopdf.css.style.FSDerivedValue;
import com.openhtmltopdf.util.XRRuntimeException;
Expand Down Expand Up @@ -262,6 +263,12 @@ public class IdentValue implements FSDerivedValue {
public static final IdentValue FOOTNOTE = addValue("footnote");
public static final IdentValue FS_FOOTNOTE_BODY = addValue("-fs-footnote-body");

/**
* Value for the -fs-border-rendering property.
* See {@link CSSName#FS_BORDER_RENDERING}
*/
public static final IdentValue NO_BEVEL = addValue("no-bevel");

/**
* Constructor for the IdentValue object
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.*;

public class PrimitivePropertyBuilders {

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

static BitSet setFor(IdentValue[] values) {
static BitSet setFor(IdentValue... values) {
BitSet result = new BitSet(IdentValue.getIdentCount());
for (int i = 0; i < values.length; i++) {
IdentValue ident = values[i];
Expand Down Expand Up @@ -530,6 +531,16 @@ protected BitSet getAllowed() {
}
}

public static class FSBorderRendering extends SingleIdent {
final BitSet ALLOWED = setFor(IdentValue.AUTO, IdentValue.NO_BEVEL);

@Override
protected BitSet getAllowed() {
return ALLOWED;
}
}


public static class BorderTopColor extends GenericColor {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,11 @@
import com.openhtmltopdf.css.style.CssContext;
import com.openhtmltopdf.newtable.CollapsedBorderValue;

/**
* Created by IntelliJ IDEA.
* User: patrick
* Date: Oct 21, 2005
* Time: 3:24:04 PM
* To change this template use File | Settings | File Templates.
*/
public class BorderPropertySet extends RectPropertySet {
public static final BorderPropertySet EMPTY_BORDER = new BorderPropertySet(0.0f, 0.0f, 0.0f, 0.0f);

public static final BorderPropertySet EMPTY_BORDER = new BorderPropertySet(true, 0.0f, 0.0f, 0.0f, 0.0f);

private boolean _allowBevel;

private IdentValue _topStyle;
private IdentValue _rightStyle;
private IdentValue _bottomStyle;
Expand All @@ -34,8 +29,9 @@ public class BorderPropertySet extends RectPropertySet {
private BorderRadiusCorner _bottomRight;
private BorderRadiusCorner _bottomLeft;

public BorderPropertySet(BorderPropertySet border) {
this(border.top(), border.right(), border.bottom(), border.left());
private BorderPropertySet(BorderPropertySet border) {
this(border.isBevelAllowed(), border.top(), border.right(), border.bottom(), border.left());

this._topStyle = border.topStyle();
this._rightStyle = border.rightStyle();
this._bottomStyle = border.bottomStyle();
Expand All @@ -45,13 +41,15 @@ public BorderPropertySet(BorderPropertySet border) {
this._rightColor = border.rightColor();
this._bottomColor = border.bottomColor();
this._leftColor = border.leftColor();

this._topLeft = border._topLeft;
this._topRight = border._topRight;
this._bottomLeft = border._bottomLeft;
this._bottomRight = border._bottomRight;
}
public BorderPropertySet(

private BorderPropertySet(
boolean allowBevel,
float top,
float right,
float bottom,
Expand All @@ -61,45 +59,52 @@ public BorderPropertySet(
BorderRadiusCorner bottomRightCorner,
BorderRadiusCorner bottomLeftCorner
) {
this._allowBevel = allowBevel;

this._top = top;
this._right = right;
this._bottom = bottom;
this._left = left;

this._topLeft = topLeftCorner;
this._topRight = topRightCorner;
this._bottomLeft = bottomLeftCorner;
this._bottomRight = bottomRightCorner;
}

public BorderPropertySet(
boolean allowBevel,
float top,
float right,
float bottom,
float left
) {
this._allowBevel = allowBevel;

this._top = top;
this._right = right;
this._bottom = bottom;
this._left = left;

this._topLeft = new BorderRadiusCorner();
this._topRight = new BorderRadiusCorner();
this._bottomLeft = new BorderRadiusCorner();
this._bottomRight = new BorderRadiusCorner();
}

public BorderPropertySet(
boolean allowBevel,
CollapsedBorderValue top,
CollapsedBorderValue right,
CollapsedBorderValue bottom,
CollapsedBorderValue left
) {
this( top.width(),
this(allowBevel,
top.width(),
right.width(),
bottom.width(),
left.width());

this._topStyle = top.style();
this._rightStyle = right.style();
this._bottomStyle = bottom.style();
Expand All @@ -108,8 +113,8 @@ public BorderPropertySet(
this._topColor = top.color();
this._rightColor = right.color();
this._bottomColor = bottom.color();
this._leftColor = left.color();
this._leftColor = left.color();

this._topLeft = new BorderRadiusCorner();
this._topRight = new BorderRadiusCorner();
this._bottomLeft = new BorderRadiusCorner();
Expand All @@ -120,6 +125,8 @@ private BorderPropertySet(
CalculatedStyle style,
CssContext ctx
) {
_allowBevel = style.isIdent(CSSName.FS_BORDER_RENDERING, IdentValue.AUTO);

_top = ( style.isIdent(CSSName.BORDER_TOP_STYLE, IdentValue.NONE) ||
style.isIdent(CSSName.BORDER_TOP_STYLE, IdentValue.HIDDEN)
?
Expand All @@ -136,7 +143,7 @@ private BorderPropertySet(
style.isIdent(CSSName.BORDER_LEFT_STYLE, IdentValue.HIDDEN)
?
0 : style.getFloatPropertyProportionalHeight(CSSName.BORDER_LEFT_WIDTH, 0, ctx));

_topColor = style.asColor(CSSName.BORDER_TOP_COLOR);
_rightColor = style.asColor(CSSName.BORDER_RIGHT_COLOR);
_bottomColor = style.asColor(CSSName.BORDER_BOTTOM_COLOR);
Expand All @@ -146,12 +153,7 @@ private BorderPropertySet(
_rightStyle = style.getIdent(CSSName.BORDER_RIGHT_STYLE);
_bottomStyle = style.getIdent(CSSName.BORDER_BOTTOM_STYLE);
_leftStyle = style.getIdent(CSSName.BORDER_LEFT_STYLE);
/*
_topLeft = new BorderRadiusCorner(style.valueByName(CSSName.BORDER_TOP_LEFT_RADIUS), ctx);
_topRight = new BorderRadiusCorner(style.valueByName(CSSName.BORDER_TOP_RIGHT_RADIUS), ctx);
_bottomLeft = new BorderRadiusCorner(style.valueByName(CSSName.BORDER_BOTTOM_LEFT_RADIUS), ctx);
_bottomRight = new BorderRadiusCorner(style.valueByName(CSSName.BORDER_BOTTOM_RIGHT_RADIUS), ctx);
*/

_topLeft = new BorderRadiusCorner(CSSName.BORDER_TOP_LEFT_RADIUS, style, ctx);
_topRight = new BorderRadiusCorner(CSSName.BORDER_TOP_RIGHT_RADIUS, style, ctx);
_bottomLeft = new BorderRadiusCorner(CSSName.BORDER_BOTTOM_LEFT_RADIUS, style, ctx);
Expand Down Expand Up @@ -200,6 +202,13 @@ public String toString() {
return "BorderPropertySet[top=" + _top + ",right=" + _right + ",bottom=" + _bottom + ",left=" + _left + "]";
}

/**
* See {@link CSSName#FS_BORDER_RENDERING}
*/
public boolean isBevelAllowed() {
return this._allowBevel;
}

public boolean noTop() {
return this._topStyle == IdentValue.NONE || (int) _top == 0;
}
Expand Down Expand Up @@ -247,16 +256,16 @@ public FSColor bottomColor() {
public FSColor leftColor() {
return _leftColor;
}

public boolean hasHidden() {
return _topStyle == IdentValue.HIDDEN || _rightStyle == IdentValue.HIDDEN ||
_bottomStyle == IdentValue.HIDDEN || _leftStyle == IdentValue.HIDDEN;
}
}

public boolean hasBorderRadius() {
return getTopLeft().hasRadius() || getTopRight().hasRadius() || getBottomLeft().hasRadius() || getBottomRight().hasRadius();
}

public BorderRadiusCorner getBottomRight() {
return _bottomRight;
}
Expand Down Expand Up @@ -288,10 +297,10 @@ public BorderRadiusCorner getTopLeft() {
public void setTopLeft(BorderRadiusCorner topLeft) {
this._topLeft = topLeft;
}

public BorderPropertySet normalizedInstance(Rectangle bounds) {
float factor = 1;

// top
factor = Math.min(factor, bounds.width / getSideWidth(_topLeft, _topRight, bounds.width));
// bottom
Expand All @@ -300,36 +309,32 @@ public BorderPropertySet normalizedInstance(Rectangle bounds) {
factor = Math.min(factor, bounds.height / getSideWidth(_topRight, _bottomRight, bounds.height));
// left
factor = Math.min(factor, bounds.height / getSideWidth(_bottomLeft, _bottomRight, bounds.height));
BorderPropertySet newPropSet = new BorderPropertySet(_top, _right, _bottom, _left,

BorderPropertySet newPropSet = new BorderPropertySet(true, _top, _right, _bottom, _left,
new BorderRadiusCorner(factor*_topLeft.getMaxLeft(bounds.height), factor*_topLeft.getMaxRight(bounds.width)),
new BorderRadiusCorner(factor*_topRight.getMaxLeft(bounds.width), factor*_topRight.getMaxRight(bounds.height)),
new BorderRadiusCorner(factor*_bottomRight.getMaxLeft(bounds.height), factor*_bottomRight.getMaxRight(bounds.width)),
new BorderRadiusCorner(factor*_bottomLeft.getMaxLeft(bounds.width), factor*_bottomLeft.getMaxRight(bounds.height)));

newPropSet._topColor = _topColor;
newPropSet._rightColor = _rightColor;
newPropSet._bottomColor = _bottomColor;
newPropSet._leftColor = _leftColor;

newPropSet._topStyle = _topStyle;
newPropSet._rightStyle = _rightStyle;
newPropSet._bottomStyle = _bottomStyle;
newPropSet._leftStyle = _leftStyle;

return newPropSet;
}

/**
* helper function for normalizeBorderRadius. Gets the max side width for each of the corners or the side width whichever is larger
* @param left
* @param right
* @param sideWidth
* @return
* Helper function for normalizeBorderRadius. Gets the max side width for each
* of the corners or the side width whichever is larger.
*/
private float getSideWidth(BorderRadiusCorner left, BorderRadiusCorner right, float sideWidth) {
return Math.max(sideWidth, left.getMaxRight(sideWidth) + right.getMaxLeft(sideWidth));
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,19 @@ public void calcCollapsedBorder(CssContext c) {
CollapsedBorderValue right = collapsedRightBorder(c);
CollapsedBorderValue bottom = collapsedBottomBorder(c);
CollapsedBorderValue left = collapsedLeftBorder(c);

_collapsedPaintingBorder = new BorderPropertySet(top, right, bottom, left);


boolean allowBevel = getStyle().isIdent(CSSName.FS_BORDER_RENDERING, IdentValue.AUTO);

_collapsedPaintingBorder = new BorderPropertySet(allowBevel, top, right, bottom, left);

// Give the extra pixel to top and left.
top.setWidth((top.width()+1)/2);
right.setWidth(right.width()/2);
bottom.setWidth(bottom.width()/2);
left.setWidth((left.width()+1)/2);
_collapsedLayoutBorder = new BorderPropertySet(top, right, bottom, left);

_collapsedLayoutBorder = new BorderPropertySet(allowBevel, top, right, bottom, left);

_collapsedBorderTop = top;
_collapsedBorderRight = right;
_collapsedBorderBottom = bottom;
Expand Down
Loading

0 comments on commit 691a79d

Please sign in to comment.