Skip to content

Commit 1f3e72a

Browse files
Implement support for box-sizing property
DEVSIX-1174
1 parent 2c92884 commit 1f3e72a

24 files changed

+406
-163
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.itextpdf.layout.property;
2+
3+
/**
4+
* A specialized enum containing potential property values for {@link
5+
* Property#BOX_SIZING}.
6+
*/
7+
public enum BoxSizingPropertyValue {
8+
CONTENT_BOX,
9+
BORDER_BOX
10+
}

layout/src/main/java/com/itextpdf/layout/property/Property.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ private Property() {
7171
public static final int BORDER_RIGHT = 12;
7272
public static final int BORDER_TOP = 13;
7373
public static final int BOTTOM = 14;
74+
public static final int BOX_SIZING = 101;
7475
public static final int CHARACTER_SPACING = 15;
7576
public static final int CLEAR = 100;
7677
public static final int COLLAPSING_MARGINS = 89;

layout/src/main/java/com/itextpdf/layout/renderer/AbstractRenderer.java

Lines changed: 130 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ This file is part of the iText (R) project.
8181
import com.itextpdf.layout.property.Background;
8282
import com.itextpdf.layout.property.BackgroundImage;
8383
import com.itextpdf.layout.property.BaseDirection;
84+
import com.itextpdf.layout.property.BoxSizingPropertyValue;
8485
import com.itextpdf.layout.property.HorizontalAlignment;
8586
import com.itextpdf.layout.property.Property;
8687
import com.itextpdf.layout.property.TransparentColor;
@@ -704,20 +705,112 @@ protected void applyDestinationsAndAnnotation(DrawContext drawContext) {
704705
applyLinkAnnotation(drawContext.getDocument());
705706
}
706707

708+
static boolean isBorderBoxSizing(IRenderer renderer) {
709+
BoxSizingPropertyValue boxSizing = renderer.<BoxSizingPropertyValue>getProperty(Property.BOX_SIZING);
710+
return boxSizing != null && boxSizing.equals(BoxSizingPropertyValue.BORDER_BOX);
711+
}
712+
713+
/**
714+
* Retrieves element's fixed content box width, if it's set.
715+
* Takes into account {@link Property#BOX_SIZING} property value.
716+
* @param parentBoxWidth width of the parent element content box.
717+
* If element has relative width, it will be
718+
* calculated relatively to this parameter.
719+
* @return element's fixed content box width or null if it's not set.
720+
*/
707721
protected Float retrieveWidth(float parentBoxWidth) {
708-
return retrieveUnitValue(parentBoxWidth, Property.WIDTH);
722+
Float width = retrieveUnitValue(parentBoxWidth, Property.WIDTH);
723+
if (width != null && isBorderBoxSizing(this)) {
724+
width = Math.max(0, (float)width - calculatePaddingBorderWidth(this));
725+
}
726+
return width;
709727
}
710728

729+
/**
730+
* Updates fixed content box width value for this renderer.
731+
* Takes into account {@link Property#BOX_SIZING} property value.
732+
* @param updatedWidthValue element's new fixed content box width.
733+
*/
734+
protected void updateWidth(UnitValue updatedWidthValue) {
735+
if (updatedWidthValue.isPointValue() && isBorderBoxSizing(this)) {
736+
updatedWidthValue.setValue(updatedWidthValue.getValue() + calculatePaddingBorderWidth(this));
737+
}
738+
setProperty(Property.WIDTH, updatedWidthValue);
739+
}
740+
741+
/**
742+
* Retrieves element's fixed content box height, if it's set.
743+
* Takes into account {@link Property#BOX_SIZING} property value.
744+
* @return element's fixed content box height or null if it's not set.
745+
*/
711746
protected Float retrieveHeight() {
712-
return this.<Float>getProperty(Property.HEIGHT);
747+
Float height = this.<Float>getProperty(Property.HEIGHT);
748+
if (height != null && isBorderBoxSizing(this)) {
749+
height = Math.max(0, (float)height - calculatePaddingBorderHeight(this));
750+
}
751+
return height;
713752
}
714753

754+
/**
755+
* Updates fixed content box height value for this renderer.
756+
* Takes into account {@link Property#BOX_SIZING} property value.
757+
* @param updatedHeightValue element's new fixed content box height, shall be not null.
758+
*/
759+
protected void updateHeight(Float updatedHeightValue) {
760+
if (isBorderBoxSizing(this)) {
761+
updatedHeightValue += calculatePaddingBorderHeight(this);
762+
}
763+
setProperty(Property.HEIGHT, updatedHeightValue);
764+
}
765+
766+
/**
767+
* Retrieves element's content box max-height, if it's set.
768+
* Takes into account {@link Property#BOX_SIZING} property value.
769+
* @return element's content box max-height or null if it's not set.
770+
*/
715771
protected Float retrieveMaxHeight() {
716-
return this.<Float>getProperty(Property.MAX_HEIGHT);
772+
Float maxHeight = this.<Float>getProperty(Property.MAX_HEIGHT);
773+
if (maxHeight != null && isBorderBoxSizing(this)) {
774+
maxHeight = Math.max(0, (float)maxHeight - calculatePaddingBorderHeight(this));
775+
}
776+
return maxHeight;
717777
}
718778

779+
/**
780+
* Updates content box max-height value for this renderer.
781+
* Takes into account {@link Property#BOX_SIZING} property value.
782+
* @param updatedMaxHeightValue element's new content box max-height, shall be not null.
783+
*/
784+
protected void updateMaxHeight(Float updatedMaxHeightValue) {
785+
if (isBorderBoxSizing(this)) {
786+
updatedMaxHeightValue += calculatePaddingBorderHeight(this);
787+
}
788+
setProperty(Property.MAX_HEIGHT, updatedMaxHeightValue);
789+
}
790+
791+
/**
792+
* Retrieves element's content box max-height, if it's set.
793+
* Takes into account {@link Property#BOX_SIZING} property value.
794+
* @return element's content box min-height or null if it's not set.
795+
*/
719796
protected Float retrieveMinHeight() {
720-
return this.<Float>getProperty(Property.MIN_HEIGHT);
797+
Float minHeight = this.<Float>getProperty(Property.MIN_HEIGHT);
798+
if (minHeight != null && isBorderBoxSizing(this)) {
799+
minHeight = Math.max(0, (float)minHeight - calculatePaddingBorderHeight(this));
800+
}
801+
return minHeight;
802+
}
803+
804+
/**
805+
* Updates content box min-height value for this renderer.
806+
* Takes into account {@link Property#BOX_SIZING} property value.
807+
* @param updatedMinHeightValue element's new content box min-height, shall be not null.
808+
*/
809+
protected void updateMinHeight(Float updatedMinHeightValue) {
810+
if (isBorderBoxSizing(this)) {
811+
updatedMinHeightValue += calculatePaddingBorderHeight(this);
812+
}
813+
setProperty(Property.MIN_HEIGHT, updatedMinHeightValue);
721814
}
722815

723816
protected Float retrieveUnitValue(float basePercentValue, int property) {
@@ -973,6 +1066,17 @@ protected MinMaxWidth getMinMaxWidth(float availableWidth) {
9731066
return MinMaxWidthUtils.countDefaultMinMaxWidth(this, availableWidth);
9741067
}
9751068

1069+
protected boolean setMinMaxWidthBasedOnFixedWidth(MinMaxWidth minMaxWidth) {
1070+
UnitValue widthProp = this.<UnitValue>getProperty(Property.WIDTH);
1071+
Float width = retrieveWidth(0);
1072+
if (width != null && widthProp != null && !widthProp.isPercentValue()) {
1073+
minMaxWidth.setChildrenMaxWidth((float) width);
1074+
minMaxWidth.setChildrenMinWidth((float) width);
1075+
return true;
1076+
}
1077+
return false;
1078+
}
1079+
9761080
protected boolean isNotFittingHeight(LayoutArea layoutArea) {
9771081
return !isPositioned() && occupiedArea.getBBox().getHeight() > layoutArea.getBBox().getHeight();
9781082
}
@@ -1253,6 +1357,14 @@ RootRenderer getRootRenderer() {
12531357
return null;
12541358
}
12551359

1360+
static float calculateAdditionalWidth(AbstractRenderer renderer) {
1361+
Rectangle dummy = new Rectangle(0, 0);
1362+
renderer.applyMargins(dummy, true);
1363+
renderer.applyBorderBox(dummy, true);
1364+
renderer.applyPaddings(dummy, true);
1365+
return dummy.getWidth();
1366+
}
1367+
12561368
static boolean noAbsolutePositionInfo(IRenderer renderer) {
12571369
return !renderer.hasProperty(Property.TOP) && !renderer.hasProperty(Property.BOTTOM) && !renderer.hasProperty(Property.LEFT) && !renderer.hasProperty(Property.RIGHT);
12581370
}
@@ -1391,4 +1503,18 @@ private void adjustPositionedRendererLayoutBoxWidth(IRenderer renderer, Rectangl
13911503
}
13921504
}
13931505

1506+
private static float calculatePaddingBorderWidth(AbstractRenderer renderer) {
1507+
Rectangle dummy = new Rectangle(0, 0);
1508+
renderer.applyBorderBox(dummy, true);
1509+
renderer.applyPaddings(dummy, true);
1510+
return dummy.getWidth();
1511+
}
1512+
1513+
private static float calculatePaddingBorderHeight(AbstractRenderer renderer) {
1514+
Rectangle dummy = new Rectangle(0, 0);
1515+
renderer.applyBorderBox(dummy, true);
1516+
renderer.applyPaddings(dummy, true);
1517+
return dummy.getHeight();
1518+
}
1519+
13941520
}

0 commit comments

Comments
 (0)