Skip to content

Commit

Permalink
#143 Implement support for box-sizing:border-box
Browse files Browse the repository at this point in the history
Includes support for min/max height/width properties and test cases.
Limitations:
+ Not implemented for replaced elements such as images/MathML, etc.
+ Not taken into account during the table layout algorithm.
  • Loading branch information
danfickle committed Aug 3, 2018
1 parent 89bb1d4 commit c4a22ef
Show file tree
Hide file tree
Showing 14 changed files with 337 additions and 11 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ head - 0.0.1-RC15-SNAPSHOT
+ NOTE: Started moving [project documentation to wiki](https://github.com/danfickle/openhtmltopdf/wiki).
+ [#228](https://github.com/danfickle/openhtmltopdf/issues/228) Support for letter-spacing CSS property. By @danfickle
+ [#143](https://github.com/danfickle/openhtmltopdf/pull/143) Merging of remaining items thanks to @backslash47
+ Support for ```box-sizing:border-box```. With additional work (for min/max width/height) by @danfickle
+ Text justification for embedded unicode fonts
+ [#250](https://github.com/danfickle/openhtmltopdf/pull/250) Optional PDF/A conformance. Thanks @syjer
+ [#252](https://github.com/danfickle/openhtmltopdf/issues/252) Incorrect placement of form controls. Thanks @tiredelk
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1481,6 +1481,15 @@ public final class CSSName implements Comparable {
INHERITS,
new PrimitivePropertyBuilders.ImageRenderingBuilder()
);

public final static CSSName BOX_SIZING =
addProperty(
"box-sizing",
PRIMITIVE,
"content-box",
NOT_INHERITED,
new PrimitivePropertyBuilders.BoxSizing()
);


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@ public class IdentValue implements FSDerivedValue {
*/
public static final IdentValue PIXELATED = addValue("pixelated");
public static final IdentValue CRISP_EDGES = addValue("crisp-edges");

/*
* Box-sizing
*/
public static final IdentValue BORDER_BOX = addValue("border-box");
public static final IdentValue CONTENT_BOX = addValue("content-box");


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1838,4 +1838,14 @@ protected BitSet getAllowed() {
return ALLOWED;
}
}

public static class BoxSizing extends SingleIdent {
// border-box | content-box
private static final BitSet ALLOWED = setFor(
new IdentValue[] {
IdentValue.BORDER_BOX, IdentValue.CONTENT_BOX });
protected BitSet getAllowed() {
return ALLOWED;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,13 @@ public boolean isParagraphContainerForBidi() {
isNonFlowContent();
}

/**
* @return true for border-box, false for content-box.
*/
public boolean isBorderBox() {
return isIdent(CSSName.BOX_SIZING, IdentValue.BORDER_BOX);
}

/**
* Aims to get the correct resolved max-width for a box in dots unit.
* Returns -1 if there is no max-width defined.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -723,18 +723,24 @@ protected void calcDimensions(LayoutContext c, int cssWidth) {
// CLEAN: cast to int
setLeftMBP((int) margin.left() + (int) border.left() + (int) padding.left());
setRightMBP((int) padding.right() + (int) border.right() + (int) margin.right());

if (c.isPrint() && getStyle().isDynamicAutoWidth()) {
setContentWidth(calcEffPageRelativeWidth(c));
} else {
setContentWidth((getContainingBlockWidth() - getLeftMBP() - getRightMBP()));
}

setHeight(0);

if (! isAnonymous() || (isFromCaptionedTable() && isFloated())) {
int pinnedContentWidth = -1;

if (cssWidth != -1) {
setContentWidth(cssWidth);
if (style.isBorderBox()) {
setBorderBoxWidth(c, cssWidth);
} else {
setContentWidth(cssWidth);
}
} else if (getStyle().isAbsolute() || getStyle().isFixed()) {
pinnedContentWidth = calcPinnedContentWidth(c);
if (pinnedContentWidth != -1) {
Expand All @@ -744,7 +750,11 @@ protected void calcDimensions(LayoutContext c, int cssWidth) {

int cssHeight = getCSSHeight(c);
if (cssHeight != -1) {
setHeight(cssHeight);
if (style.isBorderBox()) {
setBorderBoxHeight(c, cssHeight);
} else {
setHeight(cssHeight);
}
}

//check if replaced
Expand Down Expand Up @@ -970,28 +980,50 @@ private void calcShrinkToFitWidthIfNeeded(LayoutContext c) {
}

private void applyCSSMinMaxWidth(CssContext c) {
int w = getStyle().isBorderBox() ? getBorderBoxWidth(c) : getContentWidth();

if (! getStyle().isMaxWidthNone()) {
int cssMaxWidth = getCSSMaxWidth(c);
if (getContentWidth() > cssMaxWidth) {
setContentWidth(cssMaxWidth);
if (w > cssMaxWidth) {
if (getStyle().isBorderBox()) {
setBorderBoxWidth(c, cssMaxWidth);
} else {
setContentWidth(cssMaxWidth);
}
}
}

int cssMinWidth = getCSSMinWidth(c);
if (cssMinWidth > 0 && getContentWidth() < cssMinWidth) {
setContentWidth(cssMinWidth);
if (cssMinWidth > 0 && w < cssMinWidth) {
if (getStyle().isBorderBox()) {
setBorderBoxWidth(c, cssMinWidth);
} else {
setContentWidth(cssMinWidth);
}
}
}

private void applyCSSMinMaxHeight(CssContext c) {
int currentHeight = getStyle().isBorderBox() ? getBorderBoxHeight(c) : getHeight();

if (! getStyle().isMaxHeightNone()) {
int cssMaxHeight = getCSSMaxHeight(c);
if (getHeight() > cssMaxHeight) {
setHeight(cssMaxHeight);
if (currentHeight > cssMaxHeight) {
if (getStyle().isBorderBox()) {
setBorderBoxHeight(c, cssMaxHeight);
} else {
setHeight(cssMaxHeight);
}
}
}

int cssMinHeight = getCSSMinHeight(c);
if (cssMinHeight > 0 && getHeight() < cssMinHeight) {
setHeight(cssMinHeight);
if (cssMinHeight > 0 && currentHeight < cssMinHeight) {
if (getStyle().isBorderBox()) {
setBorderBoxHeight(c, cssMinHeight);
} else {
setHeight(cssMinHeight);
}
}
}

Expand Down
24 changes: 24 additions & 0 deletions openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/Box.java
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,18 @@ public void setHeight(int height) {
public int getHeight() {
return _height;
}

public void setBorderBoxHeight(CssContext c, int h) {
BorderPropertySet border = getBorder(c);
RectPropertySet padding = getPadding(c);
setHeight((int) Math.max(0f, h - border.height() - padding.height()));
}

public int getBorderBoxHeight(CssContext c) {
BorderPropertySet border = getBorder(c);
RectPropertySet padding = getPadding(c);
return (int) (getHeight() + border.height() + padding.height());
}

public void setContentWidth(int contentWidth) {
_contentWidth = contentWidth < 0 ? 0 : contentWidth;
Expand All @@ -993,6 +1005,18 @@ public void setContentWidth(int contentWidth) {
public int getContentWidth() {
return _contentWidth;
}

public int getBorderBoxWidth(CssContext c) {
BorderPropertySet border = getBorder(c);
RectPropertySet padding = getPadding(c);
return (int) (getContentWidth() + border.width() + padding.width());
}

public void setBorderBoxWidth(CssContext c, int borderBoxWidth) {
BorderPropertySet border = getBorder(c);
RectPropertySet padding = getPadding(c);
setContentWidth((int) (borderBoxWidth - border.width() - padding.width()));
}

public PaintingInfo getPaintingInfo() {
return _paintingInfo;
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<html>
<head>
<style>
@page {
size: 100px 1000px;
margin: 0;
}
body {
margin: 10px;
}
div.cont {
border: 1px solid red;
height: 31px;
margin-top: 10px;
}
.h1 {
border: 1px solid green;
box-sizing: content-box;
}
.h2 {
border: 1px solid blue;
box-sizing: border-box;
}
</style>
</head>
<body>
<!-- height only -->
<div class="cont"><div class="h1" style="height: 30px;"></div></div>

<!-- height/padding/border -->
<div class="cont"><div class="h1" style="height: 10px;padding-top: 10px; border-top-width: 10px;"></div></div>

<!-- height/padding/margin -->
<div class="cont"><div class="h1" style="height: 10px;padding-bottom: 10px; margin-top: 10px;"></div></div>

<!-- min-height overrides height -->
<div class="cont"><div class="h1" style="height: 10px;min-height: 30px;"></div></div>

<!-- max-height overrides height -->
<div class="cont"><div class="h1" style="height: 50px;max-height: 30px;"></div></div>

<!-- min-height overrides height and max-height -->
<div class="cont"><div class="h1" style="height: 10px;min-height: 30px;max-height: 10px;"></div></div>




<!-- height only -->
<div class="cont"><div class="h2" style="height: 32px;"></div></div>

<!-- height/padding/border -->
<div class="cont"><div class="h2" style="height: 32px;padding-top: 10px; border-top-width: 10px;"></div></div>

<!-- height/padding/margin -->
<div class="cont"><div class="h2" style="height: 22px;padding-bottom: 10px; margin-top: 10px;"></div></div>

<!-- min-height overrides height -->
<div class="cont"><div class="h2" style="height: 10px;min-height: 32px;"></div></div>

<!-- max-height overrides height -->
<div class="cont"><div class="h2" style="height: 50px;max-height: 32px;"></div></div>

<!-- min-height overrides height and max-height -->
<div class="cont"><div class="h2" style="height: 10px;min-height: 32px;max-height: 10px;"></div></div>



</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<html>
<head>
<style>
@page {
size: 800px 1000px;
margin: 0;
}
body {
margin: 10px;
}
div {
border: 1px solid red;
box-sizing: border-box;
}
.w {
margin: 0;
margin-top: 10px;
padding: 0;
height: 30px;
border-color: green;
}
</style>
</head>
<body>
<div style="width: 601px;">
<!-- Width plus margin-right -->
<div class="w" style="width: 600px; margin-right: 100px;"></div>

<!-- Width plus margin-left -->
<div class="w" style="width: 600px; margin-left: 100px;"></div>

<!-- Width includes padding-right -->
<div class="w" style="width: 600px; padding-right: 100px;"></div>

<!-- Width includes padding-left -->
<div class="w" style="width: 600px; padding-left: 100px;"></div>

<!-- Min-width overrides width -->
<div class="w" style="width: 50%; min-width: 600px; padding: 100px;"></div>

<!-- Max-width overrides width -->
<div class="w" style="width: 150%; max-width: 600px; padding-left: 100px;"></div>

<!-- Max-width overrides default block width of auto -->
<div class="w" style="max-width: 500px; padding-left: 100px;"></div>

<!-- Min-width wins over width and max-width -->
<div class="w" style="max-width: 300px; min-width: 600px; width: 300px;"></div>

<!-- Width overlap on right -->
<div class="w" style="width: 700px;"></div>

<!-- Min-width overlap on right -->
<div class="w" style="min-width: 700px;"></div>

<!-- Border-right included -->
<div class="w" style="width: 600px; border-right-width: 100px;"></div>

<!-- Border-right inside due to width being auto -->
<div class="w" style="border-right-width: 100px;"></div>

<!-- Margin-right inside due to width being auto -->
<div class="w" style="margin-right: 100px;"></div>

<!-- Padding-right inside due to width being auto -->
<div class="w" style="padding-right: 100px;"><div style="height: 100%;"></div></div>

<!-- Border/padding included in width -->
<div class="w" style="width: 600px; padding-right: 50px; border-right-width: 50px;"><div style="height: 100%;"></div></div>

<!-- Margin plus Border/padding/width -->
<div class="w" style="width: 600px; margin-left: 100px; padding-right: 20px; border-right-width: 50px;"><div style="height: 100%;"></div></div>

</div>
</body>
</html>
Loading

0 comments on commit c4a22ef

Please sign in to comment.