public virtual void SplitAndOverflowInheritSpecialScriptsWordBreakPoints() { String nonSpecialScriptText = "Some non-special script"; TextRenderer textRenderer = new TextRenderer(new Text(nonSpecialScriptText)); textRenderer.SetProperty(Property.FONT, PdfFontFactory.CreateFont(REGULAR_FONT, PdfEncodings.IDENTITY_H)); textRenderer.SetText(nonSpecialScriptText); NUnit.Framework.Assert.IsNull(textRenderer.GetSpecialScriptsWordBreakPoints()); LineRenderer.IsTextRendererAndRequiresSpecialScriptPreLayoutProcessing(textRenderer); NUnit.Framework.Assert.IsNotNull(textRenderer.GetSpecialScriptsWordBreakPoints()); NUnit.Framework.Assert.IsTrue(textRenderer.GetSpecialScriptsWordBreakPoints().IsEmpty()); // layout is needed prior to calling #split() in order to fill TextRenderer fields required to be non-null PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new MemoryStream())); Document document = new Document(pdfDocument); textRenderer.SetParent(document.GetRenderer()); LayoutArea layoutArea = new LayoutArea(1, new Rectangle(MinMaxWidthUtils.GetInfWidth(), AbstractRenderer.INF )); textRenderer.Layout(new LayoutContext(layoutArea)); TextRenderer[] splitRenderers = textRenderer.Split(nonSpecialScriptText.Length / 2); foreach (TextRenderer split in splitRenderers) { NUnit.Framework.Assert.IsNotNull(split.GetSpecialScriptsWordBreakPoints()); NUnit.Framework.Assert.IsTrue(split.GetSpecialScriptsWordBreakPoints().IsEmpty()); } }
private static float[] ToEffectiveTableColumnWidth(float[] tableColumnWidth) { float[] result = new float[tableColumnWidth.Length]; for (int i = 0; i < result.Length; ++i) { result[i] = tableColumnWidth[i] + MinMaxWidthUtils.GetEps(); } return(result); }
public override MinMaxWidth GetMinMaxWidth() { LayoutResult errorResult = InitializeListSymbols(new LayoutContext(new LayoutArea(1, new Rectangle(MinMaxWidthUtils .GetInfWidth(), AbstractRenderer.INF)))); if (errorResult != null) { return(MinMaxWidthUtils.CountDefaultMinMaxWidth(this)); } return(base.GetMinMaxWidth()); }
/// <summary> /// This method tries to calculate min-max-width of rotated element using heuristics /// of /// <see cref="iText.Layout.Minmaxwidth.RotationMinMaxWidth.Calculate(double, double, iText.Layout.Minmaxwidth.MinMaxWidth) /// "/>. /// </summary> /// <remarks> /// This method tries to calculate min-max-width of rotated element using heuristics /// of /// <see cref="iText.Layout.Minmaxwidth.RotationMinMaxWidth.Calculate(double, double, iText.Layout.Minmaxwidth.MinMaxWidth) /// "/>. /// This method may call /// <see cref="IRenderer.Layout(iText.Layout.Layout.LayoutContext)"/> /// once in best case /// (if the width is set on element, or if we are really lucky) and three times in worst case. /// </remarks> /// <param name="minMaxWidth">the minMaxWidth of NOT rotated renderer</param> /// <param name="renderer">the actual renderer</param> /// <returns>minMaxWidth of rotated renderer or original value in case rotated value can not be calculated, or renderer isn't rotated. /// </returns> public static MinMaxWidth CountRotationMinMaxWidth(MinMaxWidth minMaxWidth, AbstractRenderer renderer) { RotationUtils.PropertiesBackup backup = new RotationUtils.PropertiesBackup(renderer); float?rotation = backup.StoreFloatProperty(Property.ROTATION_ANGLE); if (rotation != null) { float angle = (float)rotation; //This width results in more accurate values for min-width calculations. float layoutWidth = minMaxWidth.GetMaxWidth() + MinMaxWidthUtils.GetEps(); LayoutResult layoutResult = renderer.Layout(new LayoutContext(new LayoutArea(1, new Rectangle(layoutWidth, AbstractRenderer.INF)))); if (layoutResult.GetOccupiedArea() != null) { Rectangle layoutBBox = layoutResult.GetOccupiedArea().GetBBox(); if (MinMaxWidthUtils.IsEqual(minMaxWidth.GetMinWidth(), minMaxWidth.GetMaxWidth())) { backup.RestoreProperty(Property.ROTATION_ANGLE); float rotatedWidth = (float)RotationMinMaxWidth.CalculateRotatedWidth(layoutBBox, angle); return(new MinMaxWidth(rotatedWidth, rotatedWidth, 0)); } double area = layoutResult.GetOccupiedArea().GetBBox().GetWidth() * layoutResult.GetOccupiedArea().GetBBox ().GetHeight(); RotationMinMaxWidth rotationMinMaxWidth = RotationMinMaxWidth.Calculate(angle, area, minMaxWidth); float?rotatedMinWidth = GetLayoutRotatedWidth(renderer, (float)rotationMinMaxWidth.GetMinWidthOrigin(), layoutBBox , angle); if (rotatedMinWidth != null) { if (rotatedMinWidth > rotationMinMaxWidth.GetMaxWidth()) { rotationMinMaxWidth.SetChildrenMinWidth((float)rotatedMinWidth); float?rotatedMaxWidth = GetLayoutRotatedWidth(renderer, (float)rotationMinMaxWidth.GetMaxWidthOrigin(), layoutBBox , angle); if (rotatedMaxWidth != null && rotatedMaxWidth > rotatedMinWidth) { rotationMinMaxWidth.SetChildrenMaxWidth((float)rotatedMaxWidth); } else { rotationMinMaxWidth.SetChildrenMaxWidth((float)rotatedMinWidth); } } else { rotationMinMaxWidth.SetChildrenMinWidth((float)rotatedMinWidth); } backup.RestoreProperty(Property.ROTATION_ANGLE); return(rotationMinMaxWidth); } } } backup.RestoreProperty(Property.ROTATION_ANGLE); return(minMaxWidth); }
private static float ToEffectiveWidth(IBlockElement b, float fullWidth) { if (b is Table) { return(fullWidth + ((Table)b).GetNumberOfColumns() * MinMaxWidthUtils.GetEps()); } else { return(fullWidth - MinMaxWidthUtils.GetBorderWidth(b) - MinMaxWidthUtils.GetMarginsWidth(b) - MinMaxWidthUtils .GetPaddingWidth(b) + MinMaxWidthUtils.GetEps()); } }
//Get actual width of element based on it's layout. May use occupied are of layout result of initial layout for time saving. private static float?GetLayoutRotatedWidth(AbstractRenderer renderer, float availableWidth, Rectangle previousBBox , double angle) { if (MinMaxWidthUtils.IsEqual(availableWidth, previousBBox.GetWidth())) { return((float)RotationMinMaxWidth.CalculateRotatedWidth(previousBBox, angle)); } LayoutResult result = renderer.Layout(new LayoutContext(new LayoutArea(1, new Rectangle(availableWidth + MinMaxWidthUtils .GetEps(), AbstractRenderer.INF)))); if (result.GetOccupiedArea() != null) { return((float)RotationMinMaxWidth.CalculateRotatedWidth(result.GetOccupiedArea().GetBBox(), angle)); } return(null); }
public virtual void NothingLayoutResult() { PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new MemoryStream())); Document document = new Document(pdfDocument); TextRenderer textRenderer = new TextRenderer(new iText.Layout.Element.Text(THAI_TEXT)); textRenderer.SetSpecialScriptsWordBreakPoints(new List <int>(JavaUtil.ArraysAsList(3, 8, 10, 12, 15, 20, 23 , 26, 28, 30, 36))); textRenderer.SetProperty(Property.FONT, PdfFontFactory.CreateFont(THAI_FONT, PdfEncodings.IDENTITY_H)); LineRenderer lineRenderer = new LineRenderer(); lineRenderer.SetParent(document.GetRenderer()); lineRenderer.AddChild(textRenderer); LayoutArea layoutArea = new LayoutArea(1, new Rectangle(MinMaxWidthUtils.GetInfWidth(), 10000)); Rectangle occupiedArea = lineRenderer.Layout(new LayoutContext(layoutArea)).GetOccupiedArea().GetBBox(); LayoutArea decreasedHeightLayoutArea = new LayoutArea(1, new Rectangle(occupiedArea.GetWidth(), occupiedArea .GetHeight() - 1)); LayoutResult nothingExpected = lineRenderer.Layout(new LayoutContext(decreasedHeightLayoutArea)); NUnit.Framework.Assert.AreEqual(LayoutResult.NOTHING, nothingExpected.GetStatus()); }
public override MinMaxWidth GetMinMaxWidth() { return(((MinMaxWidthLayoutResult)Layout(new LayoutContext(new LayoutArea(1, new Rectangle(MinMaxWidthUtils .GetInfWidth(), AbstractRenderer.INF))))).GetMinMaxWidth()); }
public override MinMaxWidth GetMinMaxWidth() { MinMaxWidth minMaxWidth = new MinMaxWidth(); float? rotation = this.GetPropertyAsFloat(Property.ROTATION_ANGLE); if (!SetMinMaxWidthBasedOnFixedWidth(minMaxWidth)) { float?minWidth = HasAbsoluteUnitValue(Property.MIN_WIDTH) ? RetrieveMinWidth(0) : null; float?maxWidth = HasAbsoluteUnitValue(Property.MAX_WIDTH) ? RetrieveMaxWidth(0) : null; if (minWidth == null || maxWidth == null) { bool restoreRotation = HasOwnProperty(Property.ROTATION_ANGLE); SetProperty(Property.ROTATION_ANGLE, null); MinMaxWidthLayoutResult result = (MinMaxWidthLayoutResult)Layout(new LayoutContext(new LayoutArea(1, new Rectangle (MinMaxWidthUtils.GetInfWidth(), AbstractRenderer.INF)))); if (restoreRotation) { SetProperty(Property.ROTATION_ANGLE, rotation); } else { DeleteOwnProperty(Property.ROTATION_ANGLE); } minMaxWidth = result.GetMinMaxWidth(); } if (minWidth != null) { minMaxWidth.SetChildrenMinWidth((float)minWidth); } if (maxWidth != null) { minMaxWidth.SetChildrenMaxWidth((float)maxWidth); } if (minMaxWidth.GetChildrenMinWidth() > minMaxWidth.GetChildrenMaxWidth()) { minMaxWidth.SetChildrenMaxWidth(minMaxWidth.GetChildrenMaxWidth()); } } else { minMaxWidth.SetAdditionalWidth(CalculateAdditionalWidth(this)); } return(rotation != null?RotationUtils.CountRotationMinMaxWidth(minMaxWidth, this) : minMaxWidth); }
/// <summary>This method tries to calculate width of not rotated renderer, so after rotation it fits availableWidth. /// </summary> /// <remarks> /// This method tries to calculate width of not rotated renderer, so after rotation it fits availableWidth. /// This method uses heuristics of /// <see cref="iText.Layout.Minmaxwidth.RotationMinMaxWidth.Calculate(double, double, iText.Layout.Minmaxwidth.MinMaxWidth, double) /// "/>. /// It doesn't take into account any of height properties of renderer or height of layoutArea. /// The minMaxWidth calculations and initial layout may take long time, but they won't be called if the renderer have width property. /// </remarks> /// <param name="availableWidth">the width of layoutArea</param> /// <param name="renderer">the actual renderer</param> /// <returns> /// the width that should be set as width of layout area to properly layout element, or fallback to /// <see cref="AbstractRenderer.RetrieveWidth(float)"/> /// in case it can not be calculated, or renderer isn't rotated. /// </returns> public static float?RetrieveRotatedLayoutWidth(float availableWidth, AbstractRenderer renderer) { RotationUtils.PropertiesBackup backup = new RotationUtils.PropertiesBackup(renderer); float?rotation = backup.StoreFloatProperty(Property.ROTATION_ANGLE); if (rotation != null && renderer.GetProperty <UnitValue>(Property.WIDTH) == null) { float angle = (float)rotation; backup.StoreProperty <UnitValue>(Property.HEIGHT); backup.StoreProperty <UnitValue>(Property.MIN_HEIGHT); backup.StoreProperty <UnitValue>(Property.MAX_HEIGHT); MinMaxWidth minMaxWidth = renderer.GetMinMaxWidth(); //Using this width for initial layout helps in case of small elements. They may have more free spaces but it's more likely they fit. float length = (minMaxWidth.GetMaxWidth() + minMaxWidth.GetMinWidth()) / 2 + MinMaxWidthUtils.GetEps(); LayoutResult layoutResult = renderer.Layout(new LayoutContext(new LayoutArea(1, new Rectangle(length, AbstractRenderer .INF)))); backup.RestoreProperty(Property.HEIGHT); backup.RestoreProperty(Property.MIN_HEIGHT); backup.RestoreProperty(Property.MAX_HEIGHT); Rectangle additions = new Rectangle(0, 0); renderer.ApplyPaddings(additions, true); renderer.ApplyBorderBox(additions, true); renderer.ApplyMargins(additions, true); if (layoutResult.GetOccupiedArea() != null) { double area = layoutResult.GetOccupiedArea().GetBBox().GetWidth() * layoutResult.GetOccupiedArea().GetBBox ().GetHeight(); RotationMinMaxWidth result = RotationMinMaxWidth.Calculate(angle, area, minMaxWidth, availableWidth); if (result != null) { backup.RestoreProperty(Property.ROTATION_ANGLE); if (result.GetMaxWidthHeight() > result.GetMinWidthHeight()) { return((float)(result.GetMinWidthOrigin() - additions.GetWidth() + MinMaxWidthUtils.GetEps())); } else { return((float)(result.GetMaxWidthOrigin() - additions.GetWidth() + MinMaxWidthUtils.GetEps())); } } } } backup.RestoreProperty(Property.ROTATION_ANGLE); return(renderer.RetrieveWidth(availableWidth)); }
/// <summary> /// See the algorithm detailed at https://www.w3.org/TR/css3-page/#margin-dimension /// Divide the available dimension along the A,B and C according to their properties. /// </summary> /// <param name="dimA">object containing the dimension-related properties of A</param> /// <param name="dimB">object containing the dimension-related properties of B</param> /// <param name="dimC">object containing the dimension-related properties of C</param> /// <param name="availableDimension">maximum available dimension that can be taken up</param> /// <returns>float[3] containing the distributed dimensions of A at [0], B at [1] and C at [2]</returns> private float[] CalculatePageMarginBoxDimensions(DimensionContainer dimA, DimensionContainer dimB, DimensionContainer dimC, float availableDimension) { float maxContentDimensionA = 0; float minContentDimensionA = 0; float maxContentDimensionB = 0; float minContentDimensionB = 0; float maxContentDimensionC = 0; float minContentDimensionC = 0; float[] dimensions = new float[3]; if (IsContainerEmpty(dimA) && IsContainerEmpty(dimB) && IsContainerEmpty(dimC)) { return(dimensions); } //Calculate widths //Check if B is present if (IsContainerEmpty(dimB)) { //Single box present if (IsContainerEmpty(dimA)) { if (dimC.IsAutoDimension()) { //Allocate everything to C dimensions[2] = availableDimension; } else { dimensions[2] = dimC.dimension; } } else { if (IsContainerEmpty(dimC)) { if (dimA.IsAutoDimension()) { //Allocate everything to A dimensions[0] = availableDimension; } else { dimensions[0] = dimA.dimension; } } else { if (dimA.IsAutoDimension() && dimC.IsAutoDimension()) { //Gather input maxContentDimensionA = dimA.maxContentDimension; minContentDimensionA = dimA.minContentDimension; maxContentDimensionC = dimC.maxContentDimension; minContentDimensionC = dimC.minContentDimension; float[] distributedWidths = DistributeDimensionBetweenTwoBoxes(maxContentDimensionA, minContentDimensionA, maxContentDimensionC, minContentDimensionC, availableDimension); dimensions = new float[] { distributedWidths[0], 0f, distributedWidths[1] }; } else { if (!dimA.IsAutoDimension()) { dimensions[0] = dimA.dimension; } else { dimensions[0] = availableDimension - dimC.dimension; } if (!dimC.IsAutoDimension()) { dimensions[2] = dimC.dimension; } else { dimensions[2] = availableDimension - dimA.dimension; } } } } } else { //Check for edge cases if (!IsContainerEmpty(dimA)) { if (dimA.IsAutoDimension()) { maxContentDimensionA = dimA.maxContentDimension; minContentDimensionA = dimA.minContentDimension; } else { maxContentDimensionA = dimA.dimension; minContentDimensionA = dimA.dimension; } } if (!IsContainerEmpty(dimC)) { if (dimC.IsAutoDimension()) { maxContentDimensionC = dimC.maxContentDimension; minContentDimensionC = dimC.minContentDimension; } else { maxContentDimensionC = dimC.dimension; minContentDimensionC = dimC.dimension; } } if (dimB.IsAutoDimension()) { //Construct box AC float maxContentWidthAC; float minContentWidthAC; maxContentWidthAC = 2 * Math.Max(maxContentDimensionA, maxContentDimensionC); minContentWidthAC = 2 * Math.Max(minContentDimensionA, minContentDimensionC); //Determine width box B maxContentDimensionB = dimB.maxContentDimension; minContentDimensionB = dimB.minContentDimension; float[] distributedDimensions = DistributeDimensionBetweenTwoBoxes(maxContentDimensionB, minContentDimensionB , maxContentWidthAC, minContentWidthAC, availableDimension); //Determine width boxes A & C float newAvailableDimension = (availableDimension - distributedDimensions[0]) / 2; dimensions = new float[] { newAvailableDimension, distributedDimensions[0], newAvailableDimension }; } else { dimensions[1] = dimB.dimension; float newAvailableDimension = (availableDimension - dimensions[1]) / 2; if (newAvailableDimension > float.MaxValue - MinMaxWidthUtils.GetEps()) { newAvailableDimension = float.MaxValue - MinMaxWidthUtils.GetEps(); } dimensions[0] = Math.Min(maxContentDimensionA, newAvailableDimension) + MinMaxWidthUtils.GetEps(); dimensions[2] = Math.Min(maxContentDimensionC, newAvailableDimension) + MinMaxWidthUtils.GetEps(); } SetManualDimension(dimA, dimensions, 0); SetManualDimension(dimC, dimensions, 2); } if (RecalculateIfNecessary(dimA, dimensions, 0) || RecalculateIfNecessary(dimB, dimensions, 1) || RecalculateIfNecessary (dimC, dimensions, 2)) { return(CalculatePageMarginBoxDimensions(dimA, dimB, dimC, availableDimension)); } RemoveNegativeValues(dimensions); return(dimensions); }