updated document regardling block and line-layout operation; this is html documents that are not part of the build nor part of any install process, etc.

This commit is contained in:
kipp%netscape.com 1999-11-03 21:11:37 +00:00
parent 0ac3221281
commit af2ba3fbb6
2 changed files with 239 additions and 159 deletions

View File

@ -2,134 +2,203 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.51 [en] (X11; U; Linux 2.0.36 i686) [Netscape]">
<meta name="GENERATOR" content="Mozilla/4.61 [en] (X11; I; Linux 2.2.5-22 i686) [Netscape]">
</head>
<body>
&nbsp;
<table CELLSPACING=0 CELLPADDING=0 COLS=1 WIDTH="100%" BGCOLOR="#33CCFF" NOSAVE >
<tr>
<td><font size=+3>Block Layout</font></td>
</tr>
</table>
<p>This document attempts to describe how "block" layout works in the mozilla
<h1>
<u>Block Layout</u></h1>
This document attempts to describe how "block" layout works in the mozilla
layout engine.
<p><tt>nsBlockFrame</tt> implements layout behavior that conforms to the
CSS "block" display property. The primary responsibility of the block code
is to manage "line layout". Line layout is the process where inline elements
are placed on a "line" hozironatally (left to right or right to left if
the CSS direction property is set rtl). In addition to line layout, blocks
are responsible for placement of left and right floating elements, and
handling "clear" semantics of child blocks or BR elements.
<p>To manage the child frames, nsBlockFrame uses a singly linked list of
nsLineBox's. nsLineBox's contain enough state to find all of the children
that belong to the block, plus support incremental reflow [Currently there
is too much state here - we waste memory].
<br>&nbsp;
<br>&nbsp;
<table CELLSPACING=0 CELLPADDING=0 COLS=1 WIDTH="100%" BGCOLOR="#33CCFF" NOSAVE >
<tr>
<td><font size=+2>Who's Who</font></td>
</tr>
</table>
CSS "display:block" and "display: list-item" layout. It has several responsibilities:
<ol>
<li>
&nbsp;Line layout. The block is responsible for flowing inline elements
into "lines" and applying all of the css behavior as one might expect,
including line-height, vertical-align, relative positioning, etc.</li>
<li>
Floater management. The block is responsible for the reflow and placement
of floating elements.</li>
<li>
Child block management. Blocks can contain inline elements and block elements.
Hence, blocks are responsible for reflowing child blocks. The majority
of that logic has been split out into nsBlockReflowContext, but a fair
amount remains here.</li>
<li>
Supporting table reflow. The block has to carefully compute the "max-element-size"
information needed by tables. Hence, any time changes are made here one
should always run the table regression tests because the odds are you broke
one of them!</li>
</ol>
<h3>
<u>The Big Picture for Block Reflow</u></h3>
The block frame uses a list of nsLineBox's to keep track of each "line"
of frames it manages. There are two types of lines:
<blockquote>"inline" lines which contain only inline elements
<br>"block" lines which contain exactly one block element</blockquote>
Each line has a "dirty" bit which indicates that it needs reflow. Reflow
consists of identifying which lines need to be marked dirty and then reflowing
all lines. For lines which are "clean" the reflow logic will endeavor to
recover the state of reflow <i>as if the line had been reflowed</i>. This
saves time and allows for a faster incremental reflow. For lines which
are dirty, the line is reflowed appropriately.
<p>The only special thing about incremental reflow command handling is
that it marks lines dirty before proceeding, and keeps track of the child
frame that is the next frame on the reflow command path.
<p>Here is a list of the various classes involved in block layout:
<p><b>nsBlockFrame</b>
<p>The primary culprit.
<p><b>nsBlockReflowState</b>
<p>This helper class is used to augment the nsHTMLReflowState with other
information needed by the block reflow logic during reflow. It is a temporary
object that is designed to live on the processor stack.
<p><b>nsBlockBandData</b>
<p>Another helper class that wraps up management of a space manager (nsISpaceManager,
nsSpaceManager) and nsBandData. It also assits in management of floating
elements. While nsSpaceManager is policy free, nsBlockBandData provides
specific HTML and CSS policy.
<p><b>nsBlockReflowContext</b>
<p>A helper class that encapsulates the logic needed to reflow a child
block frame. This is used by the block code reflow a child block, as well
as by the inline frame code to reflow an anonymous block, and by the block
code to reflow floating elements (which are to be treated as blocks according
to the CSS2 spec).
<p><b>nsLineBox</b>
<p>A data class used to store line information for the block frame code.
Each line has a list of children (though the frames are linked together
<blockquote>The primary culprit.</blockquote>
<b>nsBlockReflowState</b>
<blockquote>This helper class is used to augment the nsHTMLReflowState
with other information needed by the block reflow logic during reflow.
It is a temporary object that is designed to live on the processor stack
and contains "running" state used by the blocks reflow logic.</blockquote>
<b>nsBlockBandData</b>
<blockquote>Another helper class that wraps up management of a space manager
(nsISpaceManager, nsSpaceManager) and nsBandData. It also assists in management
of floating elements. While nsSpaceManager is policy free, nsBlockBandData
provides specific HTML and CSS policy.</blockquote>
<b>nsBlockReflowContext</b>
<blockquote>A helper class that encapsulates the logic needed to reflow
a child block frame. This is used by the block code reflow a child block
and to reflow floating elements (which are to be treated as blocks according
to the CSS2 spec).</blockquote>
<b>nsLineBox</b>
<blockquote>A data class used to store line information for the block frame
code. Each line has a list of children (though the frames are linked together
across lines to maintain the sibling list for nsIFrame::FirstChild) and
some other state used to assit in incremental reflow.
<p><b>nsLineLayout</b>
<p>This class is the line layout engine. Its a passive entity in the sense
that its the responsibility of the block/inline code to use the class (this
is done so that the line layout engine doesn't have to manage child frame
lists so that both nsBlockFrame and nsInlineFrame can use the class).
<p><b>nsTextRun</b>
<p>This is a data class used to store text run information. Tex turns are
logically contiguous runs of text (they may or may not be structurally
contiguous). The block frame stores a pointer to a list of nsTextRun's
and during line layout provides the list to the nsLineLayout engine so
that when text is reflowed the text layout code (nsTextFrame) can find
related text to properly handle word breaking.
<br><b></b>&nbsp;
<table CELLSPACING=0 CELLPADDING=0 COLS=1 WIDTH="100%" BGCOLOR="#33CCFF" NOSAVE >
<tr>
<td><font size=+2>Child Frame Management</font></td>
</tr>
</table>
some other state used to assist in incremental reflow.</blockquote>
<b>nsLineLayout</b>
<blockquote>This class is the line layout engine. Its a passive entity
in the sense that its the responsibility of the block/inline code to use
the class (this is done so that the line layout engine doesn't have to
manage child frame lists so that both nsBlockFrame and nsInlineFrame can
use the class).</blockquote>
<b>nsTextRun</b>
<blockquote>This is a data class used to store text run information. Text
runs are <i>logically</i> contiguous runs of text (they may or may not
be structurally contiguous). The block frame stores a pointer to a list
of nsTextRun's and during line layout provides the list to the nsLineLayout
engine so that when text is reflowed the text layout code (nsTextFrame)
can find related text to properly handle word breaking.</blockquote>
<p>When the blocks child list is modified (AppendFrames, InsertFrames,
RemoveFrame) the block code updates its nsLineBox list. Since each nsLineBox
is typed (some are marked "inline" and some are marked "block"), the update
logic maintains the invaraint of "one block frame per block line". Most
of the logic is straightforward, however there is some ugly code to manage
"first-line" frames. First-line frames are used when CSS's ":first-line"
style is selected for the block. When this is the case, the block code
creates an "anonymous first line" frame to manage the first inline children
(all of the inlines that preceed the first child block of the block).
<h3>
<u>Frame construction methods</u></h3>
When the blocks child list is modified (AppendFrames, InsertFrames, RemoveFrame)
the block code updates its nsLineBox list. Since each nsLineBox is typed
(some are marked "inline" and some are marked "block"), the update logic
maintains the invariant of "one block frame per block line".
<p>When structural changes are made to the blocks children (append/insert/remove)
the block code updates the line's and then marks the affected lines "dirty"
(each nsLineBox has a dirty bit). After the structural changes are finished
then the block will generate an incremental reflow command of type "ReflowDirty".
<h3>
<u>Line Layout</u></h3>
Line layout consists of the placement of inline elements on a line until
there is no more room on the line. At that point the line is "broken" and
continued on the next line. This process continues until all inline elements
have been exhausted. The block code maintains a list of "nsLineBox"'s to
facilitate this. These are used instead of frames because they use less
memory and because it allows the block to directly control their behavior.
<p>The helper class nsLineLayout provides the majority of the line layout
behavior needed by the block.
<p>The block does keep "text-run" information around for the nsLineLayout
logic to use during reflow. Text runs keep track of logically adjacent
pieces of text within a block. This information is essential for properly
computing line and word breaking. Why? Well, because in html you can write
something like this:
<p>&nbsp; &lt;p>I &lt;b>W&lt;/b>as thinking one day&lt;/p>
<p>Notice that the word "Was" is composed of two pieces of text, and that
they do <i>not</i> have the same parent (content or frame). To properly
reflow this and not break the word prematurely after the "W", the text-run
information is used by the text frame code to "look ahead" and prevent
premature breaking.
<p>Lines also keep track of the type of "break" that occurred on the line.
This is used, for example, to support html's "&lt;br clear=left>" behavior.
<h3>
<u>Floater Management</u></h3>
Since child block elements are containing blocks for floaters, the only
place where a block frame will see a floater is as part of an inline line.
Consequently, the nsLineBox will only keep track of floaters on inline
lines (saving storage for block lines).
<p>The nsLineLayout class and the block frame cooperate in the management
of floaters. Since the frame construction code leaves a "placeholder" frame
in-flow where the floater was found, when nsLineLayout reflows a placeholder
frame it knows to inform the block about it. That triggers the blocks "AddFloater"
logic which then determines where the floater should be placed (on the
current line or below the current line).
<p>The block frame uses the space manager to manage the effects of floaters,
namely the consumption of available space. For example, for a left aligned
floating element, the inline elements must be placed to the right of the
floater. To simplify this process, the spacemanager is used to keep track
of available and busy space. Floaters when placed mark space as busy and
the spacemanager will them compute the available space. Most of this logic
is handled by the nsBlockReflowState which uses a helper class, nsBlockBandData,
in concert with the space manager, to do the available space computations.
<h3>
<u>Child Block Placement</u></h3>
Child block reflow is done primarily by using the nsBlockReflowContext
code. However, a key detail worth mentioning here is how margins are handled.
When the nsHTMLReflowState was created, we placed into it the logic for
computing margins, border and padding (among other things). Unfortunately,
given the css rules for sibling and generational margin collapsing, the
nsHTMLReflowState is unable to properly compute top and bottom margins.
Hence, the block frame and the nsBlockReflowContext code perform that function.
At the time that the nsBlockReflowContext was designed and implemented
we thought that it could compute the top-margin itself and then proceed
to place the child block element. However, that turned out to be wrong
(oh well) because the correct available space isn't known until <i>after</i>
the top margin is computed. Hence, there is some unfortunate duplication
of reflow state calculations present in the block frame code.
<h3>
<u>Bullets</u></h3>
Another type of block frame is the "display: list-item". List-items use
nsBulletFrame's to manage bullet reflow. However, the block is responsible
for bullet placement. In most situations, the nsLineLayout class is used
to do the placement. However, if the first effective child of the block
is another block, then the block has to do the placement itself.
<h3>
<u>Blank lines</u></h3>
Because our content model contains as much of the original source documents
content as possible, we end up with a lot of white space that ends up being
compressed into nothingness. This white space ends up impacting this logic
in several ways. For example:
<p>&nbsp; &lt;div>
<br>&nbsp;&nbsp; &lt;p>abc&lt;/p>
<br>&nbsp;&nbsp; &lt;p>def&lt;/p>
<br>&nbsp; &lt;/div>
<p>In the content model for the above html, there is white space between
the various block elements (some after the &lt;div>, some after the first
&lt;/p>, again after the second &lt;/p>).
<p>For css margin collapsing to work properly, each of those instances
of white space has to behave as if they didn't exist. Consequently, there
is special logic in the inline line reflow code, and in the nsBlockReflowContext
code and in the GetTopBlockChild method, to basically ignore such lines.
<h3>
<u>First-letter style</u></h3>
The block contributes, in a small way, to first-letter style reflow. The
frame construction code is responsible for creating the list of child frames
for all frames, including the block. It manages the creation of letter-frames,
where appropriate, so that all the block has to do is reflow them almost
normally like other inline frames.
<p>There are two things different that the block does:
<p>It is responsible for calling nsLineLayout::SetFirstLetterStyleOK
<br>It is responsible for continuing to place frames on a line, even after
a frame has said "it can't fit". Normally during inline reflow, if a frame
comes back and says it can't fit, the block will end the line, push all
remaining frames to the next line and pick up the reflow from there after
making sure the frame that didn't fit is continued. For letter-frames,
this would result in the first-letter being on one line with the remaining
text on subsequent lines. Hence, the block code handles this special case.
<br>&nbsp;
<table BORDER=0 CELLSPACING=0 COLS=1 WIDTH="100%" BGCOLOR="#33CCFF" NOSAVE >
<tr>
<td><font size=+2>Basic Reflow&nbsp;Logic</font></td>
</tr>
</table>
<p>The block's reflow engine uses the nsLineBox's dirty bit to determine
what to reflow. For each line in the block, its dirty bit is examined.
If the bit is not set then the line is considered "clean" and the block
determines
<b>where</b> the line is to be placed. For dirty lines, the
line is reflowed and when finished, lines affected by the reflow are marked
dirty. The loop proceeds until either there is no more space for placing
lines, or there are no more lines (including draining lines from continuations).
<p>For each line reflowed, there are two types of lines: block lines and
inline lines. Block lines use ReflowBlockFrame to setup and reflow the
single block child on the line. Inline lines use nsReflowInlineFrames to
setup and reflow one or more inline frames on the line.
<p>nsBlockReflowContext is a helper class used to reflow child block frames.
nsLineLayout is a helper class used to reflow inline frames. See the document
on line layout for more detail on how it works.
<br>&nbsp;
<table BORDER=0 CELLSPACING=0 COLS=1 WIDTH="100%" BGCOLOR="#33CCFF" NOSAVE >
<tr>
<td><font size=+2>Floater Handling</font></td>
</tr>
</table>
<p>When frames are created by the frame construction code, "placeholders"
are made that remain in-the-flow while the floating element is moved out-of-flow.
Block frames receive child floating frames and keep them on a floater list.
Note that if an inline frame contains a floating element it to will recieve
a placeholder frame, but the floating frame will go to the inline frames
containing block.
<p>During the reflow of an inline line, the line layout logic will become
aware of reflowing a placeholder frame for a floating element. When it
does, it will inform the containing block of the floater so that the block
and reflow and then place the floating element. To assist in this process,
the nsBlockReflowState (misnamed) and the nsBlockBandData classes are used
by the block code to do the bulk of the work. These classes also assist
heavily in handling of the CSS "clear" property and HTML BR elements.
<h3>
<u>First-line style</u></h3>
First-line is handled entirely by the frame construction code.
<br>&nbsp;
<br>&nbsp;
</body>

View File

@ -2,47 +2,42 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.5 [en] (X11; I; Linux 2.0.36 i686) [Netscape]">
<meta name="GENERATOR" content="Mozilla/4.61 [en] (X11; I; Linux 2.2.5-22 i686) [Netscape]">
</head>
<body>
&nbsp;
<table CELLSPACING=0 CELLPADDING=0 COLS=1 WIDTH="100%" BGCOLOR="#33CCFF" NOSAVE >
<tr>
<td><font size=+4>Line Layout</font></td>
</tr>
</table>
<p>Line layout is the process of placing inline frames horizontally (left
<h1>
<u>Line Layout</u></h1>
Line layout is the process of placing inline frames horizontally (left
to right or right to left depending on the CSS direction property value).
An attempt is made to describe how it works.
<p>nsLineLayout is the class that provides <b>support</b> for line layout.
The container frames nsBlockFrame and nsInlineFrame use nsLineLayout to
perform line layout and span layout. Span layout is a subset of line layout
used for inline container classes - for example, the HTML "B" element).
Because of spans, nsLineLayout handles the nested nature of line layout.
<p>nsLineLayout is the class that provides support for line layout. The
container frames nsBlockFrame and nsInlineFrame use nsLineLayout to perform
line layout and span layout. Span layout is a subset of line layout used
for inline container classes - for example, the HTML "B" element). Because
of spans, nsLineLayout handles the nested nature of line layout.
<p>Line layout as a process contains the following steps:
<ol>
<li>
Initialize the nsLineLayout object (done in nsBlockFrame). This prepares
the line layout engine for reflow by initializing its internal data structures.<br>
<BR></li>
the line layout engine for reflow by initializing its internal data structures.</li>
<br>&nbsp;
<li>
Reflowing of inline frames. The block code uses nsLineLayout's <b>ReflowFrame</b>
method to reflow each inline frame in a line. This continues until the
line runs out of room or the block runs out of frames. The block may be
reflowing a span (an instance of nsInlineFrame) which will recursively
use nsLineLayout for reflow and placement of the frames in the span.<br>
<br>
Note that the container frames (nsBlockFrame/nsInlineFrame)&nbsp;call nsLineLayout's
ReflowFrame method instead of having the line layout code process a list
of children. This is done so that the container frames can handle the issues
of "pushing" and "pulling"&nbsp;of frames across continuations. Because
block and inline maintain different data structures for their child lists,
and because we don't want to mandate a common base class, the line layout
code doesn't control the "outer loop"&nbsp;of frame reflow.<br>
<BR></li>
use nsLineLayout for reflow and placement of the frames in the span.</li>
<p><br>Note that the container frames (nsBlockFrame/nsInlineFrame) call
nsLineLayout's ReflowFrame method instead of having the line layout code
process a list of children. This is done so that the container frames can
handle the issues of "pushing" and "pulling" of frames across continuations.
Because block and inline maintain different data structures for their child
lists, and because we don't want to mandate a common base class, the line
layout code doesn't control the "outer loop" of frame reflow.
<br>&nbsp;
<li>
Finish line layout by vertically aligning the frames, horizontally aligning
the frames and relatively positioning the frames on the line.</li>
@ -68,36 +63,52 @@ breaks like page breaks, floater breaks, etc. Currently, we only support
line breaks, and floater clearing breaks. Breaks can occur before the frame
(NS_INLINE_IS_BREAK_BEFORE) or after the frame (NS_INLINE_IS_BREAK_AFTER)</li>
</ul>
The handling of the reflow status is done by the container frame <b>using</b>
The handling of the reflow status is done by the container frame using
nsLineLayout.
<br>&nbsp;
<table CELLSPACING=0 CELLPADDING=0 COLS=1 WIDTH="100%" BGCOLOR="#33CCFF" NOSAVE >
<tr>
<td><font size=+3>Line Breaking</font></td>
</tr>
</table>
<p>Another aspect of nsLineLayout is that it supports line breaking. At
the highest level, line breaking consists of identifying where it is appropriate
<h3>
<u>Line Breaking</u></h3>
Another aspect of nsLineLayout is that it supports line breaking. At the
highest level, line breaking consists of identifying where it is appropriate
to break a line that doesn't fit in the available horizontal space. At
a lower level, some frames are breakable (e.g. text) and some frames are
not (e.g. images).
<p>In order to break text properly, some out-of-band information is needed
by the text frame code (nsTextFrame). In particular, because a "word"&nbsp;(a
non-breakable unit of text) may span several frames (for example:&nbsp;<b>"&lt;B>H&lt;/B>ello
there"</b> is breakable after the <b>"o"</b>&nbsp;in ello but not after
by the text frame code (nsTextFrame). In particular, because a "word" (a
non-breakable unit of text) may span several frames (for example: <b>"&lt;B>H&lt;/B>ello
there"</b> is breakable after the <b>"o"</b> in "<b>ello</b>" but not after
the <b>"H"</b>), text-run information is used to allow the text frame to
find adjacent text and look at them to determine where the next breakable
point is. nsLineLayout supports this by keeping track of the text-runs
as well as both storing and interrogating "word" state.
<p>In addition, nsLineLayout assists in the compression/expansion of whitespace
for the CSS&nbsp;white-space property. Compression occurs when neighboring
whitespace either inside a single piece of text is compressed or when spaces
between abutting elements is collapsed. Expansion occurs in preformatted
text when tabs are found. nsLineLayout keeps track of a "column"&nbsp;which
is used to determine where the next tab "moves"&nbsp;to.
<br>&nbsp;
<br>&nbsp;
<h3>
<u>White-space</u></h3>
To support the white-space property, the line layout logic keeps track
of the presence of white-space in the line as it told to reflow each inline
frame. This allows for the compression of leading whitespace and the compression
of adjacent whitespace that is in seperate inline elements.
<p>As a post-processing step, the TrimTrailingWhiteSpace logic is used
to remove those pesky pices of white-space that end up being placed at
the end of a line, that shouldn't really be seen.
<p>To support pre-formatted text that contains tab characters, the line
layout class keeps track of the current column on behalf of the text frame
code.
<h3>
<u>Vertical Alignment</u></h3>
Vertical alignment is peformed as a two and a half pass process. The first
pass is done during nsInlineFrame reflow: the child frames of the nsInlineFrame
are vertically aligned as best as can be done at the time. There are certain
values for the vertical-align property that require the alignment be done
after the lines entire height is known; those frames are placed during
the last half pass.
<p>The second pass is done by the block frame when all of the frames for
a line are known. This is where the final height of the line
<br>(not the line-height property) is known and where the final half pass
can be done to place all of the top and bottom aligned elements.
<br>&nbsp;
<h3>
<u>Horizontal Alignment</u></h3>
After all frames on a line have been placed vertically, the block code
will use nsLineLayout to perform horizontal alignment within the extra
space.
</body>
</html>