Skip to content

Commit 6b791d9

Browse files
Snipxitext-teamcity
authored andcommitted
Improve absolute positioning support
DEVSIX-1381 Autoported commit. Original commit hash: [b8ddb8362]
1 parent ee8400a commit 6b791d9

File tree

7 files changed

+187
-78
lines changed

7 files changed

+187
-78
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace iText.Layout.Layout {
2+
public class PositionedLayoutContext : LayoutContext {
3+
private LayoutArea parentOccupiedArea;
4+
5+
public PositionedLayoutContext(LayoutArea area, LayoutArea parentOccupiedArea)
6+
: base(area) {
7+
this.parentOccupiedArea = parentOccupiedArea;
8+
}
9+
10+
public virtual LayoutArea GetParentOccupiedArea() {
11+
return parentOccupiedArea;
12+
}
13+
}
14+
}

itext/itext.layout/itext/layout/renderer/AbstractRenderer.cs

Lines changed: 143 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,33 @@ public virtual TransparentColor GetPropertyAsTransparentColor(int property) {
335335
return this.GetProperty<TransparentColor>(property);
336336
}
337337

338+
/// <summary>Returns a property with a certain key, as a floating point value.</summary>
339+
/// <param name="property">
340+
/// an
341+
/// <see cref="iText.Layout.Properties.Property">enum value</see>
342+
/// </param>
343+
/// <returns>
344+
/// a
345+
/// <see cref="float?"/>
346+
/// </returns>
347+
public virtual float? GetPropertyAsFloat(int property) {
348+
return NumberUtil.AsFloat(this.GetProperty<Object>(property));
349+
}
350+
351+
/// <summary>Returns a property with a certain key, as a floating point value.</summary>
352+
/// <param name="property">
353+
/// an
354+
/// <see cref="iText.Layout.Properties.Property">enum value</see>
355+
/// </param>
356+
/// <param name="defaultValue">default value to be returned if property is not found</param>
357+
/// <returns>
358+
/// a
359+
/// <see cref="float?"/>
360+
/// </returns>
361+
public virtual float? GetPropertyAsFloat(int property, float? defaultValue) {
362+
return NumberUtil.AsFloat(this.GetProperty<Object>(property, defaultValue));
363+
}
364+
338365
/// <summary>Returns a property with a certain key, as a boolean value.</summary>
339366
/// <param name="property">
340367
/// an
@@ -348,6 +375,19 @@ public virtual TransparentColor GetPropertyAsTransparentColor(int property) {
348375
return this.GetProperty<bool?>(property);
349376
}
350377

378+
/// <summary>Returns a property with a certain key, as an integer value.</summary>
379+
/// <param name="property">
380+
/// an
381+
/// <see cref="iText.Layout.Properties.Property">enum value</see>
382+
/// </param>
383+
/// <returns>
384+
/// a
385+
/// <see cref="int?"/>
386+
/// </returns>
387+
public virtual int? GetPropertyAsInteger(int property) {
388+
return NumberUtil.AsInteger(this.GetProperty<Object>(property));
389+
}
390+
351391
/// <summary>Returns a string representation of the renderer.</summary>
352392
/// <returns>
353393
/// a
@@ -857,53 +897,37 @@ protected internal virtual Rectangle ApplyBorderBox(Rectangle rect, Border[] bor
857897
return rect.ApplyMargins<Rectangle>(topWidth, rightWidth, bottomWidth, leftWidth, reverse);
858898
}
859899

860-
protected internal virtual void ApplyAbsolutePosition(Rectangle rect) {
900+
protected internal virtual void ApplyAbsolutePosition(Rectangle parentRect) {
861901
float? top = this.GetPropertyAsFloat(Property.TOP);
862902
float? bottom = this.GetPropertyAsFloat(Property.BOTTOM);
863903
float? left = this.GetPropertyAsFloat(Property.LEFT);
864904
float? right = this.GetPropertyAsFloat(Property.RIGHT);
865-
float initialHeight = rect.GetHeight();
866-
float initialWidth = rect.GetWidth();
867-
float? minHeight = this.GetPropertyAsFloat(Property.MIN_HEIGHT);
868-
if (minHeight != null && rect.GetHeight() < (float)minHeight) {
869-
float difference = (float)minHeight - rect.GetHeight();
870-
rect.MoveDown(difference).SetHeight(rect.GetHeight() + difference);
905+
if (left == null && right == null && BaseDirection.RIGHT_TO_LEFT.Equals(this.GetProperty<BaseDirection?>(Property
906+
.BASE_DIRECTION))) {
907+
right = 0f;
871908
}
872-
if (top != null) {
873-
rect.SetHeight(rect.GetHeight() - (float)top);
874-
}
875-
if (left != null) {
876-
rect.SetX(rect.GetX() + (float)left).SetWidth(rect.GetWidth() - (float)left);
909+
if (top == null && bottom == null) {
910+
top = 0f;
877911
}
878-
if (right != null) {
879-
UnitValue width = this.GetProperty<UnitValue>(Property.WIDTH);
880-
if (left == null && width != null) {
881-
float widthValue = width.IsPointValue() ? width.GetValue() : (width.GetValue() * initialWidth);
882-
float placeLeft = rect.GetWidth() - widthValue;
883-
if (placeLeft > 0) {
884-
float computedRight = Math.Min(placeLeft, (float)right);
885-
rect.SetX(rect.GetX() + rect.GetWidth() - computedRight - widthValue);
886-
}
912+
try {
913+
if (right != null) {
914+
Move(parentRect.GetRight() - (float)right - occupiedArea.GetBBox().GetRight(), 0);
887915
}
888-
else {
889-
if (width == null) {
890-
rect.SetWidth(rect.GetWidth() - (float)right);
891-
}
916+
if (left != null) {
917+
Move(parentRect.GetLeft() + (float)left - occupiedArea.GetBBox().GetLeft(), 0);
892918
}
893-
}
894-
if (bottom != null) {
895-
if (minHeight != null) {
896-
rect.SetHeight((float)minHeight + (float)bottom);
919+
if (top != null) {
920+
Move(0, parentRect.GetTop() - (float)top - occupiedArea.GetBBox().GetTop());
897921
}
898-
else {
899-
float minHeightValue = rect.GetHeight() - (float)bottom;
900-
float? currentMaxHeight = this.GetPropertyAsFloat(Property.MAX_HEIGHT);
901-
if (currentMaxHeight != null) {
902-
minHeightValue = Math.Min(minHeightValue, (float)currentMaxHeight);
903-
}
904-
SetProperty(Property.MIN_HEIGHT, minHeightValue);
922+
if (bottom != null) {
923+
Move(0, parentRect.GetBottom() + (float)bottom - occupiedArea.GetBBox().GetBottom());
905924
}
906925
}
926+
catch (ArgumentNullException) {
927+
ILogger logger = LoggerFactory.GetLogger(typeof(iText.Layout.Renderer.AbstractRenderer));
928+
logger.Error(MessageFormatUtil.Format(iText.IO.LogMessageConstant.OCCUPIED_AREA_HAS_NOT_BEEN_INITIALIZED,
929+
"Absolute positioning might be applied incorrectly."));
930+
}
907931
}
908932

909933
protected internal virtual void ApplyRelativePositioningTranslation(bool reverse) {
@@ -1211,9 +1235,9 @@ protected internal virtual float[] CalculateShiftToPositionBBoxOfPointsAt(float
12111235
}
12121236

12131237
protected internal virtual void OverrideHeightProperties() {
1214-
float? height = this.GetPropertyAsFloat(Property.HEIGHT);
1215-
float? maxHeight = this.GetPropertyAsFloat(Property.MAX_HEIGHT);
1216-
float? minHeight = this.GetPropertyAsFloat(Property.MIN_HEIGHT);
1238+
float? height = this.GetPropertyAsFloat<float>(Property.HEIGHT);
1239+
float? maxHeight = this.GetPropertyAsFloat<float>(Property.MAX_HEIGHT);
1240+
float? minHeight = this.GetPropertyAsFloat<float>(Property.MIN_HEIGHT);
12171241
if (null != height) {
12181242
if (null == maxHeight || height < maxHeight) {
12191243
maxHeight = height;
@@ -1271,6 +1295,37 @@ internal static bool NoAbsolutePositionInfo(IRenderer renderer) {
12711295
(Property.LEFT) && !renderer.HasProperty(Property.RIGHT);
12721296
}
12731297

1298+
internal static float? GetPropertyAsFloat(IRenderer renderer, int property) {
1299+
return NumberUtil.AsFloat(renderer.GetProperty<Object>(property));
1300+
}
1301+
1302+
internal static void ApplyGeneratedAccessibleAttributes(TagTreePointer tagPointer, PdfDictionary attributes
1303+
) {
1304+
if (attributes == null) {
1305+
return;
1306+
}
1307+
// TODO if taggingPointer.getProperties will always write directly to struct elem, use it instead (add addAttributes overload with index)
1308+
PdfStructElem structElem = tagPointer.GetDocument().GetTagStructureContext().GetPointerStructElem(tagPointer
1309+
);
1310+
PdfObject structElemAttr = structElem.GetAttributes(false);
1311+
if (structElemAttr == null || !structElemAttr.IsDictionary() && !structElemAttr.IsArray()) {
1312+
structElem.SetAttributes(attributes);
1313+
}
1314+
else {
1315+
if (structElemAttr.IsDictionary()) {
1316+
PdfArray attrArr = new PdfArray();
1317+
attrArr.Add(attributes);
1318+
attrArr.Add(structElemAttr);
1319+
structElem.SetAttributes(attrArr);
1320+
}
1321+
else {
1322+
// isArray
1323+
PdfArray attrArr = (PdfArray)structElemAttr;
1324+
attrArr.Add(0, attributes);
1325+
}
1326+
}
1327+
}
1328+
12741329
internal virtual void ShrinkOccupiedAreaForAbsolutePosition() {
12751330
// In case of absolute positioning and not specified left, right, width values, the parent box is shrunk to fit
12761331
// the children. It does not occupy all the available width if it does not need to.
@@ -1335,29 +1390,58 @@ internal virtual PdfFont ResolveFirstPdfFont(String font, FontProvider provider,
13351390
());
13361391
}
13371392

1338-
internal static void ApplyGeneratedAccessibleAttributes(TagTreePointer tagPointer, PdfDictionary attributes
1339-
) {
1340-
if (attributes == null) {
1341-
return;
1393+
internal virtual void ApplyAbsolutePositionIfNeeded(LayoutContext layoutContext) {
1394+
if (IsAbsolutePosition()) {
1395+
ApplyAbsolutePosition(layoutContext is PositionedLayoutContext ? ((PositionedLayoutContext)layoutContext).
1396+
GetParentOccupiedArea().GetBBox() : layoutContext.GetArea().GetBBox());
13421397
}
1343-
// TODO if taggingPointer.getProperties will always write directly to struct elem, use it instead (add addAttributes overload with index)
1344-
PdfStructElem structElem = tagPointer.GetDocument().GetTagStructureContext().GetPointerStructElem(tagPointer
1345-
);
1346-
PdfObject structElemAttr = structElem.GetAttributes(false);
1347-
if (structElemAttr == null || !structElemAttr.IsDictionary() && !structElemAttr.IsArray()) {
1348-
structElem.SetAttributes(attributes);
1398+
}
1399+
1400+
internal virtual void PreparePositionedRendererAndAreaForLayout(IRenderer childPositionedRenderer, Rectangle
1401+
fullBbox, Rectangle parentBbox) {
1402+
float? left = GetPropertyAsFloat(childPositionedRenderer, Property.LEFT);
1403+
float? right = GetPropertyAsFloat(childPositionedRenderer, Property.RIGHT);
1404+
float? top = GetPropertyAsFloat(childPositionedRenderer, Property.TOP);
1405+
float? bottom = GetPropertyAsFloat(childPositionedRenderer, Property.BOTTOM);
1406+
childPositionedRenderer.SetParent(this);
1407+
AdjustPositionedRendererLayoutBoxWidth(childPositionedRenderer, fullBbox, left, right);
1408+
if (System.Convert.ToInt32(LayoutPosition.ABSOLUTE).Equals(childPositionedRenderer.GetProperty<int?>(Property
1409+
.POSITION))) {
1410+
UpdateMinHeightForAbsolutelyPositionedRenderer(childPositionedRenderer, parentBbox, top, bottom);
13491411
}
1350-
else {
1351-
if (structElemAttr.IsDictionary()) {
1352-
PdfArray attrArr = new PdfArray();
1353-
attrArr.Add(attributes);
1354-
attrArr.Add(structElemAttr);
1355-
structElem.SetAttributes(attrArr);
1412+
}
1413+
1414+
private void UpdateMinHeightForAbsolutelyPositionedRenderer(IRenderer renderer, Rectangle parentRendererBox
1415+
, float? top, float? bottom) {
1416+
if (top != null && bottom != null && !renderer.HasProperty(Property.HEIGHT)) {
1417+
float? currentMaxHeight = GetPropertyAsFloat(renderer, Property.MAX_HEIGHT);
1418+
float? currentMinHeight = GetPropertyAsFloat(renderer, Property.MIN_HEIGHT);
1419+
float resolvedMinHeight = Math.Max(0, parentRendererBox.GetTop() - (float)top - parentRendererBox.GetBottom
1420+
() - (float)bottom);
1421+
if (currentMinHeight != null) {
1422+
resolvedMinHeight = Math.Max(resolvedMinHeight, (float)currentMinHeight);
13561423
}
1357-
else {
1358-
// isArray
1359-
PdfArray attrArr = (PdfArray)structElemAttr;
1360-
attrArr.Add(0, attributes);
1424+
if (currentMaxHeight != null) {
1425+
resolvedMinHeight = Math.Min(resolvedMinHeight, (float)currentMaxHeight);
1426+
}
1427+
renderer.SetProperty(Property.MIN_HEIGHT, resolvedMinHeight);
1428+
}
1429+
}
1430+
1431+
private void AdjustPositionedRendererLayoutBoxWidth(IRenderer renderer, Rectangle fullBbox, float? left, float?
1432+
right) {
1433+
if (left != null) {
1434+
fullBbox.SetWidth(fullBbox.GetWidth() - (float)left).SetX(fullBbox.GetX() + (float)left);
1435+
}
1436+
if (right != null) {
1437+
fullBbox.SetWidth(fullBbox.GetWidth() - (float)right);
1438+
}
1439+
if (left == null && right == null && !renderer.HasProperty(Property.WIDTH)) {
1440+
// Other, non-block renderers won't occupy full width anyway
1441+
MinMaxWidth minMaxWidth = renderer is BlockRenderer ? ((BlockRenderer)renderer).GetMinMaxWidth(MinMaxWidthUtils
1442+
.GetMax()) : null;
1443+
if (minMaxWidth != null && minMaxWidth.GetMaxWidth() < fullBbox.GetWidth()) {
1444+
fullBbox.SetWidth(minMaxWidth.GetMaxWidth() + iText.Layout.Renderer.AbstractRenderer.EPS);
13611445
}
13621446
}
13631447
}

itext/itext.layout/itext/layout/renderer/BlockRenderer.cs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ public override LayoutResult Layout(LayoutContext layoutContext) {
296296
ApplyBorderBox(occupiedArea.GetBBox(), borders, true);
297297
ApplyMargins(occupiedArea.GetBBox(), true);
298298
//splitRenderer.occupiedArea = occupiedArea.clone();
299+
ApplyAbsolutePositionIfNeeded(layoutContext);
299300
LayoutArea editedArea = FloatingHelper.AdjustResultOccupiedAreaForFloatAndClear(this, layoutContext.GetFloatRendererAreas
300301
(), layoutContext.GetArea().GetBBox(), clearHeightCorrection, marginsCollapsingEnabled);
301302
if (true.Equals(GetPropertyAsBoolean(Property.FORCED_PLACEMENT)) || wasHeightClipped) {
@@ -322,6 +323,12 @@ public override LayoutResult Layout(LayoutContext layoutContext) {
322323
occupiedArea.SetBBox(Rectangle.GetCommonRectangle(occupiedArea.GetBBox(), result.GetOccupiedArea().GetBBox
323324
()));
324325
}
326+
else {
327+
if (IsAbsolutePosition() && childRenderer.GetOccupiedArea() != null) {
328+
occupiedArea.SetBBox(Rectangle.GetCommonRectangle(occupiedArea.GetBBox(), childRenderer.GetOccupiedArea().
329+
GetBBox()));
330+
}
331+
}
325332
}
326333
if (marginsCollapsingEnabled) {
327334
marginsCollapseHandler.EndChildMarginsHandling(layoutBox);
@@ -376,20 +383,26 @@ public override LayoutResult Layout(LayoutContext layoutContext) {
376383
}
377384
}
378385
}
386+
if (positionedRenderers.Count > 0) {
387+
foreach (IRenderer childPositionedRenderer in positionedRenderers) {
388+
Rectangle fullBbox = occupiedArea.GetBBox().Clone();
389+
// Use that value so that layout is independent of whether we are in the bottom of the page or in the top of the page
390+
float layoutMinHeight = 1000;
391+
fullBbox.MoveDown(layoutMinHeight).SetHeight(layoutMinHeight + fullBbox.GetHeight());
392+
LayoutArea parentArea = new LayoutArea(occupiedArea.GetPageNumber(), occupiedArea.GetBBox().Clone());
393+
ApplyPaddings(parentArea.GetBBox(), paddings, true);
394+
PreparePositionedRendererAndAreaForLayout(childPositionedRenderer, fullBbox, parentArea.GetBBox());
395+
childPositionedRenderer.Layout(new PositionedLayoutContext(new LayoutArea(occupiedArea.GetPageNumber(), fullBbox
396+
), parentArea));
397+
}
398+
}
379399
if (isPositioned) {
380400
CorrectPositionedLayout(layoutBox);
381401
}
382402
ApplyPaddings(occupiedArea.GetBBox(), paddings, true);
383403
ApplyBorderBox(occupiedArea.GetBBox(), borders, true);
384-
if (positionedRenderers.Count > 0) {
385-
LayoutArea area = new LayoutArea(occupiedArea.GetPageNumber(), occupiedArea.GetBBox().Clone());
386-
ApplyBorderBox(area.GetBBox(), false);
387-
foreach (IRenderer childPositionedRenderer in positionedRenderers) {
388-
childPositionedRenderer.SetParent(this).Layout(new LayoutContext(area));
389-
}
390-
ApplyBorderBox(area.GetBBox(), true);
391-
}
392404
ApplyMargins(occupiedArea.GetBBox(), true);
405+
ApplyAbsolutePositionIfNeeded(layoutContext);
393406
if (rotation != null) {
394407
ApplyRotationLayout(layoutContext.GetArea().GetBBox().Clone());
395408
if (IsNotFittingLayoutArea(layoutContext.GetArea())) {
@@ -674,6 +687,7 @@ protected internal virtual void EndRotationIfApplied(PdfCanvas canvas) {
674687
}
675688
}
676689

690+
[Obsolete]
677691
protected internal virtual void CorrectPositionedLayout(Rectangle layoutBox) {
678692
if (IsFixedLayout()) {
679693
float y = (float)this.GetPropertyAsFloat(Property.Y);
@@ -682,7 +696,6 @@ protected internal virtual void CorrectPositionedLayout(Rectangle layoutBox) {
682696
}
683697
}
684698

685-
//TODO
686699
protected internal virtual float ApplyBordersPaddingsMargins(Rectangle parentBBox, Border[] borders, float
687700
[] paddings) {
688701
float parentWidth = parentBBox.GetWidth();
@@ -694,11 +707,6 @@ protected internal virtual float ApplyBordersPaddingsMargins(Rectangle parentBBo
694707
float relativeX = IsFixedLayout() ? 0 : parentBBox.GetX();
695708
parentBBox.SetX(relativeX + x);
696709
}
697-
else {
698-
if (IsAbsolutePosition()) {
699-
ApplyAbsolutePosition(parentBBox);
700-
}
701-
}
702710
}
703711
ApplyPaddings(parentBBox, paddings, false);
704712
return parentWidth - parentBBox.GetWidth();

0 commit comments

Comments
 (0)