Field MaxPagesWithoutSplitRowProgress
How many pages in a row may be started for one table row without any part of the row being placed on them, before the layout is abandoned.
public const int MaxPagesWithoutSplitRowProgress = 64
Returns
- int
- How many pages in a row may be started for one table row without any part of the row being placed on them, before the layout is abandoned.
Remarks
Why there is a ceiling at all. The loop that places a row across regions has two ways round: it places a fragment, or it moves to the next region having placed nothing. The first is bounded by the row's own height. The second was not bounded by anything, and a document that sent it round that way for ever - one page and one repeat of the header rows a turn - took memory until the process died, whatever limits the caller had set. The rule that decides when a region may turn a fragment away now ends (DocWright.Layout.LayoutEngine.HeaderRowsWouldStrandRow(DocWright.Layout.LayoutEngine.MeasuredTable,System.Int32,DocWright.Core.Primitives.Twips,DocWright.Layout.ResolvedSection,DocWright.Layout.LayoutEngine.ComposeContext)); this is what holds if a later change to it does not.
Why 64, and why pages. A page takes nothing of a row in two cases only: the row arrived on it below other content, or it kept its repeated header rows because a page that was looked at from it will take the row. The look goes no further than the third page on, and the page it found does take the row when the flow reaches it, so at most three pages in a row are left with nothing of the row on them: the one it arrived on and the two before the one that takes it. 64 is twenty times that and more, and it is counted in pages because the regions of one page are already bounded (MaxSectionColumns). What reaching it costs is one repeat of the header rows per page: measured on the document that found the defect, whose two header rows fill nine tenths of a page, the old loop made 2,032 such pages in two seconds and kept 187 MB for them, so 64 of them are a few megabytes and well under a second before the exception.
Why it is not a ResourceLimits member (decided in Phase 72, when
MaxSpanCoveredCells became one). It is a liveness backstop rather than a
budget: no document reaches it on the shipped rule, so raising it would buy nothing,
and turning it off could only bring back the unbounded loop it was written against.
It is public so that the LimitName it reports names a member a caller can
find; a caller who wants a page budget sets ResourceLimits.MaxPages, which
layout now checks at every page it starts.