예제 #1
0
        /// <summary>
        /// Shorten the current line. Currently this is only called when the last thing on the line
        /// is a string box. If possible, replace its segment with a shorter one. If this is not possible,
        /// and it is not the first thing on the line, remove it altogether. If it IS the first thing on
        /// the line, do nothing. We'll live with the bad break, because there is nothing better we know
        /// how to do.
        /// Returns true if successful, which means FinalizeLine should be called again. False if
        /// unsuccessful, to prevent infinite loop.
        /// </summary>
        private bool Backtrack()
        {
            var lastBox = m_lines.Last().LastBox as StringBox;

            while (lastBox != null)
            {
                // We want to call FindLineBreak again with the same arguments we used to create the segment
                // of lastBox, except that ichLimBacktrack should prevent including the last character.
                // (We expect that is is NOT a white-space-only segment, since we were not able to break after it.)
                int ichMin = lastBox.IchMin;
                int ichLim = ichMin + lastBox.Segment.get_Lim(ichMin);
                //int dxWidthLast = lastBox.Segment.get_Width(ichMin, m_layoutInfo.VwGraphics);
                int ichLimBacktrack = ichLim - 1;
                // skip back one if we're splitting a surrogate.
                if (ichLimBacktrack > 0)
                {
                    string charsAtLim = Fetch(ichLimBacktrack - 1, ichLimBacktrack + 1);
                    if (Surrogates.IsTrailSurrogate(charsAtLim[1]) && Surrogates.IsLeadSurrogate(charsAtLim[0]))
                    {
                        ichLimBacktrack--;
                    }
                }
                int runIndex = m_renderRunIndex;                 // what would have beem m_renderRunIndex when making lastBox's segment.
                while (runIndex > 0 && ichMin < m_renderRuns[runIndex].RenderStart)
                {
                    runIndex--;
                }
                var              renderer  = m_layoutInfo.GetRenderer(m_renderRuns[runIndex].Ws);
                int              ichRunLim = GetLimitOfRunWithSameRenderer(renderer, runIndex);
                ILgSegment       seg;
                int              dichLim, dxWidth;
                LgEndSegmentType est;
                bool             mustGetSomeSeg = m_currentLine.FirstBox == lastBox;
                var              twsh           = LgTrailingWsHandling.ktwshAll;
                bool             runRtl         = m_layoutInfo.RendererFactory.RightToLeft(m_renderRuns[runIndex].Ws);
                bool             paraRtl        = m_para.Style.RightToLeft;
                if (runRtl != paraRtl)
                {
                    twsh = LgTrailingWsHandling.ktwshNoWs;
                }
                var spaceLeftOnCurrentLine = m_spaceLeftOnCurrentLine + lastBox.Width;

                renderer.FindBreakPoint(m_layoutInfo.VwGraphics, m_para.Source, null, ichMin,
                                        ichRunLim, ichLimBacktrack, false, mustGetSomeSeg, spaceLeftOnCurrentLine,
                                        LgLineBreak.klbWordBreak,
                                        mustGetSomeSeg ? LgLineBreak.klbClipBreak : LgLineBreak.klbWordBreak, twsh,
                                        false, out seg, out dichLim, out dxWidth, out est, null);
                if (seg == null)
                {
                    // can't make any shorter segment here.
                    // Can we backtrack further by getting rid of this box altogether?
                    Box boxBefore = m_lines.Last().BoxBefore(lastBox);
                    if (boxBefore is StringBox)
                    {
                        lastBox = (StringBox)boxBefore;
                        continue;
                    }
                    // Currently backtracking should not need to remove a non-string box, because we always allow
                    // breaking after them. So if boxBefore is not a string box, we can break after it.
                    m_currentLine.RemoveFrom(lastBox);
                    m_ichRendered            = ichMin;
                    m_spaceLeftOnCurrentLine = spaceLeftOnCurrentLine;
                    m_renderRunIndex         = AdvanceRenderRunIndexToIch(m_ichRendered, m_renderRunIndex);
                    return(true);
                }

                m_currentLine.RemoveFrom(lastBox);
                AddBoxToLine(seg, ichMin, dichLim, est, spaceLeftOnCurrentLine);
                ILgSegment whiteSpaceSeg;
                if (twsh == LgTrailingWsHandling.ktwshNoWs)
                {
                    // Add a white space segment if possible.
                    renderer.FindBreakPoint(m_layoutInfo.VwGraphics, m_para.Source, null, m_ichRendered,
                                            ichRunLim, ichRunLim, false, true, m_spaceLeftOnCurrentLine, LgLineBreak.klbWordBreak,
                                            LgLineBreak.klbWordBreak, LgTrailingWsHandling.ktwshOnlyWs,
                                            false, out whiteSpaceSeg, out dichLim, out dxWidth, out est, null);
                    if (seg != null)
                    {
                        AddBoxToLine(whiteSpaceSeg, m_ichRendered, dichLim, est, m_spaceLeftOnCurrentLine);
                    }
                }
                m_renderRunIndex = AdvanceRenderRunIndexToIch(m_ichRendered, m_renderRunIndex);
                return(true);
            }
            return(false);            // no better break available, use the line as it is.
        }