Skip to content

Commit bc11ab6

Browse files
rnadvodnyLodrKumquat
authored andcommitted
Don't create renderer with zero dimension. Update cmp
DEVSIX-1050
1 parent b87afbd commit bc11ab6

30 files changed

+122
-74
lines changed

src/main/java/com/itextpdf/html2pdf/attach/impl/layout/PageContextProcessor.java

Lines changed: 87 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ PageContextProcessor reset(PageSize defaultPageSize, float[] defaultPageMargins)
229229

230230
marks = parseMarks(styles.get(CssConstants.MARKS));
231231

232-
// todo all of this art with margins, borders and paddings?
233232
parseMargins(styles, em, rem, defaultPageMargins);
234233
parseBorders(styles, em, rem);
235234
parsePaddings(styles, em, rem);
@@ -466,50 +465,65 @@ private void drawMarginBoxes(int pageNumber, PdfDocument pdfDocument, DocumentRe
466465
PageMarginBoxContextNode[] corners = new PageMarginBoxContextNode[4];
467466
for (PageMarginBoxContextNode marginBoxContentNode : properties.getResolvedPageMarginBoxes()) {
468467
int marginBoxInd = mapMarginBoxNameToIndex(marginBoxContentNode.getMarginBoxName());
469-
if (marginBoxInd % 4 != 0)
468+
if (marginBoxInd % 4 != 0) {
470469
sides[marginBoxInd / 4][marginBoxInd % 4 - 1] = marginBoxContentNode;
471-
else
470+
}
471+
else {
472472
corners[marginBoxInd / 4] = marginBoxContentNode;
473+
}
473474
}
474475

475476
IElement[][] sideBoxElement = new IElement[4][3];
476477
IElement[] cornerBoxElement = new IElement[4];
477478
for (int i = 0; i < 4; i++) {
478479
for (int j = 0; j < 3; j++)
479-
if (sides[i][j] != null)
480+
if (sides[i][j] != null) {
480481
sideBoxElement[i][j] = processMarginBoxContent(sides[i][j], pageNumber, context);
481-
if (corners[i] != null)
482+
}
483+
if (corners[i] != null) {
482484
cornerBoxElement[i] = processMarginBoxContent(corners[i], pageNumber, context);
485+
}
483486
}
484487

485488
for (int i = 0; i < 4; i++) {
486489
if (cornerBoxElement[i] != null) {
487-
IRenderer cornerRenderer = funWithRenderer(cornerBoxElement[i], documentRenderer, pdfDocument);
488-
float rendererWidth = margins[i % 3 == 0 ? 3 : 1] - getWidthOfOneSide(cornerBoxElement[i], Property.MARGIN_LEFT, Property.BORDER_LEFT, Property.PADDING_LEFT) -
489-
getWidthOfOneSide(cornerBoxElement[i], Property.MARGIN_RIGHT, Property.BORDER_RIGHT, Property.PADDING_RIGHT);
490-
float rendererHeight = margins[i > 1 ? 2 : 0] - getWidthOfOneSide(cornerBoxElement[i], Property.MARGIN_TOP, Property.BORDER_TOP, Property.PADDING_TOP) -
491-
getWidthOfOneSide(cornerBoxElement[i], Property.MARGIN_BOTTOM, Property.BORDER_BOTTOM, Property.PADDING_BOTTOM);
490+
IRenderer cornerRenderer = createRendererFromElement(cornerBoxElement[i], documentRenderer, pdfDocument);
491+
492+
float rendererWidth =
493+
margins[i % 3 == 0 ? 3 : 1]
494+
- getSizeOfOneSide(cornerBoxElement[i], Property.MARGIN_LEFT,
495+
Property.BORDER_LEFT, Property.PADDING_LEFT)
496+
- getSizeOfOneSide(cornerBoxElement[i], Property.MARGIN_RIGHT,
497+
Property.BORDER_RIGHT, Property.PADDING_RIGHT);
498+
499+
float rendererHeight =
500+
margins[i > 1 ? 2 : 0]
501+
- getSizeOfOneSide(cornerBoxElement[i], Property.MARGIN_TOP,
502+
Property.BORDER_TOP, Property.PADDING_TOP)
503+
- getSizeOfOneSide(cornerBoxElement[i], Property.MARGIN_BOTTOM,
504+
Property.BORDER_BOTTOM, Property.PADDING_BOTTOM);
505+
492506
cornerRenderer.setProperty(Property.WIDTH, UnitValue.createPointValue(rendererWidth));
493507
cornerRenderer.setProperty(Property.HEIGHT, UnitValue.createPointValue(rendererHeight));
494508
draw(cornerRenderer, corners[i], pdfDocument, page, documentRenderer, pageNumber);
495509
}
496510

497-
IRenderer[] renderer = new IRenderer[3];
511+
IRenderer[] renderers = new IRenderer[3];
498512
for (int j = 0; j < 3; j++) {
499513
if (sideBoxElement[i][j] != null) {
500-
renderer[j] = funWithRenderer(sideBoxElement[i][j], documentRenderer, pdfDocument);
514+
renderers[j] = createRendererFromElement(sideBoxElement[i][j], documentRenderer, pdfDocument);
501515
}
502516
}
503-
determineSizes(sides[i], renderer, sideBoxElement[i], i);
517+
determineSizes(sides[i], renderers, sideBoxElement[i], i);
504518
for (int j = 0; j < 3; j++) {
505-
if (renderer[j] != null) {
506-
draw(renderer[j], sides[i][j], pdfDocument, page, documentRenderer, pageNumber);
519+
if (renderers[j] != null) {
520+
draw(renderers[j], sides[i][j], pdfDocument, page, documentRenderer, pageNumber);
507521
}
508522
}
509523
}
510524
}
511525

512-
private IRenderer funWithRenderer(IElement element, DocumentRenderer documentRenderer, PdfDocument pdfDocument) {
526+
private IRenderer createRendererFromElement(IElement element, DocumentRenderer documentRenderer, PdfDocument pdfDocument) {
513527
IRenderer renderer = element.createRendererSubTree();
514528
removeAreaBreaks(renderer);
515529
renderer.setParent(documentRenderer);
@@ -625,8 +639,6 @@ private void prepareMarginBoxesSizing(List<PageMarginBoxContextNode> resolvedPag
625639
}
626640
}
627641

628-
// todo don't forget to apply MBP to corners!!!
629-
630642
private IElement processMarginBoxContent(PageMarginBoxContextNode marginBoxContentNode, int pageNumber, ProcessorContext context) {
631643
IElementNode dummyMarginBoxNode = new PageMarginBoxDummyElement();
632644
dummyMarginBoxNode.setStyles(marginBoxContentNode.getStyles());
@@ -719,37 +731,55 @@ private void determineSizes(PageMarginBoxContextNode[] resolvedPageMarginBoxes,
719731
float[][] marginsBordersPaddingsWidths = new float[3][4];
720732
for (int i = 0; i < 3; i++) {
721733
if (elements[i] != null) {
722-
marginsBordersPaddingsWidths[i][0] = getWidthOfOneSide(elements[i], Property.MARGIN_TOP, Property.BORDER_TOP, Property.PADDING_TOP);
723-
marginsBordersPaddingsWidths[i][1] = getWidthOfOneSide(elements[i], Property.MARGIN_RIGHT, Property.BORDER_RIGHT, Property.PADDING_RIGHT);
724-
marginsBordersPaddingsWidths[i][2] = getWidthOfOneSide(elements[i], Property.MARGIN_BOTTOM, Property.BORDER_BOTTOM, Property.PADDING_BOTTOM);
725-
marginsBordersPaddingsWidths[i][3] = getWidthOfOneSide(elements[i], Property.MARGIN_LEFT, Property.BORDER_LEFT, Property.PADDING_LEFT);
734+
marginsBordersPaddingsWidths[i][0] = getSizeOfOneSide(elements[i], Property.MARGIN_TOP, Property.BORDER_TOP, Property.PADDING_TOP);
735+
marginsBordersPaddingsWidths[i][1] = getSizeOfOneSide(elements[i], Property.MARGIN_RIGHT, Property.BORDER_RIGHT, Property.PADDING_RIGHT);
736+
marginsBordersPaddingsWidths[i][2] = getSizeOfOneSide(elements[i], Property.MARGIN_BOTTOM, Property.BORDER_BOTTOM, Property.PADDING_BOTTOM);
737+
marginsBordersPaddingsWidths[i][3] = getSizeOfOneSide(elements[i], Property.MARGIN_LEFT, Property.BORDER_LEFT, Property.PADDING_LEFT);
726738
}
727739
}
728740
Rectangle withoutMargins = pageSize.clone().applyMargins(margins[0], margins[1], margins[2], margins[3], false);
729741
Map<String, PageMarginBoxContextNode> resolvedPMBMap = new HashMap<>();
730742
for (PageMarginBoxContextNode node : resolvedPageMarginBoxes) {
731-
if (node != null)
743+
if (node != null) {
732744
resolvedPMBMap.put(node.getMarginBoxName(), node);
745+
}
733746
}
734747
DimensionContainer[] dims = new DimensionContainer[3];
735748
String[] cssRuleName = getRuleNames(side);
749+
float withoutMarginsWidthOrHeight = side % 2 == 0 ? withoutMargins.getWidth() : withoutMargins.getHeight();
736750
for (int i = 0; i < 3; i++)
737-
if (side % 2 == 0)
738-
dims[i] = retrievePageMarginBoxWidths(resolvedPMBMap.get(cssRuleName[i]), renderers[i], side % 2 == 0 ? withoutMargins.getWidth() : withoutMargins.getHeight(),
751+
if (side % 2 == 0) {
752+
dims[i] = retrievePageMarginBoxWidths(resolvedPMBMap.get(cssRuleName[i]), renderers[i], withoutMarginsWidthOrHeight,
739753
marginsBordersPaddingsWidths[i][1] + marginsBordersPaddingsWidths[i][3]);
740-
else
754+
}
755+
else {
741756
dims[i] = retrievePageMarginBoxHeights(resolvedPMBMap.get(cssRuleName[i]), renderers[i], margins[side],
742-
side % 2 == 0 ? withoutMargins.getWidth() : withoutMargins.getHeight(), marginsBordersPaddingsWidths[i][1] + marginsBordersPaddingsWidths[i][3]);
743-
float[] widthOfHeightResults = calculatePageMarginBoxDimensions(dims[0], dims[1], dims[2], side % 2 == 0 ? withoutMargins.getWidth() : withoutMargins.getHeight());
744-
float centerOrMiddleCoord = getStartCoordForCenterOrMiddleBox(side % 2 == 0 ? withoutMargins.getWidth() : withoutMargins.getHeight(),
745-
widthOfHeightResults[1],
746-
side % 2 == 0 ? withoutMargins.getLeft() : withoutMargins.getBottom());
757+
withoutMarginsWidthOrHeight, marginsBordersPaddingsWidths[i][0] + marginsBordersPaddingsWidths[i][2]);
758+
759+
}
760+
761+
float centerOrMiddleCoord, widthOfHeightResults[];
762+
widthOfHeightResults = calculatePageMarginBoxDimensions(dims[0], dims[1], dims[2], withoutMarginsWidthOrHeight);
763+
if (side % 2 == 0) {
764+
centerOrMiddleCoord = getStartCoordForCenterOrMiddleBox(withoutMarginsWidthOrHeight,
765+
widthOfHeightResults[1], withoutMargins.getLeft());
766+
} else {
767+
centerOrMiddleCoord = getStartCoordForCenterOrMiddleBox(withoutMarginsWidthOrHeight,
768+
widthOfHeightResults[1], withoutMargins.getBottom());
769+
}
770+
747771
Rectangle[] result = getRectangles(side, withoutMargins, centerOrMiddleCoord, widthOfHeightResults, marginsBordersPaddingsWidths);
748772
for (int i = 0; i < 3; i++)
749773
if (resolvedPageMarginBoxes[i] != null) {
750774
resolvedPageMarginBoxes[i].setPageMarginBoxRectangle(result[i]);
751-
renderers[i].setProperty(Property.WIDTH, UnitValue.createPointValue(result[i].getWidth() - marginsBordersPaddingsWidths[i][1] - marginsBordersPaddingsWidths[i][3]));
752-
renderers[i].setProperty(Property.HEIGHT, UnitValue.createPointValue(result[i].getHeight() - marginsBordersPaddingsWidths[i][0] - marginsBordersPaddingsWidths[i][2]));
775+
UnitValue width = UnitValue.createPointValue(result[i].getWidth() - marginsBordersPaddingsWidths[i][1] - marginsBordersPaddingsWidths[i][3]);
776+
UnitValue height = UnitValue.createPointValue(result[i].getHeight() - marginsBordersPaddingsWidths[i][0] - marginsBordersPaddingsWidths[i][2]);
777+
if (Math.abs(width.getValue()) < 1e-3 || Math.abs(height.getValue()) < 1e-3) {
778+
renderers[i] = null;
779+
} else {
780+
renderers[i].setProperty(Property.WIDTH, width);
781+
renderers[i].setProperty(Property.HEIGHT, height);
782+
}
753783
}
754784
}
755785

@@ -804,21 +834,23 @@ private Rectangle[] getRectangles(int side, Rectangle withoutMargins, float cent
804834
return new Rectangle[3];
805835
}
806836

807-
// todo importance of order! Border is different from margin or padding!
808-
// todo make sure it's always top, right, bottom and left and not generic
809-
// todo make sure margin/padding is always UnitValue
810-
private float getWidthOfOneSide(IElement element, int marginProperty, int borderProperty, int paddingProperty) {
811-
// todo extract the damn Property accurately
837+
private float getSizeOfOneSide(IElement element, int marginProperty, int borderProperty, int paddingProperty) {
812838
float marginWidth = 0, paddingWidth = 0, borderWidth = 0;
839+
813840
UnitValue temp = element.<UnitValue>getProperty(marginProperty);
814-
if (null != temp)
841+
if (null != temp) {
815842
marginWidth = temp.getValue();
843+
}
844+
816845
temp = element.<UnitValue>getProperty(paddingProperty);
817-
if (null != temp)
846+
if (null != temp) {
818847
paddingWidth = temp.getValue();
848+
}
849+
819850
Border border = element.<Border>getProperty(borderProperty);
820-
if (null != border)
851+
if (null != border) {
821852
borderWidth = border.getWidth();
853+
}
822854
return marginWidth + paddingWidth + borderWidth;
823855
}
824856

@@ -850,22 +882,22 @@ private float[] calculatePageMarginBoxDimensions(DimensionContainer dimA, Dimens
850882
maxContentDimensionC = 0, minContentDimensionC = 0;
851883
float[] dimensions = new float[3];
852884

853-
if (dimA == null && dimB == null && dimC == null) {
885+
if (isContainerEmpty(dimA) && isContainerEmpty(dimB) && isContainerEmpty(dimC)) {
854886
return dimensions;
855887
}
856888

857889
//Calculate widths
858890
//Check if B is present
859-
if (dimB == null) {
891+
if (isContainerEmpty(dimB)) {
860892
//Single box present
861-
if (dimA == null) {
893+
if (isContainerEmpty(dimA)) {
862894
if (dimC.isAutoDimension()) {
863895
//Allocate everything to C
864896
dimensions[2] = availableDimension;
865897
} else {
866898
dimensions[2] = dimC.dimension;
867899
}
868-
} else if (dimC == null) {
900+
} else if (isContainerEmpty(dimC)) {
869901
if (dimA.isAutoDimension()) {
870902
//Allocate everything to A
871903
dimensions[0] = availableDimension;
@@ -896,7 +928,7 @@ private float[] calculatePageMarginBoxDimensions(DimensionContainer dimA, Dimens
896928
}
897929
} else {
898930
//Check for edge cases
899-
if (dimA != null) {
931+
if (!isContainerEmpty(dimA)) {
900932
if (dimA.isAutoDimension()) {
901933
maxContentDimensionA = dimA.maxContentDimension;
902934
minContentDimensionA = dimA.minContentDimension;
@@ -905,7 +937,7 @@ private float[] calculatePageMarginBoxDimensions(DimensionContainer dimA, Dimens
905937
minContentDimensionA = dimA.dimension;
906938
}
907939
}
908-
if (dimC != null) {
940+
if (!isContainerEmpty(dimC)) {
909941
if (dimC.isAutoDimension()) {
910942
maxContentDimensionC = dimC.maxContentDimension;
911943
minContentDimensionC = dimC.minContentDimension;
@@ -940,7 +972,10 @@ private float[] calculatePageMarginBoxDimensions(DimensionContainer dimA, Dimens
940972
} else {
941973
dimensions[1] = dimB.dimension;
942974
float newAvailableDimension = (availableDimension - dimensions[1]) / 2;
943-
// todo make sure it's not tooooo big float
975+
976+
if (newAvailableDimension > Float.MAX_VALUE - MinMaxWidthUtils.getEps()) {
977+
newAvailableDimension = Float.MAX_VALUE - MinMaxWidthUtils.getEps();
978+
}
944979
dimensions[0] = Math.min(maxContentDimensionA, newAvailableDimension) + MinMaxWidthUtils.getEps();
945980
dimensions[2] = Math.min(maxContentDimensionC, newAvailableDimension) + MinMaxWidthUtils.getEps();
946981
}
@@ -957,6 +992,10 @@ private float[] calculatePageMarginBoxDimensions(DimensionContainer dimA, Dimens
957992
return dimensions;
958993
}
959994

995+
private boolean isContainerEmpty(DimensionContainer container) {
996+
return container == null || Math.abs(container.maxContentDimension) < 1e-3;
997+
}
998+
960999
private void removeNegativeValues(float[] dimensions) {
9611000
for (int i = 0; i < dimensions.length; i++) {
9621001
if (dimensions[i] < 0) {

src/main/java/com/itextpdf/html2pdf/css/apply/impl/PageMarginBoxCssApplier.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,8 @@ public void apply(ProcessorContext context, IStylesContainer stylesContainer, IT
143143
return;
144144
}
145145

146-
float availableWidth = stylesContainer instanceof PageMarginBoxContextNode ? ((PageMarginBoxContextNode) stylesContainer).getContainingBlockForMarginBox().getWidth() : 0.0f;
147-
float availableHeight = stylesContainer instanceof PageMarginBoxContextNode ? ((PageMarginBoxContextNode) stylesContainer).getContainingBlockForMarginBox().getHeight() : 0.0f;
148-
// todo : check HORIZONTAL_ALIGNMENT in MarginApplierUtil.
146+
float availableWidth = ((PageMarginBoxContextNode) stylesContainer).getContainingBlockForMarginBox().getWidth();
147+
float availableHeight = ((PageMarginBoxContextNode) stylesContainer).getContainingBlockForMarginBox().getHeight();
149148
MarginApplierUtil.applyMargins(boxStyles, context, marginBox, availableHeight, availableWidth);
150149
PaddingApplierUtil.applyPaddings(boxStyles, context, marginBox, availableHeight, availableWidth);
151150

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ public final class MarginApplierUtil {
7171
private MarginApplierUtil() {
7272
}
7373

74-
// todo change javadocs!
7574
/**
7675
* Applies margins to an element.
7776
*
@@ -89,6 +88,8 @@ public static void applyMargins(Map<String, String> cssProps, ProcessorContext c
8988
* @param cssProps the CSS properties
9089
* @param context the processor context
9190
* @param element the element
91+
* @param baseValueHorizontal value used by default for horizontal dimension
92+
* @param baseValueVertical value used by default for vertical dimension
9293
*/
9394
public static void applyMargins(Map<String, String> cssProps, ProcessorContext context, IPropertyContainer element, float baseValueVertical, float baseValueHorizontal) {
9495
String marginTop = cssProps.get(CssConstants.MARGIN_TOP);
@@ -131,6 +132,7 @@ public static void applyMargins(Map<String, String> cssProps, ProcessorContext c
131132
* @param element the element
132133
* @param em the em value
133134
* @param rem the root em value
135+
* @param baseValue value used by default
134136
* @return false if the margin value was "auto"
135137
*/
136138
private static boolean trySetMarginIfNotAuto(int marginProperty, String marginValue, IPropertyContainer element, float em, float rem, float baseValue) {
@@ -152,14 +154,16 @@ private static boolean trySetMarginIfNotAuto(int marginProperty, String marginVa
152154
* @param marginValString the margin value as a {@link String}
153155
* @param em the em value
154156
* @param rem the root em value
157+
* @param baseValue value used my default
155158
* @return the margin value as a {@link Float}
156159
*/
157160
private static Float parseMarginValue(String marginValString, float em, float rem, float baseValue) {
158161
UnitValue marginUnitVal = CssUtils.parseLengthValueToPt(marginValString, em, rem);
159162
if (marginUnitVal != null) {
160163
if (!marginUnitVal.isPointValue()) {
161-
if (baseValue != 0.0f)
164+
if (baseValue != 0.0f) {
162165
return new Float(baseValue * marginUnitVal.getValue() * 0.01);
166+
}
163167
logger.error(LogMessageConstant.MARGIN_VALUE_IN_PERCENT_NOT_SUPPORTED);
164168
return null;
165169
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,13 @@ public final class PaddingApplierUtil {
6868
private PaddingApplierUtil() {
6969
}
7070

71-
// todo change javadoc
71+
/**
72+
* Applies paddings to an element.
73+
*
74+
* @param cssProps the CSS properties
75+
* @param context the processor context
76+
* @param element the element
77+
*/
7278
public static void applyPaddings(Map<String, String> cssProps, ProcessorContext context, IPropertyContainer element) {
7379
applyPaddings(cssProps, context, element, 0.0f, 0.0f);
7480
}
@@ -79,6 +85,8 @@ public static void applyPaddings(Map<String, String> cssProps, ProcessorContext
7985
* @param cssProps the CSS properties
8086
* @param context the processor context
8187
* @param element the element
88+
* @param baseValueHorizontal value used by default for horizontal dimension
89+
* @param baseValueVertical value used by default for vertical dimension
8290
*/
8391
public static void applyPaddings(Map<String, String> cssProps, ProcessorContext context, IPropertyContainer element, float baseValueVertical, float baseValueHorizontal) {
8492
String paddingTop = cssProps.get(CssConstants.PADDING_TOP);

0 commit comments

Comments
 (0)