diff --git a/layout/docs/LayoutOverview.md b/layout/docs/LayoutOverview.md index 0316bfe69aeb..0375ab548043 100644 --- a/layout/docs/LayoutOverview.md +++ b/layout/docs/LayoutOverview.md @@ -326,7 +326,204 @@ TODO: layers ## Pagination -The concepts behind pagination (also known as fragmentation) are a bit -complicated, so for now we\'ve split them off into a separate document: -[Gecko:Continuation\_Model](Gecko:Continuation_Model "wikilink"). This -code is used for printing, print-preview, and multicolumn frames. +Pagination (also known as fragmentation) is a concept used in printing, +print-preview, and multicolumn layout. + +### Continuations in the Frame Tree + +To render a DOM node, represented as `nsIContent` object, Gecko creates +zero or more frames (`nsIFrame` objects). Each frame represents a +rectangular area usually corresponding to the node\'s CSS box as +described by the CSS specs. Simple elements are often representable with +exactly one frame, but sometimes an element needs to be represented with +more than one frame. For example, text breaking across lines: + + xxxxxx AAAA + AAA xxxxxxx + +The A element is a single DOM node but obviously a single rectangular +frame isn\'t going to represent its layout precisely. + +Similarly, consider text breaking across pages: + + | BBBBBBBBBB | + | BBBBBBBBBB | + +------------+ + + +------------+ + | BBBBBBBBBB | + | BBBBBBBBBB | + | | + +Again, a single rectangular frame cannot represent the layout of the +node. Columns are similar. + +Another case where a single DOM node is represented by multiple frames +is when a text node contains bidirectional text (e.g. both Hebrew and +English text). In this case, the text node and its inline ancestors are +split so that each frame contains only unidirectional text. + +The first frame for an element is called the **primary frame**. The +other frames are called **continuation frames**. Primary frames are +created by `nsCSSFrameConstructor` in response to content insertion +notifications. Continuation frames are created during bidi resolution, +and during reflow, when reflow detects that a content element cannot be +fully laid out within the constraints assigned (e.g., when inline text +will not fit within a particular width constraint, or when a block +cannot be laid out within a particular height constraint). + +Continuation frames created during reflow are called \"fluid\" +continuations (or \"in-flows\"). Other continuation frames (currently, +those created during bidi resolution), are, in contrast, \"non-fluid\". +The `NS_FRAME_IS_FLUID_CONTINUATION` state bit indicates whether a +continuation frame is fluid or not. + +The frames for an element are put in a doubly-linked list. The links are +accessible via `nsIFrame::GetNextContinuation` and +`nsIFrame::GetPrevContinuation`. If only fluid continuations are to be +accessed, `nsIFrame::GetNextInFlow` and `nsIFrame::GetPrevInFlow` are +used instead. + +The following diagram shows the relationship between the original frame +tree considering just primary frames, and a possible layout with +breaking and continuations: + + Original frame tree Frame tree with A broken into three parts + Root Root + | / | \ + A A1 A2 A3 + / \ / | | | + B C B C1 C2 C3 + | /|\ | | | \ | + D E F G D E F G1 G2 + +Certain kinds of frames create multiple child frames for the same +content element: + +- `nsPageSequenceFrame` creates multiple page children, each one + associated with the entire document, separated by page breaks +- `nsColumnSetFrame` creates multiple block children, each one + associated with the column element, separated by column breaks +- `nsBlockFrame` creates multiple inline children, each one associated + with the same inline element, separated by line breaks, or by + changes in text direction +- `nsTableColFrame` creates non-fluid continuations for itself if it + has span=\"N\" and N \> 1 +- If a block frame is a multi-column container and has + `column-span:all` children, it creates multiple `nsColumnSetFrame` + children, which are linked together as non-fluid continuations. + Similarly, if a block frame is within a multi-column formatting + context and has `column-span:all` children, it is chopped into + several flows, which are linked together as non-fluid continuations + as well. See documentation and example frame trees in + [`nsCSSFrameConstructor::ConstructBlock()`](https://searchfox.org/mozilla-central/rev/d24696b5abaf9fb75f7985952eab50d5f4ed52ac/layout/base/nsCSSFrameConstructor.cpp#10431). + +#### Overflow Container Continuations + +Sometimes the content of a frame needs to break across pages even though +the frame itself is complete. This usually happens if an element with +fixed height has overflow that doesn\'t fit on one page. In this case, +the completed frame is \"overflow incomplete\", and special +continuations are created to hold its overflow. These continuations are +called \"overflow containers\". They are invisible, and are kept on a +special list in their parent. See documentation in +[nsContainerFrame.h](https://searchfox.org/mozilla-central/source/layout/generic/nsContainerFrame.h) +and example trees in [bug 379349 comment +3](https://bugzilla.mozilla.org/show_bug.cgi?id=379349#c3). + +This infrastructure was extended in [bug +154892](https://bugzilla.mozilla.org/show_bug.cgi?id=154892) to also +manage continuations for absolutely-positioned frames. + +#### Relationship of continuations to frame tree structure + +It is worth emphasizing two points about the relationship of the +prev-continuation / next-continuation linkage to the existing frame tree +structure. + +First, if you want to traverse the frame tree or a subtree thereof to +examine all the frames once, you do ``{=html}not``{=html} want +to traverse next-continuation links. All continuations are reachable by +traversing the `GetNextSibling` links from the result of `GetFirstChild` +for all child lists. + +Second, the following property holds: + +- Consider two frames F1 and F2 where F1\'s next-continuation is F2 + and their respective parent frames are P1 and P2. Then either P1\'s + next continuation is P2, or P1 == P2, because P is responsible for + breaking F1 and F2. + +In other words, continuations are sometimes siblings of each other, and +sometimes not. If their parent content was broken at the same point, +then they are not siblings, since they are children of different +continuations of the parent. So in the frame tree for the markup + +`
This is some
text.