List CreateGlyphRuns()

in ExampleGallery/CustomTextLayouts.xaml.cs [710:803]


        List<LayoutBox> CreateGlyphRuns(List<Rect> rectangles, List<FormattingSpan> formattingSpans, CanvasAnalyzedBreakpoint[] analyzedBreakpoints)
        {
            List<LayoutBox> layoutBoxes = new List<LayoutBox>();

            if (rectangles.Count == 0) return layoutBoxes;

            int rectangleIndex = -1;
            float glyphRunAdvance = 0;
            int wordsPerLine = 0;            

            for (int formattingSpanIndex = 0; formattingSpanIndex < formattingSpans.Count; formattingSpanIndex++)
            {
                var formattingSpan = formattingSpans[formattingSpanIndex];

                GlyphRun currentGlyphRun;
                if (layoutBoxes.Count == 0)
                    currentGlyphRun = BeginNewLayoutBox(ref rectangleIndex, rectangles, ref glyphRunAdvance, ref wordsPerLine, formattingSpan, layoutBoxes);
                else
                    currentGlyphRun = BeginGlyphRun(rectangles[rectangleIndex], glyphRunAdvance, layoutBoxes[layoutBoxes.Count - 1], formattingSpan, rectangleIndex);

                if (currentGlyphRun == null)
                    return layoutBoxes;

                var glyphs = formattingSpan.Glyphs;

                for (int i = 0; i < glyphs.Length; ++i)
                {
                    //
                    // Will the next word fit in the box?
                    //
                    float wordAdvance = 0.0f;
                    int wordBoundary;
                    for (wordBoundary = i; wordBoundary < glyphs.Length; wordBoundary++)
                    {
                        int correspondingTextPosition = formattingSpan.Range.CharacterIndex + GetCharacterIndex(wordBoundary, formattingSpan.ClusterMap);

                        var afterThisCharacter = analyzedBreakpoints[correspondingTextPosition].BreakAfter;
                        var beforeNextCharacter = (correspondingTextPosition < analyzedBreakpoints.Length - 1) ? analyzedBreakpoints[correspondingTextPosition + 1].BreakBefore : CanvasLineBreakCondition.Neutral;
                        
                        // 
                        // The text for this demo doesn't have any hard line breaks.
                        //
                        System.Diagnostics.Debug.Assert(afterThisCharacter != CanvasLineBreakCondition.MustBreak);

                        if (afterThisCharacter == CanvasLineBreakCondition.CanBreak && beforeNextCharacter != CanvasLineBreakCondition.CannotBreak)
                            break;

                        wordAdvance += glyphs[wordBoundary].Advance;
                    }

                    if (glyphRunAdvance + wordAdvance < rectangles[rectangleIndex].Width) // It fits
                    {
                        for (int j = i; j <= wordBoundary; j++)
                        {
                            if (j < glyphs.Length)
                            {
                                currentGlyphRun.AddGlyph(j);

                                glyphRunAdvance += glyphs[j].Advance;
                            }
                        }
                        i = wordBoundary;
                        wordsPerLine++;
                    }
                    else // Doesn't fit
                    {
                        if (wordsPerLine == 0) // Need an emegency break?
                        {
                            int breakBoundary = i;
                            while (breakBoundary < glyphs.Length && glyphRunAdvance + glyphs[breakBoundary].Advance < rectangles[rectangleIndex].Width)
                            {
                                currentGlyphRun.AddGlyph(breakBoundary);

                                glyphRunAdvance += glyphs[breakBoundary].Advance;

                                breakBoundary++;
                            }
                            i = breakBoundary - 1;
                        }
                        else
                        {
                            i--; // Retry the glyph against the next rectangle.
                        }

                        currentGlyphRun = BeginNewLayoutBox(ref rectangleIndex, rectangles, ref glyphRunAdvance, ref wordsPerLine, formattingSpan, layoutBoxes);

                        if (currentGlyphRun == null)
                            return layoutBoxes;
                    }
                }
            }

            return layoutBoxes;
        }