Beispiel #1
0
        public virtual void AlterOrphansWidowsTest()
        {
            ConverterProperties      converterProperties = new ConverterProperties();
            DefaultCssApplierFactory cssApplierFactory   = new OrphansWidowsUnitTest.CustomBlockCssApplierFactory();

            converterProperties.SetCssApplierFactory(cssApplierFactory);
            IList <IElement> elements = HtmlConverter.ConvertToElements(new FileStream(sourceFolder + "orphansWidows.html"
                                                                                       , FileMode.Open, FileAccess.Read), converterProperties);
            Div div = (Div)elements[0];

            NUnit.Framework.Assert.IsNotNull(div);
            Paragraph paragraph = (Paragraph)div.GetChildren()[0];

            NUnit.Framework.Assert.IsNotNull(paragraph);
            ParagraphWidowsControl paragraphWidowsControl = paragraph.GetProperty <ParagraphWidowsControl>(Property.WIDOWS_CONTROL
                                                                                                           );

            NUnit.Framework.Assert.IsNotNull(paragraphWidowsControl);
            NUnit.Framework.Assert.AreEqual(3, paragraphWidowsControl.GetMaxLinesToMove());
            NUnit.Framework.Assert.IsTrue(paragraphWidowsControl.IsOverflowOnWidowsViolation());
        }
        internal static LayoutResult OrphansWidowsAwareLayout(ParagraphRenderer renderer, LayoutContext context, ParagraphOrphansControl
                                                              orphansControl, ParagraphWidowsControl widowsControl)
        {
            OrphansWidowsLayoutHelper.OrphansWidowsLayoutAttempt layoutAttempt = AttemptLayout(renderer, context, context
                                                                                               .GetArea().Clone());
            if (context.IsClippedHeight() || renderer.IsPositioned() || layoutAttempt.attemptResult.GetStatus() != LayoutResult
                .PARTIAL || layoutAttempt.attemptResult.GetSplitRenderer() == null)
            {
                return(HandleAttemptAsSuccessful(layoutAttempt, context));
            }
            ParagraphRenderer splitRenderer = (ParagraphRenderer)layoutAttempt.attemptResult.GetSplitRenderer();
            bool orphansViolation           = orphansControl != null && splitRenderer != null && splitRenderer.GetLines().Count
                                              < orphansControl.GetMinOrphans() && !renderer.IsFirstOnRootArea();
            bool forcedPlacement = true.Equals(renderer.GetPropertyAsBoolean(Property.FORCED_PLACEMENT));

            if (orphansViolation && forcedPlacement)
            {
                orphansControl.HandleViolatedOrphans(splitRenderer, "Ignored orphans constraint due to forced placement.");
            }
            if (orphansViolation && !forcedPlacement)
            {
                layoutAttempt = null;
            }
            else
            {
                if (widowsControl != null && splitRenderer != null && layoutAttempt.attemptResult.GetOverflowRenderer() !=
                    null)
                {
                    ParagraphRenderer overflowRenderer = (ParagraphRenderer)layoutAttempt.attemptResult.GetOverflowRenderer();
                    // Excessively big value to check if widows constraint is violated;
                    // Make this value less in order to improve performance if you are sure
                    // that min number of widows will fit in this height. E.g. A4 page height is 842.
                    int        simulationHeight = 3500;
                    LayoutArea simulationArea   = new LayoutArea(context.GetArea().GetPageNumber(), context.GetArea().GetBBox().
                                                                 Clone().SetHeight(simulationHeight));
                    // collapsingMarginsInfo might affect available space, which is redundant in case we pass arbitrary space.
                    // floatedRendererAreas list on new area is considered empty. We don't know if there will be any, however their presence in any case will result in more widows, not less.
                    // clippedHeight is undefined for the next area, because it is defined by overflow part of the paragraph parent.
                    //               Even if it will be set to true in actual overflow-part layouting, stealing lines approach will result in
                    //               giving bigger part of MAX-HEIGHT to the overflow part and resulting in bigger number of widows, which is better.
                    //               However for possible other approaches which change content "length" (like word/char spacing adjusts),
                    //               if in actual overflow-part layouting clippedHeight will be true, those widows fixing attempts will result in worse results.
                    LayoutContext simulationContext = new LayoutContext(simulationArea);
                    LayoutResult  simulationResult  = overflowRenderer.DirectLayout(simulationContext);
                    if (simulationResult.GetStatus() == LayoutResult.FULL)
                    {
                        // simulationHeight is excessively big in order to allow to layout all of the content remaining in overflowRenderer:
                        // this way after all of the remaining content is layouted we can check if it has led to widows violation.
                        // To make this analysis possible, we expect to get result FULL.
                        // if result is PARTIAL: means that simulationHeight value isn't big enough to layout all of the content remaining in overflowRenderer.
                        // In this case we assume that widows aren't violated since the amount of the lines to fit the simulatedHeight is expected to be very large.
                        // if result is NOTHING: unexpected result, limitation of simulation approach. Retry again with forced placement set.
                        int extraWidows = widowsControl.GetMinWidows() - overflowRenderer.GetLines().Count;
                        if (extraWidows > 0)
                        {
                            int extraLinesToMove = orphansControl != null?Math.Max(orphansControl.GetMinOrphans(), 1) : 1;

                            if (extraWidows <= widowsControl.GetMaxLinesToMove() && splitRenderer.GetLines().Count - extraWidows >= extraLinesToMove
                                )
                            {
                                LineRenderer lastLine        = splitRenderer.GetLines()[splitRenderer.GetLines().Count - 1];
                                LineRenderer lastLineToLeave = splitRenderer.GetLines()[splitRenderer.GetLines().Count - extraWidows - 1];
                                float        d = lastLineToLeave.GetOccupiedArea().GetBBox().GetY() - lastLine.GetOccupiedArea().GetBBox().GetY()
                                                 - AbstractRenderer.EPS;
                                Rectangle smallerBBox = new Rectangle(context.GetArea().GetBBox());
                                smallerBBox.DecreaseHeight(d);
                                smallerBBox.MoveUp(d);
                                LayoutArea smallerAvailableArea = new LayoutArea(context.GetArea().GetPageNumber(), smallerBBox);
                                layoutAttempt = AttemptLayout(renderer, context, smallerAvailableArea);
                            }
                            else
                            {
                                if (forcedPlacement || renderer.IsFirstOnRootArea() || !widowsControl.IsOverflowOnWidowsViolation())
                                {
                                    if (forcedPlacement)
                                    {
                                        widowsControl.HandleViolatedWidows(overflowRenderer, "forced placement");
                                    }
                                    else
                                    {
                                        widowsControl.HandleViolatedWidows(overflowRenderer, "inability to fix it");
                                    }
                                }
                                else
                                {
                                    layoutAttempt = null;
                                }
                            }
                        }
                    }
                }
            }
            if (layoutAttempt != null)
            {
                return(HandleAttemptAsSuccessful(layoutAttempt, context));
            }
            else
            {
                return(new LayoutResult(LayoutResult.NOTHING, null, null, renderer));
            }
        }