/// <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); }
/// <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)); }