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