![]() |
New Layout: HTML LayoutAuthors: Troy Chevalier, Kipp Hickman, Rick Gessner, Steve ClarkUpdated: 30 April 1998
HTML layout is the set of classes that implement the HTML layout semantics.
The major components of HTML layout are body, block, inline, list item, table, and the leaf components like BR, IMG, and SPACER. Content Model. The base class for leaf HTML content objects is nsHTMLTagContent, which is for content objects that have HTML attributes. Most HTML container tags (for example, P, DIV, SPAN, etc.) have content objects that are instances of class nsHTMLContainer. nsHTMLContainer is a derived class of nsHTMLTagContent which manages an array of child content nodes. Frame creation. Whether an element is displayed as block or inline is not a function of the HTML tag, but of the associated stylistic information (see struct nsStyleDisplay). Class nsHTMLContent is the abstract base class for all HTML content objects. It creates the one and only content delegate (class ContentDelegate) that is used for all HTML content. When asked to create a frame the HTML content delegate asks the content object to create the frame. nsHTMLContainer responds by looking at the display type. If it's a block then it creates a block frame, if it's inline then it creates an inline frame, and if it's a list item then it creates a list item frame. The mapping of HTML elements to either block or inline is controlled by our default UA style sheet (file ua.css). Display None. To simplify managing of the child frames, we always create and insert a frame even if the display type is set to none. The frame that's created is of type nsFrame, and it has a size of (0, 0) and no stylistic information (no border, padding, ...). Because nsFrame is a leaf frame no child frames are generated, regardless of whether the associated content is a container.
Body Frame. Class nsBodyFrame is the frame class that's used for displaying the BODY tag. The associated content object is an instance of class BodyPart (derived class of nsHTMLContainer). nsBodyFrame supports being used as a pseudo frame, and it's often used that way. For example, table cells create a body pseudo frame for displaying the table cell data. The body frame is basically a vertical box that arranges its block-level elements from top to bottom. If it encounters an inline element, the body frame wraps the inline element in a block pseudo frame. Block Frame. Class nsCSSBlockFrame is the frame class that's used for displaying block-level elements. Block frame is a 2D layout class that lays out its block-level elements from top to bottom, and its inline elements from left to right (or right to left). Block frame has logical lines, but it does not actually have line child frames. This greatly reduces the number of frames, which means we lay out faster and we use less memory. Block frame also supports being used as a pseudo frame. Class nsListItemFrame, which handles list items, is derived from nsCSSBlockFrame. It manages the placement and painting of the list item bullet. Inline Frame. Class nsCSSInlineFrame is the frame class that's used for displaying inline elements. Inline frames are simple horizontal boxes that arrange their child frames either left to right or right to left depending on the stylistic direction. Inline frames do not support being used as a pseudo frame. This reflects the fact that we haven't needed to use Reflow Unmapped. Reflow Mapped. As you look through the HTML frame clases you'll see some similarities in the code, and you'll see some common terminology:
All the table code is contained within the layout/html/table sub-directory. Table content is stored as a normalized HTML 4.0 table. Table layout reflects the content according to a set of constraints. The constraints are a combination of physical (i.e. the width of the browser window), contentual (content of each cell), and stylistic (i.e. the HTML WIDTH attribute, CSS Style, or a compatibility mode, etc). The hierarchy for a table is:
nsTablePart maintains an nsCellMap, which is a structured description of all the cells in a table. It is the nsCellMap that holds information about the effects of row and column spans on cells. The cell map is a regular n x m grid onto which cells are overlaid, allowing us to easily answer questions about what cell occupies a logical region in the table, even for irregular tables that include complex row and column spans. Layout. Table layout is represented by a hierarchy of frame objects that describe the geometry of the table. The frame model closely mimics the content model, with a few exceptions noted below.
Table layout is determined in a 3-step process. In the first step, the table is flowed into an infinitely wide and tall space. This gives us the minimum and desired sizes for every cell in the table. In the second step, the table constraints are factored in and widths are assigned to every cell. In the third step, heights are assigned to every cell based on the computed width constraint. The results of the first step are cached and only need to be recomputed when content or constraints are changed. The near future. Table layout is designed to support multiple notions of "correct" table layout. An nsITableLayoutStrategy interface will soon be added that defines how a table should be laid out. We envision at least three implementations of nsITableLayoutStrategy: one for Netscape Navigator compatibility, one for Internet Explorer compatibility, and one for full HTML 4.0/CSS 2.0 support. An implementation of nsITableLayoutStrategy will be selected at run-time for a particular view of a table based on the stylistic properties of the table. Table layout is designed to support intelligent pagination. This means that tables will break atreasonable places across boundaries (pages, columns, etc). So for example, table pagination will be biased to keep captions and tables together, to break on row boundaries so cell data is kept together as much as possible, and THEAD and TFOOT information is replicated across breaks. For the latest information on where tables are going, see the table to-do list.
The placeholder frame creates the actual floater frame, but it is not inserted in the flow. Instead, the placeholder frame walks the frame hierarchy (geometric parents) looking for a frame that implements the nsIFloaterContainer interface. This is the containing block for the floater. The containing block is notified of the floater (see the AddFloater() member function). The floater is then either placed at the current line, or added to a to-do list of floaters to be placed below the current line. The frame itself is inserted as a child of the body frame; this keeps it out of the list of flowed children. The containing block finds the frame where it should insert the floater by walking the frame hierarchy looking for a frame that implements the nsIAnchoredItems interface. The containing block also notifies the space manager (nsISpaceManager) that the space is now unavailable (see AddRectRegion() member function). Runaround (flowing text around the anchored item) happens because the block frame calls the space manager to get a band of available space. The band data indicates which parts of the band are available, and which parts are unavailable. The space manager is created by the body frame. Each body frame has its own space manager, which means that each table cell has an associated space manager. How runaround works depends on the block-level frame being reflowed. If you're willing to interact directly with the space manager, implement interface nsIRunaround and you get access to the band data. Do this if your frame supports being non-rectangular. This is what block frames does. If you don't implement nsIRunaround then your parent frame will place you in the available space between the left and right floaters.
The HTML layout code has dependencies on the content/document model, the style system, the view hierarchy, and the graphics system.
|
|||||||||||
|
Copyright © 1998-1999 The Mozilla Organization.
Last modified July 20, 1998. |
|||||||||||