pjs/layout/doc/HLD-SpaceManager.html

254 строки
12 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>Space Manager High Level Design</title>
<meta name="author" content="Marc Attinasi (attinasi@netscape.com)">
</head>
<body>
<h1><font color="#cc0000">Gecko Layout High Level Design Document</font></h1>
<h1>Space Manager High Level Design</h1>
<br>
<h2>Overview</h2>
The Space Manager and associated classes and strructures are used by Block
and Line layout to manage rectangular regions that are occupied and available,
for correct handling of floated elements and the elements that flow around
them. &nbsp;When elements are floated to the left or right in a layout, they
take up space and influence where other elements can be placed. &nbsp;The
Space Manager is responsible for keeping track of where space is taken up
and where it is available. This information is used by block layout to correctly
compute where other floated elements should be placed, and how much space
is available to normal in-flow elements that flow around the floated bits.<br>
<br>
The Space Manager works in concert with several other classes to do its
job. The classes that are considered part of the Space Manager are:<br>
<ul>
<li>nsSpaceManager</li>
<li>nsBandData</li>
<li>nsBlockBandData</li>
<li>BandRect / BandList (private structs)</li>
<li>FrameInfo (private struct)</li>
<li>nsBandtrapezoid</li>
</ul>
Outside of the Space Manager itself, the clients of the Space Manager also
play an inportant part in the management of he available and used space.
&nbsp;The primary classes that interact witht eh Space Manager are:<br>
<ul>
<li>nsBlockReflowState</li>
<li>nsBlockFrame</li>
<li>nsBoxToBlockAdaptor</li>
</ul>
The general interaction model is to create a Space Manager for a block
frame in the context of a Reflow, and to associate it with the BlockReflowState
so it is passed down to child frames' reflow methods. After reflow, the
Space Manager is destroyed. &nbsp;During reflow, the space manager stores
the space taken up by floaters (UpdateSpaceManager in nsBlockFrame) and
provides information about the space available for other elements (GetAvailableSpace
in nsBlockReflowState). &nbsp;<br>
<br>
Additionally, there is a need to manage impacts to lines caused by changes
to floated elements. &nbsp;This is referred to as Propagation of Floater Damage
and is handled by the Block Frame, making use of teh Space Manager. When
dirty lines are incrementally reflowed, the Space Manger is told about the
larger of the new or old line combined width, which it records in an internal
nsIntervalSet as potential floater damage (the method is IncludeInDamage).
During the incremental reflow of dirty lines the block frame may encounter
lines that are NOT dirty. In this case the Space Manager is also asked if
&nbsp;there is any floater damage, and if there is then the block further
checks to see if that damage intersects the area of the non-dirty line, marking
it dirty if there is intersection. &nbsp;Thus, changes to floaters on other
lines may cause impact to otherwise clean lines, and the Space Manager facilitates
the detection of this.
<h2>Data Model</h2>
<h4>Class/Component Diagram</h4>
<blockquote>
<div align="Left"><img src="SpaceManagerClasses.png" alt="SpaceManager Class Diagram" idth="500" eight="459" title="Example Class Diagram">
<br>
</div>
</blockquote>
<ul>
<li>nsSpaceManager: The central point of management of the space taken
up by floaters in a block</li>
<li>nsBandData: Provides information about the frames occupying a band
of occupied or available space</li>
<li>nsBlockBandData: A specialization of nsBandData that is used by
nsBlockReflowState to determine the available space, floater impacts, and
where floaters are cleared. &nbsp;Essentially a CSS-specific wrapper for
generic nsBandData.</li>
<li>BandRect: Keeps the bounds of a band, along with the frames associated
with the band. &nbsp;BandRects are a linked list (provided by PRCListStr
super-class) and also provide some geometry-management methods (SplitVertically,
SplitHorizontally) and some methods that query or manipulate the frames associated
with the band (IsOccupiedBy, AddFrame, RemoveFrame).</li>
<li>BandList: A subclass of BandRect that provides a list interface
- Head(), Tail(), IsEmpty(), etc.</li>
<li>FrameInfo: A structure that keeps information about the rectangle
associated with a specific frame, in a linked list.</li>
<li>nsBandTrapezoid: Represents the discrete regions within a band that
are either Available, Occupied by a single frame, or Occupied by several
frames. &nbsp;This is used to communicate information about the space in
the band to the clients of the SpaceManager. &nbsp;There is no internal use
of the nsBandTrapezoid by the Space Manager, rather it uses its internal
BandList to create a BandData collection, which is largely made up of nsTrapezoid
data.<br>
</li>
</ul>
<h2>Use Case</h2>
<h4>Use Case 1: Space Manger is Created / Destroyed</h4>
Space Manager instances are created in the nsBlockFrame's Reflow method.
&nbsp;<br>
<ul>
<li>An instance is created&nbsp;</li>
<li>The BlockReflowState's previous Space Manger is saved off.</li>
<li>The new Space Manger instance is associated with the BlockReflowState.
&nbsp;</li>
<li>After the block frame's Reflow has completed, the old Space Manager
instance is re-associated with the BlockReflowState</li>
<li>The new Space Manager is destroyed.</li>
</ul>
If the BlockReflowState already had a Space Manager instance associated
with it, it is stored off before being replaced, and the returned to the
BlockReflowState instance after the new one has been destroyed. &nbsp;Thus,
Space Managers are effectively 'nested' during reflow, with each new block
introducing its own Space Manager.
<h4>Use Case 2: Floater is added to the Space Manager</h4> After a Space Manager is created for a block context's reflow chain, a
floated block may be added to it. &nbsp;This happens in the method <i>nsBlockReflowState::RecoverFloaters</i> and
<i>nsBlockReflowState::FlowAndPlaceFloater</i> (formerly this was done in nsBlockFrame::UpdateSpaceManager). &nbsp;<br>
<br>
The general algorightm in <i>nsBlockReflowState::RecoverFloaters</i> is:<br>
<ul>
<li>For each line in the block, see if it has floated blocks</li>
<li>If floaters are in the line, iterate over the floaters and add each
one to the Space Manger via the AddRectRegion method. &nbsp;The actual rect
for the frame is cached in an nsFloaterCache so it does not have to be recomputed.</li>
<li>If the block has any block children, then translate the Space Manager
to the child block's origin and update the space manager in the context
for the child block, recursively. When done with the child, restore the Space
Managers coordinates by translating by the negative of the child block's
origin.&nbsp; <br>
</li>
</ul><br>
The general algorightm in <i>nsBlockReflowState::FlowAndPlaceFloater</i> is:<br>
<ul>
<li>The band of available space is searched (with nsBlockReflowState::GetAvailableSpace);</li>
<li>The floater frame that is get from the passed nsFloaterCache argument is reflowed
and its rect is retriven with GetRect;</li>
<li>The floaters margins are added;</li>
<li>Check if the floater can be placed in the acutal band: if not advance to the next band;</li>
<li>Check the floater type and if it can be added to the space manager;</li>
<li>Align the floater to its containing block top if rule
<a href="http://www.w3.org/TR/REC-CSS2/visuren.html#float-position">CSS2/9.5.1/4</a>
is not respected;</li>
<li>Add the floater using <i>nsSpaceManager::AddRectRegion</i> </li>
</ul>
<h4>Use Case 3: Space Manager is used to find available space to reflow
into</h4>
The nsBlockFrame makes use of the Space Manager indirectly to get the available
space to reflow a child block or inline frame into. The block frame uses
a helper method on the nsBlockReflowState class to do the actual computation
of available space based on the data in the Space Manger. Here is how it
works for reflowing an inline frame within a block (this also occurs for
reflowing a block frame and, partially, for preparing for a resize reflow).<br>
<ul>
<li>nsBlockFrame first frees all floater information for the line that
is being reflowed.</li>
<li>GetAvailableSpace is called on the BlockReflowState</li>
<li>the BlockReflowState calls GetAvailableSpace on its BlockBandData
instance (which was setup in the BlockReflowState's constructor based on
the SpaceManager passed in and computed content area).</li>
<li>BlockBandData then gets the band data from the space manager via
a call to the Space Manager associated with the BlockBandData instance.</li>
<li>The BlockBandData then walks the collection of trapezoids that were
returned by the SpaceManager method GetBandData (as nsBandData wrappers)
and determines the right-most edge of the available space.</li>
<li>The BlockReflowState then stores this available space rect for use
in the rest of the reflow chain.<br>
</li>
</ul>
<h4>Use Case 4: Propagation of Floater Damage: remembering floater damage</h4>
This process is driven by the Block Frame.<br>
<ul>
<li>A dirty line is reflowed</li>
<li>If the line's combined area has changed then the Space Manager is
told to include the combined area as a floater damage interval.</li>
</ul>
<h4>Use Case 5: Propagation of Floater Damage: detecting and handling floater
damage</h4>
This process is driven by the Block Frame.<br>
<ul>
<li>A non-dirty line is encountered by the Block Frame in ReflowDirtyLines</li>
<li>Block Frame calls its PropagateFloaterDamage method</li>
<li>The Space Manger is checked to see if ther is any floater damage</li>
<li>If there is, then the block frame asks the Space Manager if the
line in question intersects the floater damage</li>
<li>If the line does intersect a damage interval, then the line is marked
dirty</li>
<li>If the line does not intersect a damage interval, it may still be
marked dirty if:</li>
<ul>
<li>it was impacted by floaters before, but is not any longer</li>
<li>it was not impacted by floaters befre, but is now</li>
<li><a name="block-line-impact"></a>
it is impacted by floaters and is a block<br>
</li>
</ul>
</ul>
<br>
<hr width="100%" size="2"><br>
<h1><font color="#ff0000">Problems / bugs found during documentation:</font></h1>
<ul>
<li>BandRect and BandList are public in nsSpaceManager.h - should be
private (compiles fine)</li>
<li>nsSpaceManager data members are declared protected, but there are
no subclasses. Should be private (compiles fine)</li>
<li>nsBlockFrame::Paint is mucking with nsBlockBandData in and #if 0
block - remove that and the include (compiles fine)</li>
<li>nsSpaceManger has no way of clearing the floater damage interval
set - this might be needed if the SpaceManager persists beyond a Reflow</li>
<li>As dbaron has documetned inteh code, the floater damage logic is
flawed: it only handles vertical changes to a line's combined area. &nbsp;The
Floater Damage API on the Space Manger does not support horizontal changes,
and the block frame does not attempt to handle them either except for the
case of a <a href="#block-line-impact">block-line impacted by a floater</a>
.</li>
</ul>
<br>
<br>
</body>
</html>