Ejemplo n.º 1
0
        /// <summary>Calculates and sets tab size with the account of the element that is next in the line after the tab.
        ///     </summary>
        /// <remarks>
        /// Calculates and sets tab size with the account of the element that is next in the line after the tab.
        /// Returns resulting width of the tab.
        /// </remarks>
        private float CalculateTab(Rectangle layoutBox, float curWidth, TabStop tabStop,
                                   IRenderer nextElementRenderer, LayoutResult nextElementResult, IRenderer tabRenderer
                                   )
        {
            float childWidth = 0;

            if (nextElementRenderer != null)
            {
                childWidth = nextElementRenderer.GetOccupiedArea().GetBBox().GetWidth();
            }
            float tabWidth = 0;

            switch (tabStop.GetTabAlignment())
            {
            case TabAlignment.RIGHT:
            {
                tabWidth = tabStop.GetTabPosition() - curWidth - childWidth;
                break;
            }

            case TabAlignment.CENTER:
            {
                tabWidth = tabStop.GetTabPosition() - curWidth - childWidth / 2;
                break;
            }

            case TabAlignment.ANCHOR:
            {
                float anchorPosition = -1;
                if (nextElementRenderer is TextRenderer)
                {
                    anchorPosition = ((TextRenderer)nextElementRenderer).GetTabAnchorCharacterPosition
                                         ();
                }
                if (anchorPosition == -1)
                {
                    anchorPosition = childWidth;
                }
                tabWidth = tabStop.GetTabPosition() - curWidth - anchorPosition;
                break;
            }
            }
            if (tabWidth < 0)
            {
                tabWidth = 0;
            }
            if (curWidth + tabWidth + childWidth > layoutBox.GetWidth())
            {
                tabWidth -= (curWidth + childWidth + tabWidth) - layoutBox.GetWidth();
            }
            tabRenderer.SetProperty(Property.WIDTH, UnitValue.CreatePointValue(tabWidth));
            tabRenderer.SetProperty(Property.HEIGHT, maxAscent - maxDescent);
            return(tabWidth);
        }
Ejemplo n.º 2
0
        /// <summary>Calculates and sets encountered tab size.</summary>
        /// <remarks>
        /// Calculates and sets encountered tab size.
        /// Returns null, if processing is finished and layout can be performed for the tab renderer;
        /// otherwise, in case when the tab should be processed after the next element in the line, this method returns corresponding tab stop.
        /// </remarks>
        private TabStop CalculateTab(IRenderer childRenderer, float curWidth, float lineWidth
                                     )
        {
            TabStop nextTabStop = GetNextTabStop(curWidth);

            if (nextTabStop == null)
            {
                ProcessDefaultTab(childRenderer, curWidth, lineWidth);
                return(null);
            }
            childRenderer.SetProperty(Property.TAB_LEADER, nextTabStop.GetTabLeader());
            childRenderer.SetProperty(Property.WIDTH, UnitValue.CreatePointValue(nextTabStop.GetTabPosition() - curWidth));
            childRenderer.SetProperty(Property.HEIGHT, maxAscent - maxDescent);
            if (nextTabStop.GetTabAlignment() == TabAlignment.LEFT)
            {
                return(null);
            }
            return(nextTabStop);
        }
Ejemplo n.º 3
0
        public override LayoutResult Layout(LayoutContext layoutContext)
        {
            Rectangle layoutBox = layoutContext.GetArea().GetBBox().Clone();

            occupiedArea = new LayoutArea(layoutContext.GetArea().GetPageNumber(), layoutBox.
                                          Clone().MoveDown(-layoutBox.GetHeight()).SetHeight(0));
            float curWidth = 0;

            maxAscent  = 0;
            maxDescent = 0;
            int           childPos      = 0;
            BaseDirection?baseDirection = this.GetProperty <BaseDirection?>(Property.BASE_DIRECTION, BaseDirection.NO_BIDI);

            foreach (IRenderer renderer in childRenderers)
            {
                if (renderer is TextRenderer)
                {
                    renderer.SetParent(this);
                    ((TextRenderer)renderer).ApplyOtf();
                    renderer.SetParent(null);
                    if (baseDirection == null || baseDirection == BaseDirection.NO_BIDI)
                    {
                        baseDirection = renderer.GetOwnProperty <BaseDirection?>(Property.BASE_DIRECTION);
                    }
                }
            }
            IList <int> unicodeIdsReorderingList = null;

            if (levels == null && baseDirection != null && baseDirection != BaseDirection.NO_BIDI)
            {
                unicodeIdsReorderingList = new List <int>();
                bool newLineFound = false;

                foreach (IRenderer child in childRenderers)
                {
                    if (newLineFound)
                    {
                        break;
                    }
                    if (child is TextRenderer)
                    {
                        GlyphLine text = ((TextRenderer)child).GetText();
                        for (int i = text.start; i < text.end; i++)
                        {
                            if (TextRenderer.IsNewLine(text, i))
                            {
                                newLineFound = true;
                                break;
                            }
                            // we assume all the chars will have the same bidi group
                            // we also assume pairing symbols won't get merged with other ones
                            unicodeIdsReorderingList.Add(text.Get(i).GetUnicode());
                        }
                    }
                }
                levels = unicodeIdsReorderingList.Count > 0 ? TypographyUtils.GetBidiLevels((BaseDirection)baseDirection, ArrayUtil.ToArray(unicodeIdsReorderingList)) : null;
            }
            bool             anythingPlaced = false;
            TabStop          nextTabStop    = null;
            LineLayoutResult result         = null;

            while (childPos < childRenderers.Count)
            {
                IRenderer    childRenderer = childRenderers[childPos];
                LayoutResult childResult;
                Rectangle    bbox = new Rectangle(layoutBox.GetX() + curWidth, layoutBox.GetY(), layoutBox
                                                  .GetWidth() - curWidth, layoutBox.GetHeight());
                if (childRenderer is TextRenderer)
                {
                    // Delete these properties in case of relayout. We might have applied them during justify().
                    childRenderer.DeleteOwnProperty(Property.CHARACTER_SPACING);
                    childRenderer.DeleteOwnProperty(Property.WORD_SPACING);
                }
                else
                {
                    if (childRenderer is TabRenderer)
                    {
                        if (nextTabStop != null)
                        {
                            IRenderer tabRenderer = childRenderers[childPos - 1];
                            tabRenderer.Layout(new LayoutContext(new LayoutArea(layoutContext.GetArea().GetPageNumber
                                                                                    (), bbox)));
                            curWidth += tabRenderer.GetOccupiedArea().GetBBox().GetWidth();
                        }
                        nextTabStop = CalculateTab(childRenderer, curWidth, layoutBox.GetWidth());
                        if (childPos == childRenderers.Count - 1)
                        {
                            nextTabStop = null;
                        }
                        if (nextTabStop != null)
                        {
                            ++childPos;
                            continue;
                        }
                    }
                }
                if (!anythingPlaced && childRenderer is TextRenderer)
                {
                    ((TextRenderer)childRenderer).TrimFirst();
                }
                if (nextTabStop != null && nextTabStop.GetTabAlignment() == TabAlignment.ANCHOR &&
                    childRenderer is TextRenderer)
                {
                    childRenderer.SetProperty(Property.TAB_ANCHOR, nextTabStop
                                              .GetTabAnchor());
                }
                childResult = childRenderer.SetParent(this).Layout(new LayoutContext(new LayoutArea
                                                                                         (layoutContext.GetArea().GetPageNumber(), bbox)));
                float childAscent  = 0;
                float childDescent = 0;
                if (childRenderer is TextRenderer)
                {
                    childAscent  = ((TextRenderer)childRenderer).GetAscent();
                    childDescent = ((TextRenderer)childRenderer).GetDescent();
                }
                else
                {
                    if (childRenderer is ImageRenderer)
                    {
                        childAscent = childRenderer.GetOccupiedArea().GetBBox().GetHeight();
                    }
                }
                maxAscent  = Math.Max(maxAscent, childAscent);
                maxDescent = Math.Min(maxDescent, childDescent);
                float maxHeight = maxAscent - maxDescent;
                if (nextTabStop != null)
                {
                    IRenderer tabRenderer = childRenderers[childPos - 1];
                    float     tabWidth    = CalculateTab(layoutBox, curWidth, nextTabStop, childRenderer, childResult
                                                         , tabRenderer);
                    tabRenderer.Layout(new LayoutContext(new LayoutArea(layoutContext.GetArea().GetPageNumber
                                                                            (), bbox)));
                    childResult.GetOccupiedArea().GetBBox().MoveRight(tabWidth);
                    if (childResult.GetSplitRenderer() != null)
                    {
                        childResult.GetSplitRenderer().GetOccupiedArea().GetBBox().MoveRight(tabWidth);
                    }
                    float tabAndNextElemWidth = tabWidth + childResult.GetOccupiedArea().GetBBox().GetWidth();
                    if (nextTabStop.GetTabAlignment() == TabAlignment.RIGHT && curWidth + tabAndNextElemWidth < nextTabStop.GetTabPosition())
                    {
                        curWidth = nextTabStop.GetTabPosition();
                    }
                    else
                    {
                        curWidth += tabAndNextElemWidth;
                    }
                    nextTabStop = null;
                }
                else
                {
                    curWidth += childResult.GetOccupiedArea().GetBBox().GetWidth();
                }
                occupiedArea.SetBBox(new Rectangle(layoutBox.GetX(), layoutBox.GetY() + layoutBox
                                                   .GetHeight() - maxHeight, curWidth, maxHeight));
                if (childResult.GetStatus() != LayoutResult.FULL)
                {
                    LineRenderer[] split = Split();
                    split[0].childRenderers = new List <IRenderer>(childRenderers.SubList(0, childPos)
                                                                   );
                    bool wordWasSplitAndItWillFitOntoNextLine = false;
                    if (childResult is TextLayoutResult && ((TextLayoutResult)childResult).IsWordHasBeenSplit
                            ())
                    {
                        LayoutResult newLayoutResult = childRenderer.Layout(layoutContext);
                        if (newLayoutResult is TextLayoutResult && !((TextLayoutResult)newLayoutResult).IsWordHasBeenSplit
                                ())
                        {
                            wordWasSplitAndItWillFitOntoNextLine = true;
                        }
                    }
                    if (wordWasSplitAndItWillFitOntoNextLine)
                    {
                        split[1].childRenderers.Add(childRenderer);
                        split[1].childRenderers.AddAll(childRenderers.SubList(childPos + 1, childRenderers
                                                                              .Count));
                    }
                    else
                    {
                        if (childResult.GetStatus() == LayoutResult.PARTIAL)
                        {
                            split[0].AddChild(childResult.GetSplitRenderer());
                            anythingPlaced = true;
                        }
                        if (childResult.GetStatus() == LayoutResult.PARTIAL && childResult.GetOverflowRenderer
                                () is ImageRenderer)
                        {
                            ((ImageRenderer)childResult.GetOverflowRenderer()).AutoScale(layoutContext.GetArea
                                                                                             ());
                        }
                        if (null != childResult.GetOverflowRenderer())
                        {
                            split[1].childRenderers.Add(childResult.GetOverflowRenderer());
                        }
                        split[1].childRenderers.AddAll(childRenderers.SubList(childPos + 1, childRenderers
                                                                              .Count));
                        // no sense to process empty renderer
                        if (split[1].childRenderers.Count == 0)
                        {
                            split[1] = null;
                        }
                    }
                    result = new LineLayoutResult(anythingPlaced ? LayoutResult.PARTIAL : LayoutResult.NOTHING, occupiedArea, split[0], split[1],
                                                  childResult.GetStatus() == LayoutResult.NOTHING ? childResult.GetCauseOfNothing() : this);

                    if (childResult.GetStatus() == LayoutResult.PARTIAL && childResult is TextLayoutResult && ((TextLayoutResult)childResult).IsSplitForcedByNewline())
                    {
                        result.SetSplitForcedByNewline(true);
                    }
                    break;
                }
                else
                {
                    anythingPlaced = true;
                    childPos++;
                }
            }
            if (result == null)
            {
                if (anythingPlaced)
                {
                    result = new LineLayoutResult(LayoutResult.FULL, occupiedArea, null, null);
                }
                else
                {
                    result = new LineLayoutResult(LayoutResult.NOTHING, occupiedArea, null, this, this);
                }
            }
            // Consider for now that all the children have the same font, and that after reordering text pieces
            // can be reordered, but cannot be split.
            if (baseDirection != null && baseDirection != BaseDirection.NO_BIDI)
            {
                IList <IRenderer> children = null;
                if (result.GetStatus() == LayoutResult.PARTIAL)
                {
                    children = result.GetSplitRenderer().GetChildRenderers();
                }
                else
                {
                    if (result.GetStatus() == LayoutResult.FULL)
                    {
                        children = GetChildRenderers();
                    }
                }
                if (children != null)
                {
                    IList <LineRenderer.RendererGlyph> lineGlyphs = new List <LineRenderer.RendererGlyph
                                                                              >();
                    foreach (IRenderer child in children)
                    {
                        if (child is TextRenderer)
                        {
                            GlyphLine childLine = ((TextRenderer)child).line;
                            for (int i = childLine.start; i < childLine.end; i++)
                            {
                                lineGlyphs.Add(new LineRenderer.RendererGlyph(childLine.Get(i), (TextRenderer)child
                                                                              ));
                            }
                        }
                    }
                    byte[] lineLevels = new byte[lineGlyphs.Count];
                    if (levels != null)
                    {
                        System.Array.Copy(levels, 0, lineLevels, 0, lineGlyphs.Count);
                    }
                    int[] reorder = TypographyUtils.ReorderLine(lineGlyphs, lineLevels, levels);
                    if (reorder != null)
                    {
                        children.Clear();
                        int           pos            = 0;
                        IList <int[]> reversedRanges = new List <int[]>();
                        int           initialPos     = 0;
                        bool          reversed       = false;
                        int           offset         = 0;
                        while (pos < lineGlyphs.Count)
                        {
                            IRenderer    renderer_1  = lineGlyphs[pos].renderer;
                            TextRenderer newRenderer = new TextRenderer((TextRenderer)renderer_1);
                            newRenderer.DeleteOwnProperty(Property.REVERSED);
                            children.Add(newRenderer);
                            ((TextRenderer)children[children.Count - 1]).line = new GlyphLine(((TextRenderer)
                                                                                               children[children.Count - 1]).line);
                            GlyphLine     gl = ((TextRenderer)children[children.Count - 1]).line;
                            IList <Glyph> replacementGlyphs = new List <Glyph>();
                            while (pos < lineGlyphs.Count && lineGlyphs[pos].renderer == renderer_1)
                            {
                                if (pos < lineGlyphs.Count - 1)
                                {
                                    if (reorder[pos] == reorder[pos + 1] + 1)
                                    {
                                        reversed = true;
                                    }
                                    else
                                    {
                                        if (reversed)
                                        {
                                            IList <int[]> reversedRange = new List <int[]>();
                                            reversedRange.Add(new int[] { initialPos - offset, pos - offset });
                                            newRenderer.SetProperty(Property.REVERSED, reversedRange);
                                            reversedRanges.Add(new int[] { initialPos - offset, pos - offset });
                                            reversed = false;
                                        }
                                        initialPos = pos + 1;
                                    }
                                }
                                replacementGlyphs.Add(lineGlyphs[pos].glyph);
                                pos++;
                            }
                            if (reversed)
                            {
                                IList <int[]> reversedRange = new List <int[]>();
                                reversedRange.Add(new int[] { initialPos - offset, pos - 1 - offset });
                                newRenderer.SetProperty(Property.REVERSED, reversedRange
                                                        );
                                reversedRanges.Add(new int[] { initialPos - offset, pos - 1 - offset });
                                reversed   = false;
                                initialPos = pos;
                            }
                            offset = initialPos;
                            gl.SetGlyphs(replacementGlyphs);
                        }
                        if (reversed)
                        {
                            if (children.Count == 1)
                            {
                                offset = 0;
                            }
                            IList <int[]> reversedRange = new List <int[]>();
                            reversedRange.Add(new int[] { initialPos - offset, pos - offset - 1 });
                            lineGlyphs[pos - 1].renderer.SetProperty(Property.REVERSED
                                                                     , reversedRange);
                            reversedRanges.Add(new int[] { initialPos - offset, pos - 1 - offset });
                        }
                        if (!reversedRanges.IsEmpty())
                        {
                            if (children.Count == 1)
                            {
                                lineGlyphs[0].renderer.SetProperty(Property.REVERSED, reversedRanges);
                            }
                        }
                        float currentXPos = layoutContext.GetArea().GetBBox().GetLeft();
                        foreach (IRenderer child_1 in children)
                        {
                            float currentWidth = ((TextRenderer)child_1).CalculateLineWidth();
                            ((TextRenderer)child_1).occupiedArea.GetBBox().SetX(currentXPos).SetWidth(currentWidth
                                                                                                      );
                            currentXPos += currentWidth;
                        }
                    }
                    if (result.GetStatus() == LayoutResult.PARTIAL)
                    {
                        LineRenderer overflow = (LineRenderer)result.GetOverflowRenderer();
                        if (levels != null)
                        {
                            overflow.levels = new byte[levels.Length - lineLevels.Length];
                            System.Array.Copy(levels, lineLevels.Length, overflow.levels, 0, overflow.levels.
                                              Length);
                            if (overflow.levels.Length == 0)
                            {
                                overflow.levels = null;
                            }
                        }
                    }
                    else if (result.GetStatus() == LayoutResult.NOTHING)
                    {
                        if (levels != null)
                        {
                            ((LineRenderer)result.GetOverflowRenderer()).levels = levels;
                        }
                    }
                }
            }
            if (anythingPlaced)
            {
                LineRenderer processed = result.GetStatus() == LayoutResult.FULL ? this : (LineRenderer
                                                                                           )result.GetSplitRenderer();
                processed.AdjustChildrenYLine().TrimLast();
            }
            return(result);
        }