@@ -44,6 +44,7 @@ This file is part of the iText (R) project.
44
44
package com .itextpdf .layout .renderer ;
45
45
46
46
import com .itextpdf .io .LogMessageConstant ;
47
+ import com .itextpdf .io .util .MessageFormatUtil ;
47
48
import com .itextpdf .io .util .NumberUtil ;
48
49
import com .itextpdf .kernel .color .Color ;
49
50
import com .itextpdf .kernel .font .PdfFont ;
@@ -72,19 +73,21 @@ This file is part of the iText (R) project.
72
73
import com .itextpdf .layout .font .FontFamilySplitter ;
73
74
import com .itextpdf .layout .font .FontProvider ;
74
75
import com .itextpdf .layout .layout .LayoutArea ;
76
+ import com .itextpdf .layout .layout .LayoutContext ;
75
77
import com .itextpdf .layout .layout .LayoutPosition ;
78
+ import com .itextpdf .layout .layout .PositionedLayoutContext ;
76
79
import com .itextpdf .layout .minmaxwidth .MinMaxWidth ;
77
80
import com .itextpdf .layout .minmaxwidth .MinMaxWidthUtils ;
78
81
import com .itextpdf .layout .property .Background ;
79
82
import com .itextpdf .layout .property .BackgroundImage ;
83
+ import com .itextpdf .layout .property .BaseDirection ;
80
84
import com .itextpdf .layout .property .HorizontalAlignment ;
81
85
import com .itextpdf .layout .property .Property ;
82
86
import com .itextpdf .layout .property .TransparentColor ;
83
87
import com .itextpdf .layout .property .UnitValue ;
84
88
import org .slf4j .Logger ;
85
89
import org .slf4j .LoggerFactory ;
86
90
87
- import com .itextpdf .io .util .MessageFormatUtil ;
88
91
import java .util .ArrayList ;
89
92
import java .util .Arrays ;
90
93
import java .util .Collections ;
@@ -871,54 +874,39 @@ protected Rectangle applyBorderBox(Rectangle rect, Border[] borders, boolean rev
871
874
return rect .<Rectangle >applyMargins (topWidth , rightWidth , bottomWidth , leftWidth , reverse );
872
875
}
873
876
874
- protected void applyAbsolutePosition (Rectangle rect ) {
877
+ protected void applyAbsolutePosition (Rectangle parentRect ) {
875
878
Float top = this .getPropertyAsFloat (Property .TOP );
876
879
Float bottom = this .getPropertyAsFloat (Property .BOTTOM );
877
880
Float left = this .getPropertyAsFloat (Property .LEFT );
878
881
Float right = this .getPropertyAsFloat (Property .RIGHT );
879
882
880
- float initialHeight = rect .getHeight ();
881
- float initialWidth = rect .getWidth ();
882
-
883
- Float minHeight = this .getPropertyAsFloat (Property .MIN_HEIGHT );
884
-
885
- if (minHeight != null && rect .getHeight () < (float )minHeight ) {
886
- float difference = (float )minHeight - rect .getHeight ();
887
- rect .moveDown (difference ).setHeight (rect .getHeight () + difference );
883
+ if (left == null && right == null && BaseDirection .RIGHT_TO_LEFT .equals (this .<BaseDirection >getProperty (Property .BASE_DIRECTION ))) {
884
+ right = 0f ;
888
885
}
889
886
890
- if (top != null ) {
891
- rect .setHeight (rect .getHeight () - (float )top );
892
- }
893
- if (left != null ) {
894
- rect .setX (rect .getX () + (float )left ).setWidth (rect .getWidth () - (float )left );
887
+ if (top == null && bottom == null ) {
888
+ top = 0f ;
895
889
}
896
890
897
- if (right != null ) {
898
- UnitValue width = this .<UnitValue >getProperty (Property .WIDTH );
899
- if (left == null && width != null ) {
900
- float widthValue = width .isPointValue () ? width .getValue () : (width .getValue () * initialWidth );
901
- float placeLeft = rect .getWidth () - widthValue ;
902
- if (placeLeft > 0 ) {
903
- float computedRight = Math .min (placeLeft , (float )right );
904
- rect .setX (rect .getX () + rect .getWidth () - computedRight - widthValue );
905
- }
906
- } else if (width == null ) {
907
- rect .setWidth (rect .getWidth () - (float )right );
891
+ try {
892
+ if (right != null ) {
893
+ move (parentRect .getRight () - (float ) right - occupiedArea .getBBox ().getRight (), 0 );
908
894
}
909
- }
910
895
911
- if (bottom != null ) {
912
- if (minHeight != null ) {
913
- rect .setHeight ((float )minHeight + (float )bottom );
914
- } else {
915
- float minHeightValue = rect .getHeight () - (float )bottom ;
916
- Float currentMaxHeight = this .getPropertyAsFloat (Property .MAX_HEIGHT );
917
- if (currentMaxHeight != null ) {
918
- minHeightValue = Math .min (minHeightValue , (float )currentMaxHeight );
919
- }
920
- setProperty (Property .MIN_HEIGHT , minHeightValue );
896
+ if (left != null ) {
897
+ move (parentRect .getLeft () + (float ) left - occupiedArea .getBBox ().getLeft (), 0 );
921
898
}
899
+
900
+ if (top != null ) {
901
+ move (0 , parentRect .getTop () - (float ) top - occupiedArea .getBBox ().getTop ());
902
+ }
903
+
904
+ if (bottom != null ) {
905
+ move (0 , parentRect .getBottom () + (float ) bottom - occupiedArea .getBBox ().getBottom ());
906
+ }
907
+ } catch (NullPointerException exc ) {
908
+ Logger logger = LoggerFactory .getLogger (AbstractRenderer .class );
909
+ logger .error (MessageFormatUtil .format (LogMessageConstant .OCCUPIED_AREA_HAS_NOT_BEEN_INITIALIZED , "Absolute positioning might be applied incorrectly." ));
922
910
}
923
911
}
924
912
@@ -1269,6 +1257,31 @@ static boolean noAbsolutePositionInfo(IRenderer renderer) {
1269
1257
return !renderer .hasProperty (Property .TOP ) && !renderer .hasProperty (Property .BOTTOM ) && !renderer .hasProperty (Property .LEFT ) && !renderer .hasProperty (Property .RIGHT );
1270
1258
}
1271
1259
1260
+ static Float getPropertyAsFloat (IRenderer renderer , int property ) {
1261
+ return NumberUtil .asFloat (renderer .<Object >getProperty (property ));
1262
+ }
1263
+
1264
+ static void applyGeneratedAccessibleAttributes (TagTreePointer tagPointer , PdfDictionary attributes ) {
1265
+ if (attributes == null ) {
1266
+ return ;
1267
+ }
1268
+
1269
+ // TODO if taggingPointer.getProperties will always write directly to struct elem, use it instead (add addAttributes overload with index)
1270
+ PdfStructElem structElem = tagPointer .getDocument ().getTagStructureContext ().getPointerStructElem (tagPointer );
1271
+ PdfObject structElemAttr = structElem .getAttributes (false );
1272
+ if (structElemAttr == null || !structElemAttr .isDictionary () && !structElemAttr .isArray ()) {
1273
+ structElem .setAttributes (attributes );
1274
+ } else if (structElemAttr .isDictionary ()) {
1275
+ PdfArray attrArr = new PdfArray ();
1276
+ attrArr .add (attributes );
1277
+ attrArr .add (structElemAttr );
1278
+ structElem .setAttributes (attrArr );
1279
+ } else { // isArray
1280
+ PdfArray attrArr = (PdfArray ) structElemAttr ;
1281
+ attrArr .add (0 , attributes );
1282
+ }
1283
+ }
1284
+
1272
1285
void shrinkOccupiedAreaForAbsolutePosition () {
1273
1286
// In case of absolute positioning and not specified left, right, width values, the parent box is shrunk to fit
1274
1287
// the children. It does not occupy all the available width if it does not need to.
@@ -1327,24 +1340,55 @@ PdfFont resolveFirstPdfFont(String font, FontProvider provider, FontCharacterist
1327
1340
return provider .getPdfFont (provider .getFontSelector (FontFamilySplitter .splitFontFamily (font ), fc ).bestMatch ());
1328
1341
}
1329
1342
1330
- static void applyGeneratedAccessibleAttributes ( TagTreePointer tagPointer , PdfDictionary attributes ) {
1331
- if (attributes == null ) {
1332
- return ;
1343
+ void applyAbsolutePositionIfNeeded ( LayoutContext layoutContext ) {
1344
+ if (isAbsolutePosition () ) {
1345
+ applyAbsolutePosition ( layoutContext instanceof PositionedLayoutContext ? (( PositionedLayoutContext ) layoutContext ). getParentOccupiedArea (). getBBox () : layoutContext . getArea (). getBBox ()) ;
1333
1346
}
1347
+ }
1334
1348
1335
- // TODO if taggingPointer.getProperties will always write directly to struct elem, use it instead (add addAttributes overload with index)
1336
- PdfStructElem structElem = tagPointer .getDocument ().getTagStructureContext ().getPointerStructElem (tagPointer );
1337
- PdfObject structElemAttr = structElem .getAttributes (false );
1338
- if (structElemAttr == null || !structElemAttr .isDictionary () && !structElemAttr .isArray ()) {
1339
- structElem .setAttributes (attributes );
1340
- } else if (structElemAttr .isDictionary ()) {
1341
- PdfArray attrArr = new PdfArray ();
1342
- attrArr .add (attributes );
1343
- attrArr .add (structElemAttr );
1344
- structElem .setAttributes (attrArr );
1345
- } else { // isArray
1346
- PdfArray attrArr = (PdfArray ) structElemAttr ;
1347
- attrArr .add (0 , attributes );
1349
+ void preparePositionedRendererAndAreaForLayout (IRenderer childPositionedRenderer , Rectangle fullBbox , Rectangle parentBbox ) {
1350
+ Float left = getPropertyAsFloat (childPositionedRenderer , Property .LEFT );
1351
+ Float right = getPropertyAsFloat (childPositionedRenderer , Property .RIGHT );
1352
+ Float top = getPropertyAsFloat (childPositionedRenderer , Property .TOP );
1353
+ Float bottom = getPropertyAsFloat (childPositionedRenderer , Property .BOTTOM );
1354
+ childPositionedRenderer .setParent (this );
1355
+ adjustPositionedRendererLayoutBoxWidth (childPositionedRenderer , fullBbox , left , right );
1356
+
1357
+ if (Integer .valueOf (LayoutPosition .ABSOLUTE ).equals (childPositionedRenderer .<Integer >getProperty (Property .POSITION ))) {
1358
+ updateMinHeightForAbsolutelyPositionedRenderer (childPositionedRenderer , parentBbox , top , bottom );
1359
+ }
1360
+ }
1361
+
1362
+ private void updateMinHeightForAbsolutelyPositionedRenderer (IRenderer renderer , Rectangle parentRendererBox , Float top , Float bottom ) {
1363
+ if (top != null && bottom != null && !renderer .hasProperty (Property .HEIGHT )) {
1364
+ Float currentMaxHeight = getPropertyAsFloat (renderer , Property .MAX_HEIGHT );
1365
+ Float currentMinHeight = getPropertyAsFloat (renderer , Property .MIN_HEIGHT );
1366
+ float resolvedMinHeight = Math .max (0 , parentRendererBox .getTop () - (float ) top - parentRendererBox .getBottom () - (float ) bottom );
1367
+ if (currentMinHeight != null ) {
1368
+ resolvedMinHeight = Math .max (resolvedMinHeight , (float ) currentMinHeight );
1369
+ }
1370
+ if (currentMaxHeight != null ) {
1371
+ resolvedMinHeight = Math .min (resolvedMinHeight , (float ) currentMaxHeight );
1372
+ }
1373
+ renderer .setProperty (Property .MIN_HEIGHT , resolvedMinHeight );
1374
+ }
1375
+ }
1376
+
1377
+ private void adjustPositionedRendererLayoutBoxWidth (IRenderer renderer , Rectangle fullBbox , Float left , Float right ) {
1378
+ if (left != null ) {
1379
+ fullBbox .setWidth (fullBbox .getWidth () - (float )left ).setX (fullBbox .getX () + (float )left );
1380
+ }
1381
+ if (right != null ) {
1382
+ fullBbox .setWidth (fullBbox .getWidth () - (float )right );
1383
+ }
1384
+
1385
+ if (left == null && right == null && !renderer .hasProperty (Property .WIDTH )) {
1386
+ // Other, non-block renderers won't occupy full width anyway
1387
+ MinMaxWidth minMaxWidth = renderer instanceof BlockRenderer ? ((BlockRenderer ) renderer ).getMinMaxWidth (MinMaxWidthUtils .getMax ()) : null ;
1388
+ if (minMaxWidth != null && minMaxWidth .getMaxWidth () < fullBbox .getWidth ()) {
1389
+ fullBbox .setWidth (minMaxWidth .getMaxWidth () + AbstractRenderer .EPS );
1390
+ }
1348
1391
}
1349
1392
}
1393
+
1350
1394
}
0 commit comments