public override void AddChild(IRenderer renderer) { LayoutTaggingHelper taggingHelper = this.GetProperty <LayoutTaggingHelper>(Property.TAGGING_HELPER); if (taggingHelper != null) { LayoutTaggingHelper.AddTreeHints(taggingHelper, renderer); } // Some positioned renderers might have been fetched from non-positioned child and added to this renderer, // so we use this generic mechanism of determining which renderers have been just added. int numberOfChildRenderers = childRenderers.Count; int numberOfPositionedChildRenderers = positionedRenderers.Count; base.AddChild(renderer); IList <IRenderer> addedRenderers = new List <IRenderer>(1); IList <IRenderer> addedPositionedRenderers = new List <IRenderer>(1); while (childRenderers.Count > numberOfChildRenderers) { addedRenderers.Add(childRenderers[numberOfChildRenderers]); childRenderers.JRemoveAt(numberOfChildRenderers); } while (positionedRenderers.Count > numberOfPositionedChildRenderers) { addedPositionedRenderers.Add(positionedRenderers[numberOfPositionedChildRenderers]); positionedRenderers.JRemoveAt(numberOfPositionedChildRenderers); } bool marginsCollapsingEnabled = true.Equals(GetPropertyAsBoolean(Property.COLLAPSING_MARGINS)); if (currentArea == null) { UpdateCurrentAndInitialArea(null); if (marginsCollapsingEnabled) { marginsCollapseHandler = new MarginsCollapseHandler(this, null); } } // Static layout for (int i = 0; currentArea != null && i < addedRenderers.Count; i++) { renderer = addedRenderers[i]; bool rendererIsFloat = FloatingHelper.IsRendererFloating(renderer); bool clearanceOverflowsToNextPage = FloatingHelper.IsClearanceApplied(waitingNextPageRenderers, renderer.GetProperty <ClearPropertyValue?>(Property.CLEAR)); if (rendererIsFloat && (floatOverflowedCompletely || clearanceOverflowsToNextPage)) { waitingNextPageRenderers.Add(renderer); floatOverflowedCompletely = true; continue; } ProcessWaitingKeepWithNextElement(renderer); IList <IRenderer> resultRenderers = new List <IRenderer>(); LayoutResult result = null; RootLayoutArea storedArea = null; RootLayoutArea nextStoredArea = null; MarginsCollapseInfo childMarginsInfo = null; if (marginsCollapsingEnabled && currentArea != null && renderer != null) { childMarginsInfo = marginsCollapseHandler.StartChildMarginsHandling(renderer, currentArea.GetBBox()); } while (clearanceOverflowsToNextPage || currentArea != null && renderer != null && (result = renderer.SetParent (this).Layout(new LayoutContext(currentArea.Clone(), childMarginsInfo, floatRendererAreas))).GetStatus () != LayoutResult.FULL) { bool currentAreaNeedsToBeUpdated = false; if (clearanceOverflowsToNextPage) { result = new LayoutResult(LayoutResult.NOTHING, null, null, renderer); currentAreaNeedsToBeUpdated = true; } if (result.GetStatus() == LayoutResult.PARTIAL) { if (rendererIsFloat) { waitingNextPageRenderers.Add(result.GetOverflowRenderer()); break; } else { ProcessRenderer(result.GetSplitRenderer(), resultRenderers); if (nextStoredArea != null) { currentArea = nextStoredArea; currentPageNumber = nextStoredArea.GetPageNumber(); nextStoredArea = null; } else { currentAreaNeedsToBeUpdated = true; } } } else { if (result.GetStatus() == LayoutResult.NOTHING && !clearanceOverflowsToNextPage) { if (result.GetOverflowRenderer() is ImageRenderer) { float imgHeight = ((ImageRenderer)result.GetOverflowRenderer()).GetOccupiedArea().GetBBox().GetHeight(); if (!floatRendererAreas.IsEmpty() || currentArea.GetBBox().GetHeight() < imgHeight && !currentArea.IsEmptyArea ()) { if (rendererIsFloat) { waitingNextPageRenderers.Add(result.GetOverflowRenderer()); floatOverflowedCompletely = true; break; } currentAreaNeedsToBeUpdated = true; } else { ((ImageRenderer)result.GetOverflowRenderer()).AutoScale(currentArea); result.GetOverflowRenderer().SetProperty(Property.FORCED_PLACEMENT, true); ILog logger = LogManager.GetLogger(typeof(RootRenderer)); logger.Warn(MessageFormatUtil.Format(iText.IO.LogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "")); } } else { if (currentArea.IsEmptyArea() && result.GetAreaBreak() == null) { if (true.Equals(result.GetOverflowRenderer().GetModelElement().GetProperty <bool?>(Property.KEEP_TOGETHER)) ) { result.GetOverflowRenderer().GetModelElement().SetProperty(Property.KEEP_TOGETHER, false); ILog logger = LogManager.GetLogger(typeof(RootRenderer)); logger.Warn(MessageFormatUtil.Format(iText.IO.LogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "KeepTogether property will be ignored." )); if (storedArea != null) { nextStoredArea = currentArea; currentArea = storedArea; currentPageNumber = storedArea.GetPageNumber(); } storedArea = currentArea; } else { if (null != result.GetCauseOfNothing() && true.Equals(result.GetCauseOfNothing().GetProperty <bool?>(Property .KEEP_TOGETHER))) { // set KEEP_TOGETHER false on the deepest parent (maybe the element itself) to have KEEP_TOGETHER == true IRenderer theDeepestKeptTogether = result.GetCauseOfNothing(); IRenderer parent; while (null == theDeepestKeptTogether.GetModelElement() || null == theDeepestKeptTogether.GetModelElement( ).GetOwnProperty <bool?>(Property.KEEP_TOGETHER)) { parent = ((AbstractRenderer)theDeepestKeptTogether).parent; if (parent == null) { break; } theDeepestKeptTogether = parent; } theDeepestKeptTogether.GetModelElement().SetProperty(Property.KEEP_TOGETHER, false); ILog logger = LogManager.GetLogger(typeof(RootRenderer)); logger.Warn(MessageFormatUtil.Format(iText.IO.LogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "KeepTogether property of inner element will be ignored." )); } else { if (!true.Equals(renderer.GetProperty <bool?>(Property.FORCED_PLACEMENT))) { result.GetOverflowRenderer().SetProperty(Property.FORCED_PLACEMENT, true); ILog logger = LogManager.GetLogger(typeof(RootRenderer)); logger.Warn(MessageFormatUtil.Format(iText.IO.LogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, "")); } else { // FORCED_PLACEMENT was already set to the renderer and // LogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA message was logged. // This else-clause should never be hit, otherwise there is a bug in FORCED_PLACEMENT implementation. System.Diagnostics.Debug.Assert(false); // Still handling this case in order to avoid nasty infinite loops. break; } } } } else { storedArea = currentArea; if (nextStoredArea != null) { currentArea = nextStoredArea; currentPageNumber = nextStoredArea.GetPageNumber(); nextStoredArea = null; } else { if (rendererIsFloat) { waitingNextPageRenderers.Add(result.GetOverflowRenderer()); floatOverflowedCompletely = true; break; } currentAreaNeedsToBeUpdated = true; } } } } } renderer = result.GetOverflowRenderer(); if (marginsCollapsingEnabled) { marginsCollapseHandler.EndChildMarginsHandling(currentArea.GetBBox()); } if (currentAreaNeedsToBeUpdated) { UpdateCurrentAndInitialArea(result); } if (marginsCollapsingEnabled) { marginsCollapseHandler = new MarginsCollapseHandler(this, null); childMarginsInfo = marginsCollapseHandler.StartChildMarginsHandling(renderer, currentArea.GetBBox()); } clearanceOverflowsToNextPage = clearanceOverflowsToNextPage && FloatingHelper.IsClearanceApplied(waitingNextPageRenderers , renderer.GetProperty <ClearPropertyValue?>(Property.CLEAR)); } if (marginsCollapsingEnabled) { marginsCollapseHandler.EndChildMarginsHandling(currentArea.GetBBox()); } if (null != result && null != result.GetSplitRenderer()) { renderer = result.GetSplitRenderer(); } // Keep renderer until next element is added for future keep with next adjustments if (renderer != null && result != null) { if (true.Equals(renderer.GetProperty <bool?>(Property.KEEP_WITH_NEXT))) { if (true.Equals(renderer.GetProperty <bool?>(Property.FORCED_PLACEMENT))) { ILog logger = LogManager.GetLogger(typeof(RootRenderer)); logger.Warn(iText.IO.LogMessageConstant.ELEMENT_WAS_FORCE_PLACED_KEEP_WITH_NEXT_WILL_BE_IGNORED); ShrinkCurrentAreaAndProcessRenderer(renderer, resultRenderers, result); } else { keepWithNextHangingRenderer = renderer; keepWithNextHangingRendererLayoutResult = result; } } else { if (result.GetStatus() != LayoutResult.NOTHING) { ShrinkCurrentAreaAndProcessRenderer(renderer, resultRenderers, result); } } } } for (int i = 0; i < addedPositionedRenderers.Count; i++) { positionedRenderers.Add(addedPositionedRenderers[i]); renderer = positionedRenderers[positionedRenderers.Count - 1]; int?positionedPageNumber = renderer.GetProperty <int?>(Property.PAGE_NUMBER); if (positionedPageNumber == null) { positionedPageNumber = currentPageNumber; } LayoutArea layoutArea; // For position=absolute, if none of the top, bottom, left, right properties are provided, // the content should be displayed in the flow of the current content, not overlapping it. // The behavior is just if it would be statically positioned except it does not affect other elements if (Convert.ToInt32(LayoutPosition.ABSOLUTE).Equals(renderer.GetProperty <int?>(Property.POSITION)) && AbstractRenderer .NoAbsolutePositionInfo(renderer)) { layoutArea = new LayoutArea((int)positionedPageNumber, currentArea.GetBBox().Clone()); } else { layoutArea = new LayoutArea((int)positionedPageNumber, initialCurrentArea.GetBBox().Clone()); } Rectangle fullBbox = layoutArea.GetBBox().Clone(); PreparePositionedRendererAndAreaForLayout(renderer, fullBbox, layoutArea.GetBBox()); renderer.Layout(new PositionedLayoutContext(new LayoutArea(layoutArea.GetPageNumber(), fullBbox), layoutArea )); if (immediateFlush) { FlushSingleRenderer(renderer); positionedRenderers.JRemoveAt(positionedRenderers.Count - 1); } } }
private void ProcessWaitingKeepWithNextElement(IRenderer renderer) { if (keepWithNextHangingRenderer != null) { LayoutArea rest = currentArea.Clone(); rest.GetBBox().SetHeight(rest.GetBBox().GetHeight() - keepWithNextHangingRendererLayoutResult.GetOccupiedArea ().GetBBox().GetHeight()); bool ableToProcessKeepWithNext = false; if (renderer.SetParent(this).Layout(new LayoutContext(rest)).GetStatus() != LayoutResult.NOTHING) { // The area break will not be introduced and we are safe to place everything as is ShrinkCurrentAreaAndProcessRenderer(keepWithNextHangingRenderer, new List <IRenderer>(), keepWithNextHangingRendererLayoutResult ); ableToProcessKeepWithNext = true; } else { float originalElementHeight = keepWithNextHangingRendererLayoutResult.GetOccupiedArea().GetBBox().GetHeight (); IList <float> trySplitHeightPoints = new List <float>(); float delta = 35; for (int i = 1; i <= 5 && originalElementHeight - delta * i > originalElementHeight / 2; i++) { trySplitHeightPoints.Add(originalElementHeight - delta * i); } for (int i = 0; i < trySplitHeightPoints.Count && !ableToProcessKeepWithNext; i++) { float curElementSplitHeight = trySplitHeightPoints[i]; RootLayoutArea firstElementSplitLayoutArea = (RootLayoutArea)currentArea.Clone(); firstElementSplitLayoutArea.GetBBox().SetHeight(curElementSplitHeight).MoveUp(currentArea.GetBBox().GetHeight () - curElementSplitHeight); LayoutResult firstElementSplitLayoutResult = keepWithNextHangingRenderer.SetParent(this).Layout(new LayoutContext (firstElementSplitLayoutArea.Clone())); if (firstElementSplitLayoutResult.GetStatus() == LayoutResult.PARTIAL) { RootLayoutArea storedArea = currentArea; UpdateCurrentAndInitialArea(firstElementSplitLayoutResult); LayoutResult firstElementOverflowLayoutResult = firstElementSplitLayoutResult.GetOverflowRenderer().Layout (new LayoutContext(currentArea.Clone())); if (firstElementOverflowLayoutResult.GetStatus() == LayoutResult.FULL) { LayoutArea secondElementLayoutArea = currentArea.Clone(); secondElementLayoutArea.GetBBox().SetHeight(secondElementLayoutArea.GetBBox().GetHeight() - firstElementOverflowLayoutResult .GetOccupiedArea().GetBBox().GetHeight()); LayoutResult secondElementLayoutResult = renderer.SetParent(this).Layout(new LayoutContext(secondElementLayoutArea )); if (secondElementLayoutResult.GetStatus() != LayoutResult.NOTHING) { ableToProcessKeepWithNext = true; currentArea = firstElementSplitLayoutArea; currentPageNumber = firstElementSplitLayoutArea.GetPageNumber(); ShrinkCurrentAreaAndProcessRenderer(firstElementSplitLayoutResult.GetSplitRenderer(), new List <IRenderer>( ), firstElementSplitLayoutResult); UpdateCurrentAndInitialArea(firstElementSplitLayoutResult); ShrinkCurrentAreaAndProcessRenderer(firstElementSplitLayoutResult.GetOverflowRenderer(), new List <IRenderer >(), firstElementOverflowLayoutResult); } } if (!ableToProcessKeepWithNext) { currentArea = storedArea; currentPageNumber = storedArea.GetPageNumber(); } } } } if (!ableToProcessKeepWithNext && !currentArea.IsEmptyArea()) { RootLayoutArea storedArea = currentArea; UpdateCurrentAndInitialArea(null); LayoutResult firstElementLayoutResult = keepWithNextHangingRenderer.SetParent(this).Layout(new LayoutContext (currentArea.Clone())); if (firstElementLayoutResult.GetStatus() == LayoutResult.FULL) { LayoutArea secondElementLayoutArea = currentArea.Clone(); secondElementLayoutArea.GetBBox().SetHeight(secondElementLayoutArea.GetBBox().GetHeight() - firstElementLayoutResult .GetOccupiedArea().GetBBox().GetHeight()); LayoutResult secondElementLayoutResult = renderer.SetParent(this).Layout(new LayoutContext(secondElementLayoutArea )); if (secondElementLayoutResult.GetStatus() != LayoutResult.NOTHING) { ableToProcessKeepWithNext = true; ShrinkCurrentAreaAndProcessRenderer(keepWithNextHangingRenderer, new List <IRenderer>(), keepWithNextHangingRendererLayoutResult ); } } if (!ableToProcessKeepWithNext) { currentArea = storedArea; currentPageNumber = storedArea.GetPageNumber(); } } if (!ableToProcessKeepWithNext) { ILog logger = LogManager.GetLogger(typeof(RootRenderer)); logger.Warn(iText.IO.LogMessageConstant.RENDERER_WAS_NOT_ABLE_TO_PROCESS_KEEP_WITH_NEXT); ShrinkCurrentAreaAndProcessRenderer(keepWithNextHangingRenderer, new List <IRenderer>(), keepWithNextHangingRendererLayoutResult ); } keepWithNextHangingRenderer = null; keepWithNextHangingRendererLayoutResult = null; } }