import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,743 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!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>Detailed Design Template</title>
</head>
<body>
<h1><font color="#cc0000">Gecko Layout Detailed Design Document</font></h1>
<h1>Space Manager Detailed Design</h1>
<h2>Overview</h2>
<p>
The Space Manager and related classes and structures are an important of
the Gecko Layout system, specifically Block Layout. &nbsp;See the High Level
Design document for an overview of the Space Manager, and as an introduction
to the classes, structures and algorithms container in this, the Detailed
Design Document.
</p>
<hr width="100%" size="2">
<h2>nsSpaceManager</h2>
<p>
The Space Manager is the central class is a group of classes that manage
the occupied and available space that exists in horizontal bands across
a canvas. &nbsp;The primary goal of the Space Manager is to provide information
about those bands of space to support the CSS notion of floated elements.
</p>
<p>
There are three important parts to the Space Manager API: the parts that
deal with the coordinate space of the Space Manager, the parts that deal with
the regions managed by the Space Manager, and the parts that manage float
impact intervals.
</p>
<p>
The class nsSpaceManager is declared in the file <a href="http://lxr.mozilla.org/seamonkey/source/layout/base/src/nsSpaceManager.h">
nsSpaceManger.h</a>
. &nbsp;The class is only used in the layout module and cannot be exported
outside of that module (nor does it need to be). &nbsp;It is not a general
purpose class, and is not intended to be subclasses<font color="#cc0000">
.</font>
</p>
<p>
Here is the class declaration, taken from the source file as of 01.08.02
</p>
<pre>/**
* Class for dealing with bands of available space. The space manager
* defines a coordinate space with an origin at (0, 0) that grows down
* and to the right.
*/
class nsSpaceManager {
public:
nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
~nsSpaceManager();
void* operator new(size_t aSize);
void operator delete(void* aPtr, size_t aSize);
static void Shutdown();
/*
* Get the frame that's associated with the space manager. This frame
* created the space manager, and the world coordinate space is
* relative to this frame.
*
* You can use QueryInterface() on this frame to get any additional
* interfaces.
*/
nsIFrame* GetFrame() const { return mFrame; }
/**
* Translate the current origin by the specified (dx, dy). This
* creates a new local coordinate space relative to the current
* coordinate space.
*/
void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
/**
* Returns the current translation from local coordinate space to
* world coordinate space. This represents the accumulated calls to
* Translate().
*/
void GetTranslation(nscoord&amp; aX, nscoord&amp; aY) const { aX = mX; aY = mY; }
/**
* Returns the y-most of the bottommost band or 0 if there are no bands.
*
* @return PR_TRUE if there are bands and PR_FALSE if there are no bands
*/
PRBool YMost(nscoord&amp; aYMost) const;
/**
* Returns a band starting at the specified y-offset. The band data
* indicates which parts of the band are available, and which parts
* are unavailable
*
* The band data that is returned is in the coordinate space of the
* local coordinate system.
*
* The local coordinate space origin, the y-offset, and the max size
* describe a rectangle that's used to clip the underlying band of
* available space, i.e.
* {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
* coordinate space
*
* @param aYOffset the y-offset of where the band begins. The coordinate is
* relative to the upper-left corner of the local coordinate space
* @param aMaxSize the size to use to constrain the band data
* @param aBandData [in,out] used to return the list of trapezoids that
* describe the available space and the unavailable space
* @return NS_OK if successful and NS_ERROR_FAILURE if the band data is not
* not large enough. The 'count' member of the band data struct
* indicates how large the array of trapezoids needs to be
*/
nsresult GetBandData(nscoord aYOffset,
const nsSize&amp; aMaxSize,
nsBandData&amp; aBandData) const;
/**
* Add a rectangular region of unavailable space. The space is
* relative to the local coordinate system.
*
* The region is tagged with a frame
*
* @param aFrame the frame used to identify the region. Must not be NULL
* @param aUnavailableSpace the bounding rect of the unavailable space
* @return NS_OK if successful
* NS_ERROR_FAILURE if there is already a region tagged with aFrame
*/
nsresult AddRectRegion(nsIFrame* aFrame,
const nsRect&amp; aUnavailableSpace);
/**
* Resize the rectangular region associated with aFrame by the specified
* deltas. The height change always applies to the bottom edge or the existing
* rect. You specify whether the width change applies to the left or right edge
*
* Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
* tagged with aFrame
*/
enum AffectedEdge {LeftEdge, RightEdge};
nsresult ResizeRectRegion(nsIFrame* aFrame,
nscoord aDeltaWidth,
nscoord aDeltaHeight,
AffectedEdge aEdge = RightEdge);
/**
* Offset the region associated with aFrame by the specified amount.
*
* Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
* tagged with aFrame
*/
nsresult OffsetRegion(nsIFrame* aFrame, nscoord dx, nscoord dy);
/**
* Remove the region associated with aFrane.
*
* Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
* tagged with aFrame
*/
nsresult RemoveRegion(nsIFrame* aFrame);
/**
* Clears the list of regions representing the unavailable space.
*/
void ClearRegions();
/**
* Methods for dealing with the propagation of float damage during
* reflow.
*/
PRBool HasFloatDamage()
{
return !mFloatDamage.IsEmpty();
}
void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
{
mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
}
PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
{
return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
}
#ifdef DEBUG
/**
* Dump the state of the spacemanager out to a file
*/
nsresult List(FILE* out);
void SizeOf(nsISizeOfHandler* aHandler, uint32_t* aResult) const;
#endif
private:
// Structure that maintains information about the region associated
// with a particular frame
struct FrameInfo {
nsIFrame* const mFrame;
nsRect mRect; // rectangular region
FrameInfo* mNext;
FrameInfo(nsIFrame* aFrame, const nsRect&amp; aRect);
#ifdef NS_BUILD_REFCNT_LOGGING
~FrameInfo();
#endif
};
// Doubly linked list of band rects
struct BandRect : PRCListStr {
nscoord mLeft, mTop;
nscoord mRight, mBottom;
int32_t mNumFrames; // number of frames occupying this rect
union {
nsIFrame* mFrame; // single frame occupying the space
nsVoidArray* mFrames; // list of frames occupying the space
};
BandRect(nscoord aLeft, nscoord aTop,
nscoord aRight, nscoord aBottom,
nsIFrame*);
BandRect(nscoord aLeft, nscoord aTop,
nscoord aRight, nscoord aBottom,
nsVoidArray*);
~BandRect();
// List operations
BandRect* Next() const {return (BandRect*)PR_NEXT_LINK(this);}
BandRect* Prev() const {return (BandRect*)PR_PREV_LINK(this);}
void InsertBefore(BandRect* aBandRect) {PR_INSERT_BEFORE(aBandRect, this);}
void InsertAfter(BandRect* aBandRect) {PR_INSERT_AFTER(aBandRect, this);}
void Remove() {PR_REMOVE_LINK(this);}
// Split the band rect into two vertically, with this band rect becoming
// the top part, and a new band rect being allocated and returned for the
// bottom part
//
// Does not insert the new band rect into the linked list
BandRect* SplitVertically(nscoord aBottom);
// Split the band rect into two horizontally, with this band rect becoming
// the left part, and a new band rect being allocated and returned for the
// right part
//
// Does not insert the new band rect into the linked list
BandRect* SplitHorizontally(nscoord aRight);
// Accessor functions
PRBool IsOccupiedBy(const nsIFrame*) const;
void AddFrame(const nsIFrame*);
void RemoveFrame(const nsIFrame*);
PRBool HasSameFrameList(const BandRect* aBandRect) const;
int32_t Length() const;
};
// Circular linked list of band rects
struct BandList : BandRect {
BandList();
// Accessors
PRBool IsEmpty() const {return PR_CLIST_IS_EMPTY((PRCListStr*)this);}
BandRect* Head() const {return (BandRect*)PR_LIST_HEAD(this);}
BandRect* Tail() const {return (BandRect*)PR_LIST_TAIL(this);}
// Operations
void Append(BandRect* aBandRect) {PR_APPEND_LINK(aBandRect, this);}
// Remove and delete all the band rects in the list
void Clear();
};
FrameInfo* GetFrameInfoFor(nsIFrame* aFrame);
FrameInfo* CreateFrameInfo(nsIFrame* aFrame, const nsRect&amp; aRect);
void DestroyFrameInfo(FrameInfo*);
void ClearFrameInfo();
void ClearBandRects();
BandRect* GetNextBand(const BandRect* aBandRect) const;
void DivideBand(BandRect* aBand, nscoord aBottom);
PRBool CanJoinBands(BandRect* aBand, BandRect* aPrevBand);
PRBool JoinBands(BandRect* aBand, BandRect* aPrevBand);
void AddRectToBand(BandRect* aBand, BandRect* aBandRect);
void InsertBandRect(BandRect* aBandRect);
nsresult GetBandAvailableSpace(const BandRect* aBand,
nscoord aY,
const nsSize&amp; aMaxSize,
nsBandData&amp; aAvailableSpace) const;
nsIFrame* const mFrame; // frame associated with the space manager
nscoord mX, mY; // translation from local to global coordinate space
BandList mBandList; // header/sentinel for circular linked list of band rects
FrameInfo* mFrameInfoMap;
nsIntervalSet mFloatDamage;
static int32_t sCachedSpaceManagerCount;
static void* sCachedSpaceManagers[NS_SPACE_MANAGER_CACHE_SIZE];
nsSpaceManager(const nsSpaceManager&amp;); // no implementation
void operator=(const nsSpaceManager&amp;); // no implementation
};
</pre>
<h3>Public API</h3>
<h4>Life Cycle:</h4>
<p>
The Constructor requires a Presentation Shell, used for arena allocations
mostly, and a frame that this Space Manager is rooted on. &nbsp;The coordinate
space of this Space Manager is relative to the frame passed in to the constructor.
</p>
<pre> nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
~nsSpaceManager();
</pre>
<p>
Operators 'new' and 'delete' are overridden to support a recycler. &nbsp;Space
Manager instances come and go pretty frequently, and this recycler prevents
excessive heap allocations and the performance penalties associated with
it. The #define NS_SPACE_MANAGER_CACHE_SIZE is used to control the number
of Space Manager instances that can be present in the recycler, currently
4. &nbsp;If more than NS_SPACE_MANAGER_CACHE_SIZE are allocated at a time,
then standard allocation is used.
</p>
<pre>
void* operator new(size_t aSize);
void operator delete(void* aPtr, size_t aSize);
</pre>
<p>
A Static method is used to shutdown the Space Manager recycling. &nbsp;This
method deletes all of the Space Mangers inthe recycler,and prevents further
recycling. &nbsp;It is meant to be called only when the layout module is being
terminated.
</p>
<pre> static void Shutdown();
</pre>
<h4>Origin / Coordinate Space Translation</h4>
<pre> /**
* Translate the current origin by the specified (dx, dy). This
* creates a new local coordinate space relative to the current
* coordinate space.
*/
void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
/**
* Returns the current translation from local coordinate space to
* world coordinate space. This represents the accumulated calls to
* Translate().
*/
void GetTranslation(nscoord&amp; aX, nscoord&amp; aY) const { aX = mX; aY = mY; }
/**
* Returns the y-most of the bottommost band or 0 if there are no bands.
*
* @return PR_TRUE if there are bands and PR_FALSE if there are no bands
*/
PRBool YMost(nscoord&amp; aYMost) const;
</pre>
<h4>Region Management</h4>
<pre> /**
* Returns a band starting at the specified y-offset. The band data
* indicates which parts of the band are available, and which parts
* are unavailable
*
* The band data that is returned is in the coordinate space of the
* local coordinate system.
*
* The local coordinate space origin, the y-offset, and the max size
* describe a rectangle that's used to clip the underlying band of
* available space, i.e.
* {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
* coordinate space
*
* @param aYOffset the y-offset of where the band begins. The coordinate is
* relative to the upper-left corner of the local coordinate space
* @param aMaxSize the size to use to constrain the band data
* @param aBandData [in,out] used to return the list of trapezoids that
* describe the available space and the unavailable space
* @return NS_OK if successful and NS_ERROR_FAILURE if the band data is not
* not large enough. The 'count' member of the band data struct
* indicates how large the array of trapezoids needs to be
*/
nsresult GetBandData(nscoord aYOffset,
const nsSize&amp; aMaxSize,
nsBandData&amp; aBandData) const;
/**
* Add a rectangular region of unavailable space. The space is
* relative to the local coordinate system.
*
* The region is tagged with a frame
*
* @param aFrame the frame used to identify the region. Must not be NULL
* @param aUnavailableSpace the bounding rect of the unavailable space
* @return NS_OK if successful
* NS_ERROR_FAILURE if there is already a region tagged with aFrame
*/
nsresult AddRectRegion(nsIFrame* aFrame,
const nsRect&amp; aUnavailableSpace);
/**
* Resize the rectangular region associated with aFrame by the specified
* deltas. The height change always applies to the bottom edge or the existing
* rect. You specify whether the width change applies to the left or right edge
*
* Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
* tagged with aFrame
*/
enum AffectedEdge {LeftEdge, RightEdge};
nsresult ResizeRectRegion(nsIFrame* aFrame,
nscoord aDeltaWidth,
nscoord aDeltaHeight,
AffectedEdge aEdge = RightEdge);
/**
* Offset the region associated with aFrame by the specified amount.
*
* Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
* tagged with aFrame
*/
nsresult OffsetRegion(nsIFrame* aFrame, nscoord dx, nscoord dy);
/**
* Remove the region associated with aFrane.
*
* Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
* tagged with aFrame
*/
nsresult RemoveRegion(nsIFrame* aFrame);
/**
* Clears the list of regions representing the unavailable space.
*/
void ClearRegions();
</pre>
<h4>Float Impact</h4>
<pre> /**
* Methods for dealing with the propagation of float damage during
* reflow.
*/
PRBool HasFloatDamage()
{
return !mFloatDamage.IsEmpty();
}
void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
{
mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
}
PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
{
return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
}
</pre>
<h4>Debug Only Methods</h4>
<pre> /**
* Dump the state of the spacemanager out to a file
*/
nsresult List(FILE* out);
void SizeOf(nsISizeOfHandler* aHandler, uint32_t* aResult) const;
</pre>
<h4>Unused / Obsolete Methods</h4>
<pre> /*
* Get the frame that's associated with the space manager. This frame
* created the space manager, and the world coordinate space is
* relative to this frame.
*
* You can use QueryInterface() on this frame to get any additional
* interfaces.
*/
nsIFrame* GetFrame() const { return mFrame; }
</pre>
<h3>Implementation Notes</h3>
<h4></h4>
<h4>Algorithm 1: GetBandData</h4>
<p>
GetBandData is used to provide information to clients about what space if
available and unavailable in a band of space. &nbsp;The client provides a
vertical offset, the yOffset, that corresponds to the band that is of interest.
&nbsp;This will be the y offset of the frame that is being reflowed. &nbsp;The
caller also provides a collection of BandData objects (an array) and the
number of items that the collection can handle. &nbsp;If the collection is
too small, then an error is returned and the count is updated to indicate
the size required.
</p>
<p>
The algorithm to provide the band data is as follows:
</p>
<ul>
<li>Get a &nbsp;vertical offset in world coordinates (instead of frame-relative
coordinates) by adding the y-origin of the SpaceManager to the y offset passed
in</li>
<li>If the (adjusted) y value passed in is greater than the greatest band
being managed, then all space is available so a single trapezoid is returned,
marked as available and sized to the maximum size value (passed in).</li>
<li>If the (adjusted) y offset intersects a band, then gather the band
data:</li>
<ul>
<li>walk the internal bandData list from head to tail</li>
<li>for each band data entry, see if the top of the band is greater than
the (adjusted) y offset requested</li>
<li>if it is, then band is below the offset requested, so the area between
the band and the y offset is available - create a trapezoid with that region
and return it.</li>
<li>if the (adjusted) y offset is between the band top and bottom, then
get the available space for the band by calling GetBandAvailableSpace</li>
<li>otherwise, move to the next band</li>
</ul>
</ul>
<h5>GetBandAvailableSpace:</h5>
This method is called from GetBandData only. It walks all of the bands in
the space manager and determines which bands intersect with the band passed
in, and if within those bands there are regions that are available or occupied.
<ul>
<li>First, walk all of the bands until a band that is to the right of the
desired offset is located</li>
<li>Starting at that band, &nbsp;walk the remaining bands:</li>
<ul>
<li>if the current band is to the right of the requested band, then there
is available space.&nbsp;</li>
<ul>
<li>if there is more room in the bandData collection, then add a trapezoid
to the bandData collection such that it is marked as available and has a
rect that represents the space between the reference band tna dht band being
examined</li>
<li>if there is no more room in the BandData collection, estimate the
number of entries requires as the current count + twice the number of bands
below the reference band, plus two. &nbsp;Return an error code so the caller
can reallocate the collection and try again.</li>
</ul>
<li>check the size of the collection again, if there is no room left
then estimate the number of items requires as the current count + twice the
number of bands below the band in question plus one.&nbsp;</li>
<li>create a new trapezoid in the band collection that has a region corresponding
to the reference band rect, marked as occupied by either a single or multiple
frames.</li>
<li>move to the next band</li>
</ul>
<li>after walking all of the band data, se if we have reached the right
edge of the band.&nbsp;</li>
<ul>
<li>If not, then check for space in the band collection</li>
<ul>
<li>if there is no room left, then set the count to the current count
plus 1 and return an error.</li>
<li>otherwise, create another entry in the band collection, marked
as available, and with a rect corresponding to the area remainin in the band
(eg. from the right edge of the last band rect to the right edge of the band).</li>
</ul>
</ul>
</ul>
<h4>Algorithm 2: AddRectRegion</h4>
Clients call into this method to notify the Space Manager that a new frame
is occupying some space.
<ul>
<li>First, try to get frame info for the frame. If it is found, return
an error since the frame is already associated with a region in the Space
Manager.</li>
<li>Next, create a rect from the occupied space passed in by the caller,
transforming it first to world-coordinates by adding the Space Manager's
offset to the occupied space rect passed in.</li>
<li>Create a new Frame Info instance for the frame and rect, returning
an error if allocation fails.</li>
<li>Check if the occupied space rect (adjusted) is empty, if so, return
an error &nbsp;(<font color="#cc0000">NOTE: this could be done earlier, or
prevented by the caller</font>)</li>
<li>Allocate a new BandRect instance with the rect and frame as constructor
arguments, and insert it into the collection via InsertBandRect</li>
</ul>
<h5>InsertBandRect:</h5>
Internal method to insert a band rect into the BandList in the correct location.
There are several cases it has to handle, as specified in the source file
comments:
<pre>// When comparing a rect to a band there are seven cases to consider.
// 'R' is the rect and 'B' is the band.
//
// Case 1 Case 2 Case 3 Case 4
// ------ ------ ------ ------
// +-----+ +-----+ +-----+ +-----+
// | R | | R | +-----+ +-----+ | | | |
// +-----+ +-----+ | | | R | | B | | B |
// +-----+ | B | +-----+ | | +-----+ | |
// | | | | +-----+ | R | +-----+
// | B | +-----+ +-----+
// | |
// +-----+
//
//
//
// Case 5 Case 6 Case 7
// ------ ------ ------
// +-----+ +-----+ +-----+ +-----+
// | | | R | | B | | | +-----+
// | B | +-----+ +-----+ | R | | B |
// | | | | +-----+
// +-----+ +-----+
// +-----+
// | R |
// +-----+
//
</pre>
<ul>
<li>First, check for the easiest case, where there are no existing band
rects, or the band rect passed in is below the bottommost rect. In this case,
just append the band rect and return.</li>
<li>Starting at the head of the list of bandRects, check for intersection
with the rect passed in:</li>
<ul>
<li>case #1: the rect is totally above the current band rect, so insert
a new band rect before the current bandRect</li>
<li>cases #2 and #7: the rect is partially above the band rect, so it
is divided into two bandRects, one entirely above the band, and one containing
the remainder of the rect. &nbsp;Insert the part that is totally above the
bandRect before the current bandRect, as in case #1 above, and adjust the
other band rect to exclude the part already added.</li>
<li>case #5: the rect is totally below the current bandRect, so just
skip to the next band</li>
<li>case #3 and #4: rect is at least partially intersection with the
bandRect, so divide the current band into two parts, where the top part is
above the current rect. &nbsp;Move to the new band just created, which is
the next band.</li>
<li>case #6: the rect shares the bottom and height with the bandRect,
so just add the rect to the band.</li>
<li>case #4 and #7: create a new rect for the part that overlaps the
bandRect, and add it to the current bandRect (similar to case #6) and then
move on to the next band, removing that part from the rect passed in. &nbsp;If
no more bands, append the rect passed in to the end of the bandRect list.</li>
</ul>
</ul>
<i>This algorithm is pretty confusing - basically what needs to happen is
that rects and bands need to be divided up so that complicated cases like
#2, #4, and #7, are reduced to simpler cases where the rects is totally above,
below, or between a band rect. &nbsp;From the current implementation, it
might be worth verifying that the final result of the inserts is a correctly
ordered liest of bandRects (debug mode only).</i>
<h4>Algorithm 3: RemoveRegion</h4>
When a float is removed, the Space Manager is notified by a call to RemoveRegion,
passing in the frame that is being removed.
<ul>
<li>Get the FrameInfo for the frame passed in. If not found, an error is
returned.</li>
<li>If the rect for the frame is not empty, then visit each band in the
bandList:</li>
<ul>
<li>for each rect in the band:
</li>
</ul>
<ul>
<ul>
<li>if the bandRect is occupied by the frame, either remove the frame
from the bandRect (if there are other frames sharing it) and remember that
it was shared</li>
<li>otherwise simply remove the bandRect (no other frames share it).</li>
<li>if the bandRect was shared, then try to coalesce adjacent bandRects</li>
<ul>
<li>if the previous bandRect is directly next to the current bandRect,
and they have the same frame list, then make the current bandRect cover the
previous bandRect's full region (adjust the left edge to be that of the previous
bandRect) and remove the previous bandRect.</li>
</ul>
</ul>
</ul>
<ul>
<li>if the current band or prior band had a rect occupied byu the frame,
then try to join the two bands via JoinBands</li>
</ul>
<li>Finally, destroy the frameInfo for the frame.
</li>
</ul>
<br>
<hr width="100%" size="2">
<h2>Cross-Component Algorithms</h2>
<br>
<hr width="100%" size="2">
<h2>Tech Notes</h2>
<ul>
<li>
</li>
</ul>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -0,0 +1,245 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!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 with the 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 floats (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 Float Damage and is handled by the Block Frame, making use of the
Space Manager. When a float is incrementally reflowed, the Space
Manager is notified if the float's region has changed. If so, the
vertical space that has been affected (including both the float's old
region and the float's new region) is noted in the internal
nsIntervalSet as potential float 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 float 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 floats 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 floats 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, float impacts, and
where floats 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 Manager 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 Manager is saved off.</li>
<li>The new Space Manager 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: Float 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::RecoverFloats</i> and
<i>nsBlockReflowState::FlowAndPlaceFloat</i> (formerly this was done in nsBlockFrame::UpdateSpaceManager). &nbsp;<br>
<br>
The general algorightm in <i>nsBlockReflowState::RecoverFloats</i> is:<br>
<ul>
<li>For each line in the block, see if it has floated blocks</li>
<li>If floats are in the line, iterate over the floats and add each
one to the Space Manager via the AddRectRegion method. &nbsp;The actual rect
for the frame is cached in an nsFloatCache 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::FlowAndPlaceFloat</i> is:<br>
<ul>
<li>The region that the float currently occupies is recorded.</li>
<li>The band of available space is searched (with nsBlockReflowState::GetAvailableSpace);</li>
<li>The float frame that is get from the passed nsFloatCache argument is reflowed
and its rect is retrieved with GetRect;</li>
<li>The floats margins are added;</li>
<li>Check if the float can be placed in the acutal band: if not advance to the next band;</li>
<li>Check the float type and if it can be added to the space manager;</li>
<li>Align the float 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 float using <i>nsSpaceManager::AddRectRegion</i> </li>
<li>Compare the area that the float used to occupy with the area that it now occupies: if different,
record the vertically affected interval using <i>nsSpaceManager::IncludeInDamage</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 Manager. 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 float 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 Float Damage: detecting and handling float
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 PropagateFloatDamage method</li>
<li>The Space Manager is checked to see if there is any float damage</li>
<li>If there is, then the block frame asks the Space Manager if the
line in question intersects the float 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 floats before, but is not any longer</li>
<li>it was not impacted by floats befre, but is now</li>
<li><a name="block-line-impact"></a>
it is impacted by floats 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 float damage interval
set - this might be needed if the SpaceManager persists beyond a Reflow</li>
</ul>
<br>
<br>
</body>
</html>

View file

@ -0,0 +1,354 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Layout Overview</title>
<meta http-equiv="content-type"
content="text/html; charset=ISO-8859-1">
</head>
<body>
<h1>Layout System Overview</h1>
<br>
<h3>Layout's Job: Provide the Presentation</h3>
Layout is primarily concerned with providing a presentation to an HTML or
XML document. This presentation is typically formatted in accordance with
the requirements of the <a href="http://www.w3.org/TR/REC-CSS1">CSS1</a>
and <a href="http://www.w3.org/TR/REC-CSS2/">CSS2</a> specifications from
the W3C. Presentation formatting is also required to provide compatibility
with legacy browsers (Microsoft Internet Explorer and Netscape Navigator
4.x). The decision about when to apply CSS-specified formatting and when
to apply legacy formatting is controlled by the document's DOCTYPE specification.
These layout modes are referred to as 'Standards' and 'NavQuirks' modes. (DOCTYPE
and modes are explained in more detail <a
href="http://www.mozilla.org/quality/help/bugzilla-helper.html">here</a>).<br>
<br>
The presentation generally is constrained by the width of the window in which
the presentation is to be displayed, and a height that extends as far as
necessary. This is referred to as the Galley Mode presentation, and is what
one expects from a typical browser. Additionally, layout must support a paginated
presentation, where the width of the presentation is constrained by the dimensions
of the printed output (paper) and the height of each page is fixed. This
paged presentation presents several challenges not present in the galley
presentation, namely how to break up elements that are larger than a single
page, and how to handle changes to page dimensions.<br>
<br>
The original design of the Layout system allowed for multiple, possibly different,
presentations to be supported simultaneously from the same content model.
In other words, the same HTML or XML document could be viewed as a normal
galley presentation in a browser window, while simultaneously being presented
in a paged presentation to a printer, or even an aural presentation to a
speech-synthesizer. To date the only real use of this multiple presentation
ability is seen in printing, where multiple presentations are managed, all
connected to the same content model. (note: it is unclear if this is really
a benefit - it may have been better to use a copy of the content model for
each presentation, and to remove the complexity of managing separate presentations
- analysis is needed here). The idea of supporting a non-visual presentation
is interesting. Layout's support for aural presentations is undeveloped,
though conceptually, it is possible and supported by the architecture.<br>
<br>
<h3>How Layout Does its Job: Frames and Reflow</h3>
So, layout is concerned with providing a presentation, in galley or paged
mode. Given a content model, how does the layout system actually create the
presentation? Through the creation and management of frames. Frames are an
encapsulation of a region on the screen, a region that contains geometry
(size and location, stacking order). Generally frames correspond to the content
elements, though there is often a one-to-many correspondence between content
elements and frames. Layout creates frames for content based on either the
specific HTML rules for an element or based on the CSS display type of the
element. In the case of the HTML-specific elements, the frame types that
correspond to the element are hard-coded, but in the more general case where
the display type is needes, the layout system must determine that display
type by using the Style System. A content element is passed to the Style
System and a request is made to resolve the style for that element. This
causes the Style System to apply all style rules that correspond to the element
and results in a resolved Style Context - the style data specific to that
element. The Layout module looks at the 'display' field of the style context
to determine what kind of frame to create (block, inline, table, etc.). The
style context is associated with the frame via a reference because it is
needed for many other computations during the formatting of the frames.<br>
<br>
Once a frame is created for a content element, it must be formatted. We refer
to this as 'laying out' the frame, or as 'reflowing' the frame. Each frame
implements a Reflow method to compute its position and size, among other
things. For more details on the Reflow mechanism, see the Reflow Overview
document... &nbsp;The CSS formatting requirements present two distinct layout
models: 1) the in-flow model, where the geometry of an element is influenced
by the geometry of the elements that precede it, and 2) the positioned model,
where the geometry of an element is not influenced by the geometry of the
elements that precede it, or in any case, is influenced more locally. The
in-flow cased is considered the 'normal' case, and corresponds to normal
HTML formatting. The later case, called 'out of flow' puts the document author
in control of the layout, and the author must specify the locations and sizes
of all of the elements that are positioned. There is, of course, some complexity
involved with managing these two models simultanelusly...<br>
<br>
So far the general flow of layout looks like this:<br>
<br>
1) Obtain a document's content model<br>
2) Utilize the Style System to resolve the style of each element in the content
model<br>
3) Construct the frames that correspond to the content model, according to
the resolved style data.<br>
4) Perform the initial layout, or initial reflow, on the newly constructed
frame.<br>
<br>
This is pretty straight-forward, but is complicated somewhat by the notion
of <i>incrementalism</i>. One of the goals of the Layout system's design
is to create parts of the presentation as they become available, rather than
waiting for the entire document to be read, parsed, and then presented. This
is a major benefit for large documents because the user does not have to wait
for the 200th page of text to be read in before the first page can be displayed
- they can start reading something right away. So really, this sequence of
operations Resolve Style, Create Frame, Layout Frame, gets repeated many
times as the content becomes available. In the normal in-flow case this is
quite natural because the sequential addition of new content results in sequential
addition of new frames, and because everything is in-flow, the new frames
do not influence the geometry of the frames that have already been formatted.
When out-of-flow frames are present this is a more difficult problem, however.
Sometimes a content element comes in incrementally, and invalidates the formatting
of some of the frames that precede it, frame that have already been formatted.
In this case the Layout System has to detect that impact and reflow again
the impacted frames. This is referred to as an <i>incremental reflow</i>.<br>
<br>
<a name="DHTML_interaction"></a>Another responsibility of layout is to manage
dynamic changes to the content model, changes that occur after the document
has been loaded and (possibly) presented. These dynamic changes are caused
by manipulations of the content model via the&nbsp;<acronym
title="Document Object Model">DOM<acronym></acronym></acronym> (generally
through java script). When a content element is modified, added or removed,
Layout is notified. If content elements have been inserted, new frames are
created and formatted (and impacts to other frames are managed by performing
further incremental reflows). If content is removed, the corresponding frames
are destroyed (again, impacts to other elements are managed). If a content
element is modified, layout must determine if the chage influences the formatting
of that or other elements' presentations, and must then reformat, or re-reflow,
the impacted elements. In all cases, the determination of the impact is critical
to avoid either the problem of not updating impacted elements, thus presenting
an invalid presentation, or updating too much of the presentation and thus
doing too much work, potentially causing performance problems.<br>
<br>
One very special case of dynamic content manipulation is the HTML Editor.
Layout is used to implement both a full-blown WYSIWYG HTML editor, and a single
and multi-line text entry control. In both cases, the content is manipulated
by the user (via the DOM) and the resulting visual impacts must be shown as
quickly as possible, without disconcerting flicker or other artifacts that
might bother the user. Consider a text entry field: the user types text into
a form on the web. As the user types a new character it is inserted into
the content model. This causes layout to be notified that a new piece of
content has been entered, which causes Layout to create a new frame and format
it. This must happen very fast, so the user's typing is not delayed. In the
case of the WYSIWYG HTML editor, the user expects that the modifications
they make to the document will apear immediately, not seconds later. This
is especially critical when the user is typing into the document: it would
be quite unusable if typing a character at the end of a document in the HTML
editor caused the entire document to be reformated - it would be too slow,
at least on low-end machines. Thus the HTML editor and text controls put
considerable performance requirements on the layout system's handling of dynamic
content manipulation.<br>
<h3>The Fundamentals of Frames: Block and Line</h3>
There are many types of frames that are designed to model various formatting
requirements of different HTML and XML elements. CSS2 defines several (block,
inline, list-item, marker, run-in, compact, and various table types) and
the standard HTML form controls require their own special frame types to
be formatted as expected. The most essential frame types are Block and Inline,
and these correspond to the most important Layout concepts, the Block and
Line.<br>
<br>
A block is a rectangular region that is composed of one or more lines. A
line is a single row of text or other presentational elements. All layout
happens in the context of a block, and all of the contents of a block are
formatted into lines within that block. As the width of a block is changed,
the contents of the lines must be reformatted. consider for example a large
paragraph of text sitting in paragraph:<br>
<br>
<pre>&lt;p&gt;<br> We need documentation for users, web developers, and developers working
on Mozilla. If you write your own code, document it. Much of the
existing code &lt;b&gt;isn&#8217;t very well documented&lt;/b&gt;. In the process of figuring
things out, try and document your discoveries.
If you&#8217;d like to contribute, let us know.<br>&lt;/p&gt;</pre>
There is one block that corresponds to the &lt;p&gt; element, and then a number
of lines of text that correspond to the text. As the width of the block changes
(due to the window being resized, for example) the length of the lines within
it changes, and thus more or less text appears on each line. The block is
responsible for managing the lines. Note that lines may contain only inline
elements, whereas block may contain both inline elements and other blocks.<br>
<h3>Other Layout Models: XUL</h3>
In addition to managing CSS-defined formatting, the layout system provides
a way to integrate other layout schemes into the presentation. Currently
layout supports the formatting of XUL elements, which utilize a constraint-based
layout language. The Box is introduced into the layout system's frame model
via an adapter (BoxToBlockAdapter) that translates the normal layout model
into the box formatting model. Conceptually, this could be used to introduce
other layout systems, but it might be worth noting that there was no specific
facility designed into the layout system to accommodate this. Layout deals
with frames, but as long as the layout system being considered has no need
to influence presentational elements from other layout systems, it can be
adapted using a frame-based adapter, ala XUL.<br>
<br>
<h2>Core Classes</h2>
At the highest level, the layout system is a group of classes that manages
the presentation within a fixed width and either unlimited height (galley
presentation) or discrete page heights (paged presentation). Digging just
a tiny bit deeper into the system we find that the complexity (and interest)
mushrooms very rapidly. The idea of formatting text and graphics to fit within
a given screen area sounds simple, but the interaction of in-flow and out-of-flow
elements, the considerations of incremental page rendering, and the performance
concerns of dynamic content changes makes for a system that has a lot of
work to do, and a lot of data to manage. Here are the high-level classes
that make up the layout system. Of course this is a small percentage of the
total clases in layout (see the detailed design documents for the details
on all of the classes, in the context of their actual role).<br>
<h3>Presentation Shell / Presentation Context</h3>
Together the presentation shell and the presentation context provide the
root of the current presentation. The original design provided for a single
Presentation Shell to manage multiple Presentation Contexts, to allow a single
shell to handle multiple presentations. It is unclear if this is really possible,
however, and in general it is assumed that there is a one-to-one correspondence
between a presentation shell and a presentation context. The two classes
should probably be folded into one, or the distinction between them formalized
and utilized in the code. The Presentation Shell currently owns a controlling
reference to the Presentation Context. Further references to the Presentation
Shell and Presentation Context will be made by using the term Presentation
Shell.<br>
<br>
The Presentation Shell is the root of the presentation, and as such it owns
and manges a lot of layout objects that are used to create and maintain a
presentation (<font color="#990000">note that the DocumentViewer is the owner
of the Presentation Shell, and in some cases the creator of the objects
used by the Presentation Shell to manage the presentation. More details
of the Document Viewer are needed here...</font>). The Presentation Shell,
or PresShell, is first and foremost the owner of the formatting objects,
the frames. Management of the frames is facilitated by the Frame Manager,
an instance of which the PresShell owns. Additionally, the PresShell provides
a specialized storage heap for frames, called an Arena, that is used to make
allocation and deallocation of frames faster and less likely to fragment
the global heap. <br>
<br>
The Presentation Shell also owns the root of the Style System, the Style
Set. In many cases the Presentation Shell provides pass-through methods to
the Style Set, and generally uses the Style Set to do style resolution and
Style Sheet management.<br>
<br>
One of the critical aspects of the Presentation Shell is the handling of
frame formatting, or reflow. The Presentation Shell owns and maintains a
Reflow Queue where requests for reflow are held until it is time to perform
a reflow, and then pulled out and executed.<br>
<br>
It is also important to see the Presentation Shell as an observer of many
kinds of events in the system. For example, the Presentation Shell receives
notifications of document load events, which are used to trigger updates
to the formatting of the frames in some cases. The Presentation Shell also
receives notifications about changes in cursor and focus states, whereby
the selection and caret updates can be made visible.<br>
<br>
There are dozens of other data objects managed by the Presentation Shell
and Presentation Context, all necessary for the internal implementation.
These data members and their roles will be discussed in the Presentation
Shell design documents. For this overview, the Frames, Style Set, and Reflow
Queue are the most important high-level parts of the Presentation Shell.<br>
<h3>Frame Manager</h3>
The Frame Manager is used to, well, manage frames. Frames are basic formatting
objects used in layout, and the Frame Manager is responsible for making frames
available to clients. There are several collections of frames maintained
by the Frame Manager. The most basic is a list of all of the frames starting
at the root frame. Clients generally do not want to incur the expense of
traversing all of the frames from the root to find the frame they are interested
in, so the Frame Manager provides some other mappings based on the needs of
the clients.<br>
<br>
The most crucial mapping is the Primary Frame Map. This collection provides
access to a frame that is designated as the primary frame for a piece of
content. When a frame is created for a piece of content, it may be the 'primary
frame' for that content element (content elements that require multiple
frames have primary and secondary frames; only the primary frame is mapped).
The Frame Manager is then instructed to store the mapping from a content
element to the primary frame. This mapping facilitates updates to frames
that result in changes to content (see <a href="#DHTML_interaction">discussion
above</a>).<br>
<br>
Another important mapping maintained by the Frame Manager is that of the
undisplayed content. When a content element is defined as having no display
(via the CSS property 'display:none') it is noted by a special entry in the
undisplayed map. This is important because no frame is generated for these
elements yet changes to their style values and to the content elements still
need to be handled by layout, in case their display state changes from 'none'
to something else. The Undisplayed Map keeps track of all content and style
data for elements that currently have no frames. (<font color="#990000">note:
the original architecture of the layout system included the creation of frames
for elements with no display. This changed somewhere along the line, but
there is no indication of why the change was made. Presumably it is more
time and space-efficient to prevent frame creation for elements with no display.)</font><br>
<br>
The Frame Manager also maintains a list of Forms and Form Controls, as <i>content
nodes</i>. This is presumably related to the fact that layout is responsible
for form submission, but this is a design flaw that is being corrected by
moving form submission into the content world. These collections of Forms
and Form Controls should be removed eventually.<br>
<br>
<h3>CSS Frame Constructor</h3>
The Frame Constructor is responsible for resolving style values for content
elements and creating the appropriate frames corresponding to that element.
In addition to managing the creation of frames, the Frame Constructor is
responsible for managing changes to the frames. Frame Construction is generally
achieved by the use of stateless methods, but in some cases there is the
need to provide context to frames created as children of a container. The
Frame Manager uses the Frame Constructor State class to manage the important
information about the container of a frame being created (<font
color="#990000">and lots of other state-stuff too - need to describe more
fully</font>).<br>
<h3>Frame</h3>
The Frame is the most fundamental layout object. The class nsFrame is the
base class for all frames, and it inherits from the base class nsIFrame (note:
nsIFrame is NOT an interface, it is an abstract base class. It was once an
interface but was changed to be a base class when the Style System was modified
- the name was not changed to reflect that it is not an interface). The Frame
provides generic functionality that can be used by subclasses but cannot
itself be instantiated.<br>
<br>
nsFrame:<br>
The Frame provides a mechanism to navigate to a parent frame as well as child
frames. All frames have a parent except for the root frame. The Frame is
able to provide a reference to its parent and to its children upon request.
The basic data that all frames maintain include: a rectangle describing the
dimensions of the frame, a pointer to the content that the frame is representing,
the style context representing all of the stylistic data corresponding to
the frame, a parent frame pointer, a sibling frame pointer, and a series
of state bits.<br>
<br>
Frames are chained primarily by the sibling links. Given a frame, one can
walk the sibling of that frame, and can also navigate back up to the parent
frame. Specializations of the frame also allow for the management of child
frames; this functionality is provided by the Container Frame.<br>
<br>
Container Frames:<br>
The Container Frame is a specialization of the base frame class that introduces
the ability to manage a list of child frames. All frames that need to manage
child frames (e.g. frames that are not themselves leaf frames) derive from
Container Frame.<br>
<br>
<br>
<br>
<h3>Block Frame<br>
</h3>
<h3>Reflow State</h3>
<h3>Reflow Metrics<br>
</h3>
<h3>Space Manager<br>
</h3>
<h3>StyleSet</h3>
<h3>StyleContext</h3>
<br>
<br>
<hr width="100%" size="2"><br>
<b>Document History:<br>
</b>
<ul>
<li>05/20/2002 - Marc Attinasi: &nbsp;created, wrote highest level introduction
to general layout concepts, links to relevant specs and existing documents.<br>
</li>
</ul>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

View file

@ -0,0 +1,479 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<meta name="author" content="Marc Attinasi"><title>Adding a new style property - layout cookbook</title></head>
<body>
<h1>Adding a new style property</h1>
<blockquote>
<h4>Document history:</h4>
<ul>
<li>03/21/2002: Marc Attinasi (attinasi@netscape.com) created document
/ implementing -moz-force-broken-image-icon for bug <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=58646">
58646</a></li>
<li>
6/18/2002: David Baron (dbaron@dbaron.org): corrected support
for 'inherit' and 'initial' (didn't test with code, though),
and explained what the final boolean in CheckPropertyData is for.
</li>
<li>
11/09/2002: Christopher Aillon (caillon@returnzero.com): updated
nsCSSPropList.h macro description and added information about
nsIDOMCSS2Properties.idl.
</li>
</ul>
<p>
<b>NOTE</b>: This document is still missing a few pieces. I need to
add information on adding to <code>nsComputedDOMStyle</code>.
</p>
</blockquote>
<h2>Overview</h2>
When a new style property is needed there are many places in the code that
need to be updated. This document outlines the procedure used to add a new
property, in this case the property is a proprietary one called '-moz-force-broken-image-icons'
and is used as a way for a stylesheet to force broken image icons to be displayed.
This is all being done in the context of <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=58646">
bug 58646</a>.
<h2>Analysis</h2>
<p>Up front you have to decide some things about the new property:</p>
<p><b>Questions:</b></p>
<ol>
<li>Is the property proprietary or specified by the CSS standard?</li>
<li>Is the property inherited?</li>
<li>What types of values can the property have?</li>
<li>Does it logically fit with other existing properties?</li>
<li>What is the impact to the layout of a page if that property changes?</li>
<li>What do you want to name it?</li>
</ol>
<p><b>Answers:</b></p>
<ol>
<li>In our specific case, we want a property that is used internally,
so it is a proprietary property.</li>
<li>The property is to be used for images, which are leaf elements, so
there is no need to inherit it.</li>
<li>The property is used simply to force a broken image to be represented
by an icon, so it only supports the values '0' and '1' as numerics. </li>
<li>It is hard to see how this property fits logically in with other
properties, but if we stretch our imaginations we could say that it is a
sort of UI property.</li>
<li>If this property changes, the image frame has to be recreated. This
is because the decision about whether to display the icon or not will impact
the decision to replace the image frame with an inline text frame for the
ALT text, so if the ALT text inline is already made, there is no image frame
left around to reflow or otherwise modify.</li>
<li>Finally, the name will be '-moz-force-broken-image-icons' - that
should be pretty self-describing (by convention we start proprietary property
names with '-moz-').</li>
</ol>
<h2>Implementation</h2>
<p>There are several places that need to be educated about a new style property.
They are:
</p>
<ul>
<li><a href="#CSSPropList">CSS Property Names and Hint Tables</a>: the new
property name must be made formally know to the system</li>
<li><a href="#CSSDeclaration">CSS Declaration</a>: the declaration must be
able to hold the property and its value(s)</li>
<li><a href="#Parser">CSS Parser</a>: the parser must be able to parse the
property name, validate the values, and provide a declaration for the property
and value</li>
<li><a href="#StyleContext">Style Context</a>: the StyleContext must be able
to hold the resolved value of the property, and provide a means to retrieve the
property value. Additionally, the StyleContext has to know what kind of impact a
change to this property causes.</li>
<li><a href="#RuleNode">Rule Nodes</a>: the RuleNodes need to know how the
property is inherited and how it is shared by other elements.</li>
<li><a href="#DOM">DOM</a>: Your style should be accessible from the DOM so
users may dynamically set/get its property value.</li>
<li><a href="#Layout">Layout</a>: layout has to know what to do with the
property, in other words, the meaning of the property.</li>
</ul>
<h3><a name="CSSPropList">CSS Property Name / Constants / Hints</a></h3>
<p>
First, add the new name to the property list in <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsCSSPropList.h">
nsCSSPropList.h</a>
 Insert the property in the list alphabetically, using the existing
property names as a template. The format of the entry you will create is:
</p>
<pre>CSS_PROP(-moz-force-broken-image-icons, force_broken_image_icons, MozForceBrokenImageIcons, nsChangeHint_ReconstructFrame) // bug 58646</pre>
<p>The first value is the formal property name, in other words the property
name as it is seen by the CSS parser.<br>
The second value is the name of the property as it will appear internally.<br>
The third value is the name of the DOM property used to access your style.<br>
The last value indicates what must change when the value of the property
changes. It should be an
<a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsChangeHint.h">nsChangeHint</a>.</p>
<p>If you need to introduce new constants for the values of the property, they
must be added to <a href="http://lxr.mozilla.org/seamonkey/source/layout/base/public/nsStyleConsts.h">
nsStyleConsts.h</a>
and to the appropriate keyword tables in <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/src/nsCSSProps.cpp">
nsCSSProps.cpp</a>
(note: this cookbook does not do this since the new property does not require
any new keywords for the property values).
<h3><a name="CSSDeclaration">CSS Declaration</a></h3>
Changes will need to be made to the structs and classes defined in <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSDeclaration.h">
nsCSSDeclaration.h </a>
and <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSDeclaration.cpp">
nsCSSDeclaration.cpp</a>
<br>
<br>
First, find the declaration of the struct that will hold the new property
value (in the header file). For this example it is the struct <b>nsCSSUserInterface</b>
. Modify the struct declaration to include a new data member for the new
property, of the type CSSValue. Next, open the implementation file (the cpp)
and modify the struct's constructors. <br>
<br>
Next, the <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSDeclaration.cpp#1410">
AppendValue</a>
method must be updated to support your new property. The CSSParser will
call this to build up a declaration. Find the portion of that method that
deals with the other properties in the struct that you are adding your property
to (or create a new section if you are creating a new style struct). For
this example we will find the 'UserInterface' section and add our new property
<a href="#AppendValueCase">there</a>
.<br>
<pre> // nsCSSUserInterface
case eCSSProperty_user_input:
case eCSSProperty_user_modify:
case eCSSProperty_user_select:
case eCSSProperty_key_equivalent:
case eCSSProperty_user_focus:
case eCSSProperty_resizer:
case eCSSProperty_cursor:
case eCSSProperty_force_broken_image_icons: {
CSS_ENSURE(UserInterface) {
switch (aProperty) {
case eCSSProperty_user_input: theUserInterface-&gt;mUserInput = aValue; break;
case eCSSProperty_user_modify: theUserInterface-&gt;mUserModify = aValue; break;
case eCSSProperty_user_select: theUserInterface-&gt;mUserSelect = aValue; break;
case eCSSProperty_key_equivalent:
CSS_ENSURE_DATA(theUserInterface-&gt;mKeyEquivalent, nsCSSValueList) {
theUserInterface-&gt;mKeyEquivalent-&gt;mValue = aValue;
CSS_IF_DELETE(theUserInterface-&gt;mKeyEquivalent-&gt;mNext);
}
break;
case eCSSProperty_user_focus: theUserInterface-&gt;mUserFocus = aValue; break;
case eCSSProperty_resizer: theUserInterface-&gt;mResizer = aValue; break;
case eCSSProperty_cursor:
CSS_ENSURE_DATA(theUserInterface-&gt;mCursor, nsCSSValueList) {
theUserInterface-&gt;mCursor-&gt;mValue = aValue;
CSS_IF_DELETE(theUserInterface-&gt;mCursor-&gt;mNext);
}
break;
<b> <a name="AppendValueCase"></a>case eCSSProperty_force_broken_image_icons: theUserInterface-&gt;mForceBrokenImageIcon = aValue; break;
</b>
CSS_BOGUS_DEFAULT; // make compiler happy
}
}
break;
}
</pre>
The GetValue method must be similarly <a href="#GetValueCase">modified</a>
:<br>
<pre> // nsCSSUserInterface
case eCSSProperty_user_input:
case eCSSProperty_user_modify:
case eCSSProperty_user_select:
case eCSSProperty_key_equivalent:
case eCSSProperty_user_focus:
case eCSSProperty_resizer:
case eCSSProperty_cursor:
case eCSSProperty_force_broken_image_icons: {
CSS_VARONSTACK_GET(UserInterface);
if (nullptr != theUserInterface) {
switch (aProperty) {
case eCSSProperty_user_input: aValue = theUserInterface-&gt;mUserInput; break;
case eCSSProperty_user_modify: aValue = theUserInterface-&gt;mUserModify; break;
case eCSSProperty_user_select: aValue = theUserInterface-&gt;mUserSelect; break;
case eCSSProperty_key_equivalent:
if (nullptr != theUserInterface-&gt;mKeyEquivalent) {
aValue = theUserInterface-&gt;mKeyEquivalent-&gt;mValue;
}
break;
case eCSSProperty_user_focus: aValue = theUserInterface-&gt;mUserFocus; break;
case eCSSProperty_resizer: aValue = theUserInterface-&gt;mResizer; break;
case eCSSProperty_cursor:
if (nullptr != theUserInterface-&gt;mCursor) {
aValue = theUserInterface-&gt;mCursor-&gt;mValue;
}
break;
<b> <a name="GetValueCase"></a>case eCSSProperty_force_broken_image_icons: aValue = theUserInterface-&gt;mForceBrokenImageIcons; break;
</b>
CSS_BOGUS_DEFAULT; // make compiler happy
}
}
else {
aValue.Reset();
}
break;
}
</pre>
Finally <a href="#ListCase">modify </a>
the 'List' method to output the property value.<br>
<pre>void nsCSSUserInterface::List(FILE* out, int32_t aIndent) const
{
for (int32_t index = aIndent; --index &gt;= 0; ) fputs(" ", out);
nsAutoString buffer;
mUserInput.AppendToString(buffer, eCSSProperty_user_input);
mUserModify.AppendToString(buffer, eCSSProperty_user_modify);
mUserSelect.AppendToString(buffer, eCSSProperty_user_select);
nsCSSValueList* keyEquiv = mKeyEquivalent;
while (nullptr != keyEquiv) {
keyEquiv-&gt;mValue.AppendToString(buffer, eCSSProperty_key_equivalent);
keyEquiv= keyEquiv-&gt;mNext;
}
mUserFocus.AppendToString(buffer, eCSSProperty_user_focus);
mResizer.AppendToString(buffer, eCSSProperty_resizer);
nsCSSValueList* cursor = mCursor;
while (nullptr != cursor) {
cursor-&gt;mValue.AppendToString(buffer, eCSSProperty_cursor);
cursor = cursor-&gt;mNext;
}
<b> <a name="ListCase"></a>mForceBrokenImageIcon.AppendToString(buffer,eCSSProperty_force_broken_image_icons);</b>
fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
}
</pre>
<h3><a name="Parser">CSS Parser</a></h3>
Next, the CSSParser must be educated about this new property so that it can
read in the formal declarations and build up the internal declarations that
will be used to build the rules. If you are adding a simple property that
takes a single value, you simply add your new property to the ParseSingleProperty
method. If a more complex parsing is required you will have to write a new
method to handle it, modeling it off of one of the existing parsing helper
methods (see <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#4151">
ParseBackground</a>
, for and example). We are just adding a simple single-value property here.<br>
<br>
Open nsCSSParser.cpp and look for the method <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#3580">
ParseSingleProperty</a>
. This method is responsible for calling the relevant helper routine to parse
the value(s). Find an existing property that is similar to the property you
are adding. For our example we are adding a property that takes a numeric
value so we will model it after the 'height' property and call ParsePositiveVariant.
Add a new case for the new property and call the appropriate parser-helper
and make a call to ParseVariant passing the <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#2754">
variant flag</a>
that makes sense for your property. In our case<br>
<br>
<pre>  case eCSSProperty_force_broken_image_icons:</pre>
<pre>    return ParsePositiveVariant(aErrorCode, aValue, VARIANT_INTEGER, nullptr);</pre>
This will parse the value as a positive integer value, which is what we want.<br>
<br>
<h3><a name="StyleContext">Style Context</a></h3>
Having implemented support for the new property in the CSS Parser and CSS
Declaration classes in the content module, it is now time to provide support
for the new property in layout. The Style Context must be given a new data
member corresponding to the declaration's new data member, so the computed
value can be held for the layout objects to use.<br>
<br>
First look into <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsStyleStruct.h">
nsStyleStruct.h</a>
to see the existing style strucs. Find the one that you want to store the
data on. In this example, we want to put it on the nsStyleUserInterface struct,
however there is also a class nsStyleUIReset that holds the non-inherited
values, so we will use that one (remember, our property is not inherited).
Add a <a href="#StyleContextMember">data member</a>
to hold the value:
<pre>struct nsStyleUIReset {
nsStyleUIReset(void);
nsStyleUIReset(const nsStyleUIReset&amp; aOther);
~nsStyleUIReset(void);
NS_DEFINE_STATIC_STYLESTRUCTID_ACCESSOR(eStyleStruct_UIReset)
void* operator new(size_t sz, nsPresContext* aContext) {
return aContext->AllocateFromShell(sz);
}
void Destroy(nsPresContext* aContext) {
this-&gt;~nsStyleUIReset();
aContext-&gt;FreeToShell(sizeof(nsStyleUIReset), this);
};
int32_t CalcDifference(const nsStyleUIReset&amp; aOther) const;
uint8_t mUserSelect; // [reset] (selection-style)
PRUnichar mKeyEquivalent; // [reset] XXX what type should this be?
uint8_t mResizer; // [reset]
<b><a name="StyleContextMember"></a>uint8_t mForceBrokenImageIcon; // [reset] (0 if not forcing, otherwise forcing)</b>
};
</pre>
In the implementation file <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/src/nsStyleStruct.cpp">
nsStyleContext.cpp </a>
add the new data member to the constructors of the style struct and the CalcDifference
method, which must return the correct style-change hint when a change to
your new property is detected. The constructor changes are obvious, but here
is the CalcDifference change for our example:<br>
<pre>int32_t nsStyleUIReset::CalcDifference(const nsStyleUIReset&amp; aOther) const
{
<b> if (mForceBrokenImageIcon == aOther.mForceBrokenImageIcon) {</b>
if (mResizer == aOther.mResizer) {
if (mUserSelect == aOther.mUserSelect) {
if (mKeyEquivalent == aOther.mKeyEquivalent) {
return NS_STYLE_HINT_NONE;
}
return NS_STYLE_HINT_CONTENT;
}
return NS_STYLE_HINT_VISUAL;
}
return NS_STYLE_HINT_VISUAL;
}
<b>return nsChangeHint_ReconstructFrame;
</b>}
</pre>
<h3>CSSStyleRule</h3>
The nsCSSStyleRule must be updated to manage mapping the declaration to the
style struct. In the file <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSStyleRule.cpp">
nsCSSStyleRule.cpp</a>
, locate the Declaration mapping function corresponding to the style struct
you have added your property to. For example, we <a href="http://bugzilla.mozilla.org/MapUIForDeclChange">
update </a>
MapUIForDeclaration:<br>
<pre>static nsresult
MapUIForDeclaration(nsCSSDeclaration* aDecl, const nsStyleStructID&amp; aID, nsCSSUserInterface&amp; aUI)
{
if (!aDecl)
return NS_OK; // The rule must have a declaration.
nsCSSUserInterface* ourUI = (nsCSSUserInterface*)aDecl-&gt;GetData(kCSSUserInterfaceSID);
if (!ourUI)
return NS_OK; // We don't have any rules for UI.
if (aID == eStyleStruct_UserInterface) {
if (aUI.mUserFocus.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserFocus.GetUnit() != eCSSUnit_Null)
aUI.mUserFocus = ourUI-&gt;mUserFocus;
if (aUI.mUserInput.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserInput.GetUnit() != eCSSUnit_Null)
aUI.mUserInput = ourUI-&gt;mUserInput;
if (aUI.mUserModify.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserModify.GetUnit() != eCSSUnit_Null)
aUI.mUserModify = ourUI-&gt;mUserModify;
if (!aUI.mCursor &amp;&amp; ourUI-&gt;mCursor)
aUI.mCursor = ourUI-&gt;mCursor;
}
else if (aID == eStyleStruct_UIReset) {
if (aUI.mUserSelect.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserSelect.GetUnit() != eCSSUnit_Null)
aUI.mUserSelect = ourUI-&gt;mUserSelect;
if (!aUI.mKeyEquivalent &amp;&amp; ourUI-&gt;mKeyEquivalent)
aUI.mKeyEquivalent = ourUI-&gt;mKeyEquivalent;
if (aUI.mResizer.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mResizer.GetUnit() != eCSSUnit_Null)
aUI.mResizer = ourUI-&gt;mResizer;
<b>
<a name="MapUIForDeclChange"></a>if (aUI.mForceBrokenImageIcon.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mForceBrokenImageIcon.GetUnit() == eCSSUnit_Integer)
aUI.mForceBrokenImageIcon = ourUI-&gt;mForceBrokenImageIcon;</b>
}
return NS_OK;
}
</pre>
<h3><a name="RuleNode">Rule Node</a></h3>
Now we have to update the RuleNode code to know about the new property. First,
locate the PropertyCheckData array for the data that you added the new property
to. For this example, we add the following:<br>
<pre>static const PropertyCheckData UIResetCheckProperties[] = {
CHECKDATA_PROP(nsCSSUserInterface, mUserSelect, CHECKDATA_VALUE, PR_FALSE),
CHECKDATA_PROP(nsCSSUserInterface, mResizer, CHECKDATA_VALUE, PR_FALSE),
CHECKDATA_PROP(nsCSSUserInterface, mKeyEquivalent, CHECKDATA_VALUELIST, PR_FALSE)
<b>CHECKDATA_PROP(nsCSSUserInterface, mForceBrokenImageIcon, CHECKDATA_VALUE, PR_FALSE)</b>
};
</pre>
The first two arguments correspond to the structure and data member from
the CSSDeclaration, the third is the data type, the fourth indicates
whether it is a coord value that uses an explicit inherit value on the
style data struct that must be computed by layout.<br>
<br>
Next, we have to make sure the ComputeXXX method for the structure the property
was added to is updated to mange the new value. In this example we need to
modify the nsRuleNode::ComputeUIResetData method to handle the CSS Declaration
to the style struct:<br>
<pre> ...
// resizer: auto, none, enum, inherit
if (eCSSUnit_Enumerated == uiData.mResizer.GetUnit()) {
ui-&gt;mResizer = uiData.mResizer.GetIntValue();
}
else if (eCSSUnit_Auto == uiData.mResizer.GetUnit()) {
ui-&gt;mResizer = NS_STYLE_RESIZER_AUTO;
}
else if (eCSSUnit_None == uiData.mResizer.GetUnit()) {
ui-&gt;mResizer = NS_STYLE_RESIZER_NONE;
}
else if (eCSSUnit_Inherit == uiData.mResizer.GetUnit()) {
inherited = PR_TRUE;
ui-&gt;mResizer = parentUI-&gt;mResizer;
}
<b>// force-broken-image-icons: integer, inherit, initial
if (eCSSUnit_Integer == uiData.mForceBrokenImageIcons.GetUnit()) {
ui-&gt;mForceBrokenImageIcons = uiData.mForceBrokenImageIcons.GetIntValue();
} else if (eCSSUnit_Inherit == uiData.mForceBrokenImageIcons.GetUnit()) {
inherited = PR_TRUE;
ui-&gt;mForceBrokenImageIcons = parentUI-&gt;mForceBrokenImageIcons;
} else if (eCSSUnit_Initial == uiData.mForceBrokenImageIcons.GetUnit()) {
ui-&gt;mForceBrokenImageIcons = 0;
}</b>
if (inherited)
// We inherited, and therefore can't be cached in the rule node. We have to be put right on the
// style context.
aContext-&gt;SetStyle(eStyleStruct_UIReset, *ui);
else {
// We were fully specified and can therefore be cached right on the rule node.
if (!aHighestNode-&gt;mStyleData.mResetData)
aHighestNode-&gt;mStyleData.mResetData = new (mPresContext) nsResetStyleData;
aHighestNode-&gt;mStyleData.mResetData-&gt;mUIData = ui;
// Propagate the bit down.
PropagateDependentBit(NS_STYLE_INHERIT_UI_RESET, aHighestNode);
}
...
</pre>
<h3><a name="DOM">DOM</a></h3>
Users in scripts, or anywhere outside of layout/ or content/ may need to access
the new property. This is done using the CSS OM, specifically
<code>nsIDOMCSSStyleDeclaration</code> and <code>CSS2Properties</code>.
By the magic of C++ pre-processing, the
CSS2Properties bits will be implemented automatically when you
<a href="#CSSPropList">add your property</a> to <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsCSSPropList.h">
nsCSSPropList.h</a>.
<h3><a name="Layout">Layout</a></h3>
OK, finally the style system is supporting the new property. It is time to
actually make use of it now.<br>
<br>
In layout, retrieve the styleStruct that has the new property from the frame's
style context. Access the new property and get its value. It is that simple.
For this example, it looks like this, in nsImageFrame:<br>
<pre> PRBool forceIcon = PR_FALSE;
if (StyleUIReset()-&gt;mForceBrokenImageIcon) {
forceIcon = PR_TRUE;
}
</pre>
Create some testcases with style rules that use the new property, make sure
it is being parsed correctly. Test it in an external stylesheet and in inline
style. Test that it is inherited correctly, or not inherited as appropriate
to your property. Update this document with any further details, or correcting
any errors.<br>
</body></html>

116
layout/doc/dd-template.html Normal file
View file

@ -0,0 +1,116 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!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>Layout Detailed Design Template</title>
<meta name="author" content="Marc Attinasi (attinasi@netscape.com)">
</head>
<body>
<h1><font color="#cc0000">Gecko Layout Detailed Design Document Template</font></h1>
[Use this template to start your detailed design. Replace items in square
brackets with the appropriate text for your component, class or system. &nbsp;Keep
in mind that this is just a general template intended for most designs.
Your specific design may require different organization or topics - the
goal is to provide detailed information about the software to the reader.]<br>
<br>
<h1>[Component / Class Name] Detailed Design</h1>
<h2>Overview</h2>
[Introduce the scope of this design document: what is being documented here.
Provide a reference back to the High Level design(s) that correspond.]<br>
<hr width="100%" size="2">
<h2>[Class / Component A]</h2>
[Briefly refresh the reader with the purpose of the class or component.
Provide enough information to make accessible the following sections on the
public API, private methods and members, and algorithms. Bring up and tricky
or otherwise interesting relationships that will be detailed.]<br>
<br>
<h3>Public API</h3>
[Show the public API for the component, as IDL, C++ header file, or as a
pseudo-code description. &nbsp;If using a source file, the comments in the
source file should cover most of the detail needed. If they do not, then add
that detail there. &nbsp;See the Overview document for more details on the
scope of information that should be presented.]<br>
<h3>Protected API</h3>
[If there is a protected API, list the methods and members and indicate
the responsibilities of the callers with respect o calling the base class,
enforcing base class invariants, etc.]<br>
<br>
<h3>Implementation Notes</h3>
[The nasty details of the implementation get exposed here. This section
can be broken down into subsections as necessary, and should include details
of particularly important algorithms, performance characteristics or constraints,
memory usage, tricky ownership issues, and anything else that would make understanding
the implementation easier for the reader.]<br>
<h4>Algorithms</h4>
<h5>[Interesting Algorithm 1: The internally maintained sorted list]</h5>
[explain the nature of the algorithm, the reason it was chosen, the types
of input it is expected to operate on, etc. Annotated pseudo-code is a good
idea here, but actual code is often too detailed to b of much use by itself.
It the actual code is sufficient to understand it, then this subsection is
probably not needed.]<br>
<h5>[Interesting Algorithm 2: Handling overflow of the input buffer]</h5>
[your description here]<br>
<h4></h4>
<hr width="100%" size="2">
<h2>[Class / Component B]</h2>
[Repeat the structure for the next class or component.]<br>
<br>
<hr width="100%" size="2">
<h2>Cross-Component Algorithms</h2>
[specify the details of algorithms that cross a single component. refer
to each component, describe the flow of control, the responsibilities of each
component along the way, the error handling, the state-management if any,
and the expected results for a given input. Generally each of these algorithms
gets its own subsection.]<br>
<h3>[Turning a byte-stream into a fully parsed token-tree]</h3>
[Detailed description, pesudo-code, state transitions, etc.]<br>
<h3>[Managing updates to the document]</h3>
[Detailed description, pesudo-code, state transitions, etc.]<br>
<br>
<hr width="100%" size="2">
<h2>Tech Notes</h2>
[This section contains links to tech notes related to the implementations
covered in this design. &nbsp;Tech Notes tend to be extremely specific, often
recipes for how to do something or how to fix a class of defects. &nbsp;If
the tech note is more general, it may be a good idea to move it into the Detailed
design itself.]<br>
<ul>
<li>[<a href="link%20to%20tech%20note">Debugging buffer overflows</a>
]</li>
<li>[<a href="link%20to%20tech%20note">Adding new element or attribute
types</a>
]</li>
<li>[<a href="link%20to%20tech%20note">How To detect and fix problems
with the alignment of elements</a>
]</li>
<li>[<a href="link%20to%20tech%20note">Fix for Bug 666: ownership of tokens
was mistakenly transferred</a>
]</li>
</ul>
<br>
</body>
</html>

245
layout/doc/debugtable.html Normal file
View file

@ -0,0 +1,245 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body {font-family:arial}
.log {background-color:silver; color:blue}
pre.log {display:table-cell}
</style>
<title>Debugging facilities in HTML-Table code</title>
</head>
<body>
<h1>Debugging facilities in HTML-table code</h1>
<h2>Reflow</h2>
<p>The most efficient tool to claim that html-table code is the victim and not the source of layout bugs is a <a href="http://lxr.mozilla.org/seamonkey/source/layout/doc/frame_reflow_debug.html">frame reflow debug log</a>. Look there especially how the maxElementsize (MES) and desired size are propagated.
<h2>Block Reflow</h2>
<p>
Another way to debug the reflow process is implemented inside <a href="http://lxr.mozilla.org/seamonkey/source/layout/html/base/src/nsBlockFrame.cpp">nsBlockFrame.cpp</a>. It can be invoked by<p>
<code>set GECKO_BLOCK_DEBUG_FLAGS=reflow</code>
<p>
The available options are:
<ul>
<li><code>reflow</code>
<li> <code>really-noisy-reflow</code>
<li><code>max-element-size</code>
<li><code> space-manager</code>
<li><code>verify-lines</code>
<li><code>damage-repair</code>
<li><code>lame-paint-metrics</code>
<li><code>lame-reflow-metrics</code>
<li><code>disable-resize-opt</code>
</ul>
<p>
These options can be combined with a comma separated list
Messages generated by the <code>reflow</code> switch:
<ul>
<li><code> Block(div)(1)@00BE5AC4: reflowing dirty lines computedWidth=9000 computedHeight=1500</code>
<ul>
<li> this message is generated inside of <br>
<code>nsresult nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)</code>
<li> it first shows the Block ID and Address
<li>and then the computed width and Height from the HTMLReflowState.
</ul>
</ul>
<h2>DEBUG_TABLE_STRATEGY</h2>
<p>
The table layout strategy can be visualized by defining in the <a href="http://lxr.mozilla.org/seamonkey/source/layout/html/table/src/Makefile.in">makefiles</a> the constant DEBUG_TABLE_STRATEGY.
If one takes for instance the following table
<table cellspacing="10"><tr><th>rendering</th><th>code</th></tr>
<tr valign="top"><td valign="top" style="padding-top:10px">
<table border width="300">
<colgroup>
<col>
<col width="50%">
<col width="1*">
<col>
</colgroup>
<tr>
<td style="width:80px">cell 1</td>
<td>cell 2</td>
<td>cell 3</td>
<td>cell 4</td>
</tr>
</table>
</td>
<td valign="top"><pre class="log">
&lt;table border width="300"&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col width="50%"&gt;
&lt;col width="1*"&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tr&gt;
&lt;td style="width:80px"&gt;cell 1&lt;/td&gt;
&lt;td&gt;cell 2&lt;/td&gt;
&lt;td&gt;cell 3&lt;/td&gt;
&lt;td&gt;cell 4&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
</pre>
</td>
</tr>
</table>
<p>
it will produce the following log at the entrance of <code>AssignNonPctColWidths</code>:
<p>
<table class="log"><tr><td>
<pre>
AssignNonPctColWidths en max=4500 count=0
***START TABLE DUMP***
mColWidths=-1 -1 -1 -1
col frame cache -&gt;
0=00B93138 1=00B931F0 2=024DD728 3=024DD780
**START COL DUMP** colIndex=0 isAnonymous=0 constraint=0
widths=-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 **END COL DUMP**
**START COL DUMP** colIndex=1 isAnonymous=0 constraint=0
widths=-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 **END COL DUMP**
**START COL DUMP** colIndex=2 isAnonymous=0 constraint=0
widths=-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 **END COL DUMP**
**START COL DUMP** colIndex=3 isAnonymous=0 constraint=0
widths=-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 **END COL DUMP**
***END TABLE DUMP***
</pre>
</td></tr></table>
<p>
The <span class="log">en</span> stands for entrance (<span class="log">ex</span> for leaving a routine). The first line of the data dump shows that no width has yet been assigned to the columns <span class="log">mColWidths=-1 -1 -1 -1</span>, <code>-1</code> stands for:
<pre>
#define WIDTH_NOT_SET -1
</pre>
<p>
This is followed by a reference to the column frame pointers:
<p>
<pre class="log">
col frame cache -&gt;
0=00B93138 1=00B931F0 2=024DD728 3=024DD780
</pre>
<p>
This is followed by the information which width has been set for each column. The index of the column, whether it is anonymous and what kind of constrained has been applied<span class="log">colIndex=0 isAnonymous=0 constraint=0</span>. The following constraint types are known:
<p>
<pre>
eNoConstraint = 0,
ePixelConstraint = 1, // pixel width
ePercentConstraint = 2, // percent width
eProportionConstraint = 3, // 1*, 2*, etc. cols attribute assigns 1*
e0ProportionConstraint = 4 // 0*, means to force to min width
</pre>
<p>
After this follows the width information for each column:
<p>
<pre class="log">
widths=-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
</pre>
<p>
The table code knows ten different width's:
<pre>
#define NUM_WIDTHS 10
#define NUM_MAJOR_WIDTHS 3 // MIN, DES, FIX
#define MIN_CON 0 // minimum width required of the content + padding
#define DES_CON 1 // desired width of the content + padding
#define FIX 2 // fixed width either from the content or cell, col, etc. + padding
#define MIN_ADJ 3 // minimum width + padding due to col spans
#define DES_ADJ 4 // desired width + padding due to col spans
#define FIX_ADJ 5 // fixed width + padding due to col spans
#define PCT 6 // percent width of cell or col
#define PCT_ADJ 7 // percent width of cell or col from percent colspan
#define MIN_PRO 8 // desired width due to proportional &lt;col&gt;s or cols attribute
#define FINAL 9 // width after the table has been balanced, considering all of the others
</pre>
<p>
In the last log snippet none of these width's has been set.
Leaving AssignNonPctColWidths shows that already to all columns a width of 360 twips has been assigned
<pre class="log">
AssignNonPctColWidths ex
***START TABLE DUMP***
mColWidths=360 360 360 360
col frame cache -&gt;
0=00B93138 1=00B931F0 2=024DD728 3=024DD780
**START COL DUMP** colIndex=0 isAnonymous=0 constraint=0
widths=360 540 1230 -1 -1 -1 -1 -1 -1 360 **END COL DUMP**
**START COL DUMP** colIndex=1 isAnonymous=0 constraint=0
widths=360 540 -1 -1 -1 -1 -1 -1 -1 360 **END COL DUMP**
**START COL DUMP** colIndex=2 isAnonymous=0 constraint=3
widths=360 540 -1 -1 -1 -1 -1 -1 540 360 **END COL DUMP**
**START COL DUMP** colIndex=3 isAnonymous=0 constraint=0
widths=360 540 -1 -1 -1 -1 -1 -1 -1 360 **END COL DUMP**
***END TABLE DUMP***
</pre>
<p>
The first column has already the minimum content width, the table column can't shrink below that, the desired content width of <span class="log">540</span> twips, that's the space to layout <code>cell 1</code> without wrapping the text and the <span class="log">1230</span> which correspond to the <code>style="width:80px"</code> at the first cell. At this step the final size is <span class="log">360</span> twips.
<p>
<table cellpadding="8">
<tr>
<th> MIN_CON</th><th>DES_CON</th><th>FIX</th><th>MIN_ADJ</th><th>DES_ADJ</th><th>FIX_ADJ</th><th>PCT</th><th> PCT_ADJ</th><th> MIN_PRO</th><th>FINAL</th>
</tr>
<tr align="center">
<td>360</td><td> 540</td><td> 1230 </td><td>-1</td><td> -1 </td><td>-1</td><td> -1</td><td> -1</td><td> -1</td><td> 360</td></tr></table>
<p>
There was no change till the entrance of <code>BalanceColumnWidths
</code>
<p>
<pre class="log">
BalanceColumnWidths en count=1
***START TABLE DUMP***
mColWidths=360 360 360 360
col frame cache -&gt;
0=00B93138 1=00B931F0 2=024DD728 3=024DD780
**START COL DUMP** colIndex=0 isAnonymous=0 constraint=0
widths=360 540 1230 -1 -1 -1 -1 -1 -1 360 **END COL DUMP**
**START COL DUMP** colIndex=1 isAnonymous=0 constraint=0
widths=360 540 -1 -1 -1 -1 -1 -1 -1 360 **END COL DUMP**
**START COL DUMP** colIndex=2 isAnonymous=0 constraint=3
widths=360 540 -1 -1 -1 -1 -1 -1 540 360 **END COL DUMP**
**START COL DUMP** colIndex=3 isAnonymous=0 constraint=0
widths=360 540 -1 -1 -1 -1 -1 -1 -1 360 **END COL DUMP**
***END TABLE DUMP***
</pre>
<p>
But at the end the final distribution between the columns has been reached.
<p>
<pre class="log">
BalanceColumnWidths ex
***START TABLE DUMP***
mColWidths=1230 2160 465 465
col frame cache -&gt;
0=00B93138 1=00B931F0 2=024DD728 3=024DD780
**START COL DUMP** colIndex=0 isAnonymous=0 constraint=0
widths=360 540 1230 -1 -1 -1 -1 -1 -1 1230 **END COL DUMP**
**START COL DUMP** colIndex=1 isAnonymous=0 constraint=0
widths=360 540 -1 -1 -1 -1 2160 -1 -1 2160 **END COL DUMP**
**START COL DUMP** colIndex=2 isAnonymous=0 constraint=3
widths=360 540 -1 -1 -1 -1 -1 -1 540 465 **END COL DUMP**
**START COL DUMP** colIndex=3 isAnonymous=0 constraint=0
widths=360 540 -1 -1 -1 -1 -1 -1 -1 465 **END COL DUMP**
***END TABLE DUMP***
</pre>
<p>
The column dump is implemented in <code>nsTableColFrame.cpp</code> in the routine:
<code>void nsTableColFrame::Dump(int32_t aIndent)</code>.
<h2>DEBUG_TABLE_REFLOW_TIMING</h2>
<p>needs to be written
<hr>
<p style="text-align:right">author: Bernd Mielke <br>2002-06-05</p>
</body>
</html>

View file

@ -0,0 +1,224 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<style type="text/css">
body {font-family:arial}
.log {background-color:silver; color:blue}
</style>
<title> Debugging Frame Reflow</title>
</head>
<body>
<h1>Debugging Frame Reflow HowTo</h1>
<h2>General Overview</h2>
<p> The frame reflow can be logged with the debug capabilities implemented in <a href="http://lxr.mozilla.org/seamonkey/source/layout/html/base/src/nsFrame.cpp"><code>nsFrame.cpp</code></a>.
It provides the following information for each frame at the
start of its reflow
<ul>
<li>reflow reason
<li>available width, available height
<li>computed width, computed height
<li>the previous and the next frame in flow
<li>and a count number.
</ul>
<p>When the frame's reflow is finished the following information is displayed :</p>
<ul>
<li>reflow metric (desired) width, height
<li>max. element size (MES) width
<li>maximum Width
<li>frame status
<li>overflow area
</ul>
<h2>Getting the log</h2>
<ul>
<li>Make sure that your build is a <b>debug</b> build.
<li>Create a text file (for instance <code>reflow_rules.txt</code>).
<li>Enter this line in the text file <pre>* 1</pre>
<li>Save the text file in the <code>%DIST%</code> directory
<li>Go to the <code>%DIST%</code> directory
<li>enter from command line: <code>set GECKO_DISPLAY_REFLOW_RULES_FILE=reflow_rules.txt</code>
<li> Run <code>viewer &gt; logfile.txt</code> and load your testcase. The
logfile will contain all the promised information.
</ul>
<h2>Log File analyis</h2>
<p>The logfile for a simple table like</p>
<pre>
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table width="100"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;foo&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p> will create the following log:</p>
<table class="log"><tr><td>
<pre>
VP 00B97C30 r=0 a=9180,4470 c=9180,4470 cnt=856
scroll 00B97EE0 r=0 a=9180,4470 c=9180,4470 cnt=857
scroll 00B97EE0 r=0 a=9180,4470 c=9180,4470 cnt=858
canvas 00B97C6C r=0 a=9180,UC c=9180,4470 cnt=859
area 02D7AFE4 r=0 a=9180,UC c=9180,UC cnt=860
text 02D7B150 r=0 a=9180,UC c=UC,UC cnt=861
text 02D7B150 d=0,0
block 02D7B210 r=0 a=9180,UC c=8940,UC cnt=862
block 02D7B210 d=8940,0
area 02D7AFE4 d=9180,120
canvas 00B97C6C d=9180,4470
scroll 00B97EE0 d=9180,4470
scroll 00B97EE0 d=9180,4470
VP 00B97C30 d=9180,4470
VP 00B97C30 r=1 a=9180,4470 c=9180,4470 cnt=863
scroll 00B97EE0 r=1 a=9180,4470 c=9180,4470 cnt=864
scroll 00B97EE0 r=1 a=9180,4470 c=9180,4470 cnt=865
canvas 00B97C6C r=1 a=9180,UC c=9180,4470 cnt=866
area 02D7AFE4 r=1 a=9180,UC c=9180,UC cnt=867
block 02D7B210 r=1 a=9180,UC c=8940,UC cnt=868
text 02D7B3F8 r=0 a=8940,UC c=UC,UC cnt=869
text 02D7B3F8 d=0,0
tblW 02D7B5F0 r=0 a=8940,UC c=0,0 cnt=870
tbl 02D7B7EC r=0 a=8940,UC c=1500,UC cnt=871
rowG 00B984A4 r=0 a=UC,UC c=UC,UC cnt=872
row 02D7BAF8 r=0 a=UC,UC c=UC,UC cnt=873
cell 02D7BC98 r=0 a=UC,UC c=UC,UC cnt=874
block 02D7BCF8 r=0 a=UC,UC c=UC,UC cnt=875
text 02D7BE84 r=0 a=UC,UC c=UC,UC cnt=876
text 02D7BE84 d=300,285 me=300
block 02D7BCF8 d=300,300 me=300
cell 02D7BC98 d=330,330 me=330
row 02D7BAF8 d=UC,330
rowG 00B984A4 d=UC,330
colG 02D7BFB0 r=0 a=UC,UC c=UC,UC cnt=877
col 02D7C0D8 r=0 a=0,0 c=1500,UC cnt=878
col 02D7C0D8 d=0,0
colG 02D7BFB0 d=0,0
rowG 00B984A4 r=2 a=1500,UC c=1500,UC cnt=879
row 02D7BAF8 r=2 a=1500,UC c=1500,UC cnt=880
cell 02D7BC98 r=2 a=1440,UC c=1410,UC cnt=881
block 02D7BCF8 r=2 a=1410,UC c=1410,UC cnt=882
block 02D7BCF8 d=1410,300
cell 02D7BC98 d=1440,330
row 02D7BAF8 d=1500,330
rowG 00B984A4 d=1500,330
colG 02D7BFB0 r=2 a=1500,UC c=1500,UC cnt=883
col 02D7C0D8 r=0 a=0,0 c=1500,UC cnt=884
col 02D7C0D8 d=0,0
colG 02D7BFB0 d=0,0
tbl 02D7B7EC d=1500,390
tblW 02D7B5F0 d=1500,390
text 02D7C130 r=0 a=8940,UC c=UC,UC cnt=885
text 02D7C130 d=0,0
block 02D7B210 d=8940,390
area 02D7AFE4 d=9180,630
canvas 00B97C6C d=9180,4470
scroll 00B97EE0 d=9180,4470
scroll 00B97EE0 d=9180,4470
VP 00B97C30 d=9180,4470
</pre>
</td></tr></table>
<p>
The first line shows the reflow of the viewport (<code class="log">VP</code>). This viewport has the address <code class="log">00B97C30</code>. It is the initial reflow: <code class="log">r=0</code>. Other reflow reasons are: </p>
<table>
<tr><td>1</td><td>incremental reflow</td></tr>
<tr><td>2</td><td>resize reflow</td></tr>
<tr><td>3</td><td>style change reflow</td></tr>
<tr><td>4</td><td>dirty reflow.</td></tr>
</table>
<p>The available width is 9180 twips. The available height is 4470 twips (<code class="log">a=9180,4470</code>). The computed width is 9180 twips. The computed height is 4470 twips (<code class="log">c=9180,4470</code>). The line count is 856 (<code class="log">cnt=856</code>).
<p>
Below this is a line that reads:<p><code class="log">tblW 02D7B5F0 r=0 a=8940,UC c=0,0 cnt=870</code></p><p> Here the <code class="log">UC</code> shows that on initial reflow the available height for the table wrapper frame is unconstrained.
<p>
The table cell requires its children to compute the MES. It is reported back from the block as:
<p><code class="log">block 02D7BCF8 d=300,300 me=300</code></p>
<p>The block max. element size is 300 twips.
<p> The second table reflow is started at
<p><code class="log">rowG 00B984A4 r=2 a=1500,UC c=1500,UC cnt=879</code></p>
<p>where the previous information is used.
The block has been required to compute the max. element size only once and it reports now:
<p> <code class="log">block 02D7BCF8 d=1410,300</code></p>
<p>The block shows the same address as the previous one.
<p>Frames with children that overflow the parent will return <code>PR_TRUE</code> from <code>HasOverflowRect()</code>. For these frames
the overflow area is displayed as <code class="log">block 025ED8F0 d=8940,1020 o=(0,0) 9180 x 1020</code>. The overflow area is specified as (x,y) origin and width x height.
<p> The reflow finishes at the same level where it started.
<h2>Advanced reflow debugging</h2>
<p>The previously described technique dumps the data for every frame. Sometimes the log is clearer if only the main frames are shown.
The entries in the reflow log can be controlled on a frame level. For instance adding <code>text 0</code> to the rules in <code>reflow_rules.txt</code> would hide the text entries from the reflow. The display of the following frames can be turned on by adding a line with the frame name and <code>1</code> or turned off by adding a line with the frame name and <code>0</code>:</p>
<table cellspacing="5">
<tr><th style="text-align:left">short name</th><th style="text-align:left">layout tag</th></tr>
<tr><td>area</td><td>area</td></tr>
<tr><td>block</td><td>block</td></tr>
<tr><td>br</td><td>br</td></tr>
<tr><td>bullet</td><td>bullet</td></tr>
<tr><td>button</td><td>gfxButtonControl</td></tr>
<tr><td>hr</td><td>hr</td></tr>
<tr><td>frameI</td><td>htmlFrameInner</td></tr>
<tr><td>frameO</td><td>htmlFrameOuter</td></tr>
<tr><td>img</td><td>image</td></tr>
<tr><td>inline</td><td>inline</td></tr>
<tr><td>letter</td><td>letter</td></tr>
<tr><td>line</td><td>line</td></tr>
<tr><td>select</td><td>select</td></tr>
<tr><td>obj</td><td>object</td></tr>
<tr><td>page</td><td>page</td></tr>
<tr><td>place</td><td>placeholder</td></tr>
<tr><td>canvas</td><td>canvas</td></tr>
<tr><td>root</td><td>root</td></tr>
<tr><td>scroll</td><td>scroll</td></tr>
<tr><td>caption</td><td>tableCaption</td></tr>
<tr><td>cell</td><td>tableCell</td></tr>
<tr><td>bcCell</td><td>bcTableCell</td></tr>
<tr><td>col</td><td>tableCol</td></tr>
<tr><td>colG</td><td>tableColGroup</td></tr>
<tr><td> tbl</td><td>table</td></tr>
<tr><td>tblW</td><td>tableWrapper</td></tr>
<tr><td>rowG</td><td>tableRowGroup</td></tr>
<tr><td>row</td><td>tableRow</td></tr>
<tr><td>textCtl</td><td>textInput</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>VP</td><td>viewport</td></tr>
</table>
<p>Once the problem is reduced to a single frame level, placing a breakpoint at <code>DisplayReflowEnterPrint</code> in <a href="http://lxr.mozilla.org/seamonkey/source/layout/html/base/src/nsFrame.cpp"><code>nsFrame.cpp</code></a> is a very efficient way to step through
the reflow tree.
<h2>Other reflow debug options</h2>
<h3>GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS</h3>
<p>
Setting this option via <code>set GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS = 1</code> enables a verification for each coordinate value that the coordinates are aligned at pixel boundaries.
<table class="log"><tr><td>
<pre>
row 0268A594 r=0 a=UC,UC c=UC,20 cnt=870
VALUE 20 is not a whole pixel
cell 0268A6C0 r=0 a=UC,UC c=UC,15 cnt=871
block 0268A764 r=0 a=UC,UC c=UC,UC cnt=872
block 0268A764 d=0,0 me=0
cell 0268A6C0 d=0,0 me=0
row 0268A594 d=UC,20
VALUE 20 is not a whole pixel
rowG 0268A02C d=UC,695
VALUE 695 is not a whole pixel</pre>
</td></tr></table>
<p>
While unaligned values at the entrance of a frame reflow can be ignored, when they appear at the exit of a routine this can cause display errors like stray lines. OS2 is very vulnerable to pixel alignement errors as text is drawn on pixel boundaries.
<h3>GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES</h3>
<p>
Setting this option via <code>set GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES = 1</code> will cause an advance of the indent even for frames which are blocked via the reflow rules file.
</body>
</html>

View file

@ -0,0 +1,109 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!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>Layout High Level design Template</title>
<meta name="author" content="Marc Attinasi (attinasi@netscape.com)">
</head>
<body>
<h1><font color="#cc0000">Gecko Layout High Level Design Document Template</font></h1>
[Use this template to start your high level design. Replace items in square
brackets with the appropriate text for your component, class or system. &nbsp;Keep
in mind that this is just a general template intended for most designs.
Your specific design may require different organization or topics - the
goal is to provide high-level information about the software to the reader.]<br>
<br>
<h1>[Component/Class/System Name] High Level Design</h1>
<br>
<h2>Overview</h2>
[Provide a descriptive overview of the component, class, or system that
you are documenting. Describe what the system is supposed to do, where it
is in the overall system, who the clients are, how it is expected to perform,
and any other information that is important to convey to somebody interested
in understanding what the documented system is all about.]<br>
<br>
<h2>Data Model</h2>
[This section describes the classes or components that make up the data
model for the system being documented. It can include a graphical representation
of the classes and their relationships to each other (derivation, aggregation,
ownership, usership, etc.). No implementation details are to be included
here, but general relationships and inter-relationships should be shown and
briefly described. The reader should be able to understand the players in
the system, and the extent to which those players interact with or are related
to the other players.]<br>
<h4>Class/Component Diagram</h4>
<blockquote>
<div align="Left"><img src="ExampleClassDiagram.jpg" alt="Example Class Diagram" width="324" height="270" title="Example Class Diagram">
<br>
</div>
</blockquote>
<ul>
<li>[Class/<a href="Link%20To%20Component%20A%20Detailed%20Design">
Component A</a>
]: This class is used to...</li>
<li>[Class/<a href="Link%20To%20Component%20B%20Detailed%20Design">
Component B</a>
]: This class works with Class A to...<br>
</li>
</ul>
<br>
<h2>Use Case</h2>
[Use Cases describe interactions between specific instances of the objects
or components described in the Data Model. &nbsp;There will generally be
use cases for each &nbsp; interesting runtime interaction between the objects
in the system. An extremely simple system will have at least one use case
describing the behavior of the simple system in action, but most systems
have many use cases corresponding to the any things that the system does.
&nbsp;The reader should be able to find the use case (or cases) that correspond
to the situation they are interested in understanding, and they should be
able to learn how data flows through the system, what objects are involved,
how &nbsp;object and data life-cycles are managed (e.g. where allocations
ad deallocations occur, and who maintains ownership). This section makes up
the bulk of the document. It touches on implementations and algorithms, but
rather than describing them in detail, it stays high-level and links to the
detailed designs that correspond.]<br>
<h4>[Use Case 1: Component is Created]</h4>
The component is created by a client with...<br>
&nbsp;[Image could go here if it were interesting enough...]<br>
<br>
<h4>[Use Case 2: Component is Destroyed]</h4>
When the client is finished with the instance they created (or were given
ownership of) the destroy it by calling...<br>
<br>
<h4>[Use Case 3: Component is used to find all invalid links on the page]</h4>
Descriptive text of how the component is invoked goes here. The other
components that it uses to carry out its task are shown, and the general
flow of data is documented.<br>
[Picture of the component instance with annotations showing data flow,
ownership, etc. goes here]<br>
<h2>State Transitions</h2>
[Where appropriate, the discrete states of a system should be enumerated
and the transitions between the states defined. &nbsp;Not all systems require
full state transition diagrams, but most systems have at least a handful
of interesting states, and at least a small number of interesting stimuli
that cause transitions from one state to another. &nbsp; Of course, classes
or components that are not stateful have no need for this section.]<br>
<br>
<br>
</body>
</html>

126
layout/doc/index.html Normal file
View file

@ -0,0 +1,126 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Layout Documentation Index Page</title>
<meta http-equiv="content-type"
content="text/html; charset=ISO-8859-1">
<style>
/* colors for status of documents */
*.ood { color: red !important; }
*.good { color: black !important; }
*.wip { color: blue !important; }
*.unassigned { color: green !important; }
/* inherit the colors into the links */
p > a { color: inherit; }
</style>
</head>
<body>
<h1>Layout Technical Documentation: Primary Index</h1>
<p class="wip">Document Status: Work In Progress (attinasi)
<p>The goal of this document is to provide extensive links to documentation
on the Gecko Layout components and classes. There are two sections containing
links to the documents, and there is overlap between these sections by
design. First, there is a '<a href="#TopicIndex">Topics</a>' section,
where documentation is listed by generic topics, more or less free-form
and ad-hoc. Second, there is a '<a href="#ClasscomponentIndex">Class and
Component</a>' section, where specific classes and components are listed,
mapping naturally to the source code. All documents should be indexed in
both sections, so pick the index that corresponds to what you are thinking
about. A <a href="#HowTo">Tech Notes section</a> is also included to help
contributors find information on small topics and issues, including simple
'How To' cookbooks.
<p><blockquote>
<i>For information about the structure of layout documents, see the <a
href="http://lxr.mozilla.org/seamonkey/source/layout/doc/overview.html">Layout
Documentation Overview</a>&nbsp; and the Layout DocumentationTemplates
(<a
href="http://lxr.mozilla.org/seamonkey/source/layout/doc/hld-template.html">High
Level Design Template</a> / <a
href="http://lxr.mozilla.org/seamonkey/source/layout/doc/dd-template.html">Detailed
Design Template</a>).
</i>
</blockquote>
<hr width="100%" size="2">
<div align="left"
style="border: 1px solid blue; margin: auto; width: 65%;"><big><b>Legend</b></big>
<ul>
<li class="good">Black: complete and believed to be up to date (class='good')</li>
<li class="wip">Blue: incomplete or work in progress (class='wip')</li>
<li class="ood">Red: out of date or innacurate (class='ood', bug should be filed and bug number / link noted)</li>
<li class="unassigned">Green: unassigned work</li>
</li>
</ul>
</div>
<h2><a name="TopicIndex"></a>Topic Indices</h2>
<div style="border: 1px solid black; margin: 1em; padding: 1em;">
<p class="wip">What is Layout? The High Level Layout Overview (attinasi)
<p class="wip">Debugging Layout (bernd)
<p class="unassigned">How Reflow works
<p class="wip">Tables balancing (karnaze)
<p class="wip">Table Borders collapsing (karnaze)
<p class="wip">Block in Inline situations (kin)
<p class="good"><a href="http://lxr.mozilla.org/seamonkey/source/layout/doc/HLD-SpaceManager.html">Managing Floats</a>
<p class="unassigned">Text Measurement and Text Breaking
<p class="unassigned">Image loading and display
<p class="unassigned">Margin Collapsing
<p class="unassigned">Scrolling Blocks
<p class="unassigned">Box and Block interactions
<p class="wip">Printing and Print Preview (rods)
<p class="unassigned">Plugins: the object frame and related layout classes
</div>
<h2><a name="ClasscomponentIndex"></a>Class and Component Indices</h2>
<div style="border: 1px solid black; margin: 1em; padding: 1em;">
<p class="unassigned">Presentation Shell and Context: High Level / Detailed
<p class="unassigned">Frames and the Frame Manager: High Level / Detailed
<p class="good">Reflow: <a href="http://www.mozilla.org/newlayout/doc/reflow.html">High Level (waterson)</a> / <span class="unassigned">Detailed</span>
<p class="unassigned">Block and Line layout: High Level / Detailed
<p class="unassigned">TextFrame - Text Measurement and Line Breaking: High Level / Detailed
<p class="wip">PageSequenceFrame and PageFrame: High Level / Detailed (rods)
<p class="unassigned">Object Frame: High Level / Detailed
<p class="good">Space Manager:
<a href="http://lxr.mozilla.org/seamonkey/source/layout/doc/HLD-SpaceManager.html">High Level</a> /
<a href="http://lxr.mozilla.org/seamonkey/source/layout/doc/DD-SpaceManager.html">Detailed</a>
<p class="wip">Layout Debug Plugin: high Level / Detailed (dcone)
</div>
<h2><a name="HowTo"></a>How To / Tech Notes</h2>
<div style="border: 1px solid black; margin: 1em; padding: 1em;">
<p class="good"><a href="http://lxr.mozilla.org/seamonkey/source/layout/doc/frame_reflow_debug.html">How to Debug Reflow </a>
<p class="good"><a href="http://www.mozilla.org/newlayout/doc/block-and-line.html">Waterson's Block and Line Cheat Sheet</a>
<p class="good"><a href="http://lxr.mozilla.org/seamonkey/source/layout/doc/adding-style-props.html">How to add Style Properties</a>
<p class="unassigned">Measuring Layout Performance
<p class="wip"><a href="http://lxr.mozilla.org/seamonkey/source/layout/doc/regression_tests.html">Running the Regression Tests (bernd/dcone)</a>
<p class="good"><a href="http://lxr.mozilla.org/seamonkey/source/layout/doc/debugtable.html">Debugging Table Reflow</a>
</div>
<hr width="100%" size="2">
<p>Authors:
<ul>
<li>Marc Attinasi (attinasi@netscape.com)</li>
</ul>
<p>Document History:
<ul>
<li>05/06/2002 - Marc Attinasi: created</li>
<li>05/13/2002 - Marc Attinasi: added Block and Line Cheat Sheet, and link to existing Reflow document</li>
<li>05/21/2002 - Marc Attinasi: added Bernd's Table Reflow Debugging How-To (thanks Bernd!)</li>
<li>05/21/2002 - Bernd Mielke: added Frame Reflow Debugging How-To</li>
<li>06/16/2002 - Bernd Mielke: added layout regression test description</li>
</ul>
</body>
</html>

Binary file not shown.

View file

@ -0,0 +1,209 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.61 [en] (X11; I; Linux 2.2.5-22 i686) [Netscape]">
</head>
<body>
<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 "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>
Float 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>
<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 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>
<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>Float Management</u></h3>
Since child block elements are containing blocks for floats, the only
place where a block frame will see a float is as part of an inline line.
Consequently, the nsLineBox will only keep track of floats on inline
lines (saving storage for block lines).
<p>The nsLineLayout class and the block frame cooperate in the management
of floats. Since the frame construction code leaves a "placeholder" frame
in-flow where the float was found, when nsLineLayout reflows a placeholder
frame it knows to inform the block about it. That triggers the blocks "AddFloat"
logic which then determines where the float 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 floats,
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
float. To simplify this process, the spacemanager is used to keep track
of available and busy space. Floats 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;
<h3>
<u>First-line style</u></h3>
First-line is handled entirely by the frame construction code.
<br>&nbsp;
<br>&nbsp;
</body>
</html>

View file

@ -0,0 +1,101 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Nisheeth Ranjan">
<meta name="GENERATOR" content="Mozilla/4.5 [en]C-NSCP (WinNT; U) [Netscape]">
<title>HTML Layout Internals</title>
</head>
<body>
<h1>
HTML Layout Internals</h1>
<h2>
Big picture</h2>
An HTML document comes in from netlib into the HTML parser.&nbsp; The parser
creates parser nodes and feeds them to the content sink.&nbsp; The content
sink constructs a content model that represents the hierarchical structure
of the document.&nbsp; As different sub-trees in the content model are
fully available, the stylesheet processor iterates over them and creates
the corresponding frame hierarchy.&nbsp; The frames recursively layout
and render themselves.
<p>The part that we are going to drill down into is the code in the block
and inline frame classes.&nbsp; Block and inline are the two primary display
types specified in CSS and are used in the layout of most of the HTML tags.&nbsp;
The table related tags have their own display types like "table-cell",
"table-row", etc. and their implementation is a separate topic in itself.
<h2>
Block and inline code</h2>
The main classes involved in the layout of HTML documents are nsBlockFrame
and nsInlineFrame, both of which inherit from nsContainerFrame (why?).&nbsp;
These classes are persistent across reflows and are organized in a hierarchy
to constitute the frame model of the Gecko system.&nbsp; The frame model
is derived by applying style and presentation semantics to the content
model.&nbsp; Each frame in the frame model has a one to one correspondence
with a rectangular region on the presentation context (screen, printer,
etc.) and contains the formatting information needed to render that rectangle.&nbsp;
The block and inline frame classes implement the nsIFrame and nsIHTMLReflow
interfaces.&nbsp; The nsIFrame interface contains methods for managing
child frames and linkage with sibling frames, accessing the style context
associated with the frame, painting the frame, and handling events that
are passed in from the widget hierarchy.&nbsp; The nsIHTMLReflow interface
inherits from the nsIReflow interface and adds methods related to word
breaking and whitespace querying.&nbsp; The nsIReflow interface defines
the Reflow() method that initiates the reflow process along with the
DidReflow() method that get calledafter the reflow process.&nbsp;
nsReflowState and nsReflowMetrics are parameters to
the templatized nsIReflow interface: the former is used to hold state during
reflow of a frame and the latter is used to return the frame's desired
size and alignment to the parent frame during the reflow process.
<p>nsBlockReflowContext and nsBlockReflowState both hold state information
during the reflow process.&nbsp; nsBlockReflowContext encapsulates the
state and algorithm for reflowing child block frames.&nbsp; nsBlockReflowState
contains state and methods used by a block frame to reflow itself.&nbsp;
Both these classes are instantiated once per block frame.
<p>The nsLineLayout class is the engine used by the block and inline frame
classes to layout themselves on a line.&nbsp; Frames get passed in to the
nsLineLayout class via the BeginSpan() and EndSpan() methods.&nbsp; Each
span represents a run of frames with the same style data (???).&nbsp; Other
methods exist on the nsLineLayout class to position and size the frames
on the current line.
<p>nsBlockBandData is the class used to manage the processing of the space-manager
(nsSpaceManager) band data.&nbsp; It provides HTML/CSS specific semantics
on top of the general space management facilities provided by nsSpaceManager.
<p>nsSpaceManager is a class that is told about regions that reserve space
and exposes methods to query for available space in a given band.
<p>The nsLineBox class represents a horizontal line of frames and is singly
linked to the next line box in the document.&nbsp; It is basically a container
of a frame list that share the property of being on the same line in the
formatted output of the document.
<p>The nsTextRun class holds on to a list of frames containing pieces of
text that form a logical text run.&nbsp; This is needed because a single
text run can occur on leaves at many levels of the document's content tree.&nbsp;
This class gives the text layout process an efficient way to get access
to text runs and, so, determine where word breaks should occur.
<h2>
Questions</h2>
What are anonymous blocks (nsBlockFrame.h)?
<br>What is the difference between a span and a band (nsLineLayout)?
<br>Why do nsBlockFrame and nsInlineFrame both inherit from nsContainerFrame?
<h2>
To Do</h2>
<ol>
<li>
Provide more information about methods and state of each of the classes
above.</li>
<li>
Give a description of how the above classes interact with each other as
a simple HTML document is laid out.&nbsp; Then, add in different features
to the HTML that exercise different areas of the code, like floats, anonymous
blocks, etc.</li>
</ol>
</body>
</html>

View file

@ -0,0 +1,124 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@namespace xlink url("http://www.w3.org/1999/xlink");
Documentation {
display: block;
font-family: Verdana, sans-serif;
font-size: 11pt;
margin: 8px;
}
Author {
display: block;
font-size: 90%;
}
Author:before {
content: "Author: ";
font-weight: bold;
}
UpdateDate {
display: block;
font-size: 90%;
}
UpdateDate:before {
content: "Updated: ";
font-weight: bold;
}
Title {
display: block;
font-size: 250%;
font-weight: bold;
letter-spacing: -1.25pt;
margin-top: 0;
margin-bottom: .5em;
}
SectionHeading {
display: block;
font-size: 125%;
font-weight: bold;
margin-top: 2em;
margin-bottom: .5em;
}
Body {
display: block;
margin-top: 1em;
margin-bottom: .5em;
}
SectionHeading + Body { /* body after section heading */
margin-top: 0;
}
Components {
display: block;
margin-top: 1em;
margin-left: .5in;
border: dotted 1px black;
}
:link:hover {
background-color: blue;
color: white;
cursor: pointer;
}
/* workaround for above rule not working */
*[xlink|type] {
cursor: pointer;
}
/* workaround for above rule not working */
*[xlink|show="replace"] {
cursor: pointer;
}
Term {
display: block;
font-weight: bold;
background-color: lightyellow;
padding-left: .5em;
}
Definition {
display: block;
margin-left: 40px;
}
Interfaces, Characteristics, Items, Categories {
display: block;
margin-left: 40px;
list-style-position: outside;
list-style-type: disc;
}
Purposes {
display: block;
margin-left: 40px;
list-style-position: outside;
list-style-type: decimal;
counter-reset: -html-counter 0;
}
Interface, Characteristic, Purpose, Item, Category {
display: list-item;
}
RunIn {
display: inline;
font-weight: bold;
}
Note {
width: 2in;
height: auto;
float: right;
font-size: 90%;
margin-left: 1em;
margin-right: .5em;
border-top: solid 2px black;
border-bottom: solid 1px black;
padding: .5em 0;
}
Note:before {
content: "Note";
font-weight: bold;
display: inline;
background-color: black;
color: white;
margin-right: .25em;
padding: .5em .25em 0 .25em;
}

View file

@ -0,0 +1,279 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<?xml-stylesheet href="layout.css" type="text/css"?>
<!DOCTYPE Documentation>
<Documentation xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink">
<Title>Gecko Layout Engine</Title>
<Author xlink:type="simple" xlink:show="new" xlink:href="mailto:troy@netscape.com">Troy Chevalier</Author>
<UpdateDate>8 August 1999</UpdateDate>
<SectionHeading>Overview</SectionHeading>
<Body>Gecko is Mozilla's new layout engine. It is based on the HTML4, CSS1, XML 1.0,
and DOM Internet standards, and it is built using a modular XPCOM-based
architecture.</Body>
<Body>When we talk about layout, we're referring to the formatting process that applies
presentation styles to a source document. The formatting process is controlled
by the style specification.</Body>
<SectionHeading>Components</SectionHeading>
<Body>Here are a list of components and terms that will be referenced by this document.</Body>
<Components>
<Term>Parser</Term>
<Definition>Either the <A xlink:type="simple" xlink:show="replace" xlink:href="http://www.mozilla.org/newlayout/doc/parser.html">HTML</A>
or XML parser. Processes the document and makes calls to the content sink.</Definition>
<Term>Content sink</Term>
<Definition>Called by the parser. Responsible for building the content model.</Definition>
<Term><A xlink:type="simple" xlink:show="replace" xlink:href="http://www.mozilla.org/newlayout/doc/contentmodel.html">Content model</A></Term>
<Definition>Consists of document object and a tree of content objects. Changes to the
content model result in modifications of the frame model.</Definition>
<Term>Frame model</Term>
<Definition><A xlink:type="simple" xlink:show="replace" xlink:href="#Frames">Frames</A> are formatting
objects. Each frame defines a particular set of formatting characteristics.</Definition>
<Term><A xlink:type="simple" xlink:show="replace" xlink:href="#Reflow">Reflow</A></Term>
<Definition>The formatting process. Reflow of the frame model defines the visual appearance
of the formatted document.</Definition>
<Term><A xlink:type="simple" xlink:show="replace" xlink:href="#FrameConstruction">Frame construction</A></Term>
<Definition>Initial creation and updating of the frame model in response to changes to the
content model and changes to the style data.</Definition>
<Term><A xlink:type="simple" xlink:show="replace" xlink:href="http://www.mozilla.org/newlayout/doc/style.html">Style system</A></Term>
<Definition>Provide the mapping and management of style data onto document content in a given
presentation. Major components are style set, style sheets, style sheet and
rules, style context, and style sheet loader.</Definition>
<Term>Presentation shell</Term>
<Definition>Controlling point for managing the presentation of a document.</Definition>
<Term><A xlink:type="simple" xlink:show="replace" xlink:href="http://www.mozilla.org/newlayout/doc/viewsystem.html">View system</A></Term>
<Definition>Consists of a view manager and view objects arranged in a tree hierarchy.
Views support overlapped positioning, z-order sorting, and opacity levels.</Definition>
</Components>
<SectionHeading>Document Loading</SectionHeading>
<Body>The basic flow of control is as follows: as the parser encounters tokens it notifies
the content sink that a new node (or child node) is encountered. The content sink
creates the appropriate type content object and inserts it into the content model.</Body>
<Body>Whenever the content model changes the document's observers are notified. The presentation
shell is one of the document observers. The presentation shell forwards the document
change notification to the style set object</Body>
<Body>The style set passes the notification to the frame construction code, the
frame construction code creates new frames and inserts them into the frame model. The
document is reflowed, and the formatted changes are displayed.
</Body>
<Body>
The actual interfaces involved are:
<Interfaces>
<Interface>nsIDocument</Interface>
<Interface>nsIDocumentObserver</Interface>
<Interface>nsIPresShell</Interface>
<Interface>nsIStyleSet</Interface>
<Interface>nsIStyleFrameConstruction</Interface>
<Interface>nsIFrame</Interface>
</Interfaces>
</Body>
<Body>All of the interface files are located in the mozilla/layout/base/public
directory.</Body>
<SectionHeading>Object Lifetimes</SectionHeading>
<Body>Gecko supports multiple views of the same document. This means you can print the
same document that you're viewing on the screen, and there's only one content
model. Because there's just a single content model, each of the content objects
is referenced counted. The document holds a reference to the root content object,
and each content node holds a reference to its child content nodes.</Body>
<Body>Each view of the document has a separate presentation shell, style manager,
style set, and frame hierarchy. The presentation shell is the controlling point for
the presentation of a document, and it holds a reference to the document object.</Body>
<Body>Frames and views are not referenced counted. The lifetime of the frame hierarchy
is bounded by the lifetime of the presentation shell which owns the frames. The
lifetime of the view hierarchy is bounded by the lifetime of the view manager
that owns the views.</Body>
<SectionHeading><html:a name="Frames">Frames</html:a></SectionHeading>
<Body>Each frame defines a particular set of formatting characteristics. Frames have
the opportunity to:
<Characteristics>
<Characteristic>reflow (format) their child frames</Characteristic>
<Characteristic>render their appearance</Characteristic>
<Characteristic>handle mouse and keyboard events</Characteristic>
<Characteristic>display a cursor</Characteristic>
<Characteristic>have an associated view object</Characteristic>
</Characteristics>
</Body>
<Body>Frames can have multiple child lists, the default unnamed child list
(referred to as the principal child list) and additional named child lists.
There is an ordering of frames within a child list, but no ordering
between frames in different child lists of the same parent frame.</Body>
<Body>The principal child list contains the flowed children, and the additional
child lists are for out-of-flow frames like floated elements and absolutely
positioned elements.</Body>
<Body>Child frames are linked together in a singly linked list. Each frame
defines its own local coordinate space. Frame bounding rects are in twips,
and the origin is relative to the upper-left corner of its parent frame.
The bounding rect includes the content area, borders, and padding.</Body>
<SectionHeading><html:a name="FrameConstruction">Frame Construction</html:a></SectionHeading>
<Body>The frame construction process begins with a notification that content
has been added or removed or that style has changed.</Body>
<Body>The first step is to resolve style information for the content element.
This process creates a style context that is stored in the frame (see
nsIStyleContext).</Body>
<Body>Once style is resolved construction rules are used to decide the type of
frame to create. First we look at the element's tag and special case some
things like IMG elements. If we don't create a frame that way, then we use
the 'display' property to dictate what type of frame to create. Typically
it's a block or inline frame.</Body>
<Body>For a 'display' value of 'none' no frame is created. For elements that are
out of the flow (for example, a floated element or an absolutely positioned
element), a placeholder frame is also created. The placeholder frame is inserted
into the flow exactly where the out-of-flow frame would have been inserted.
The out-of-flow frame is then inserted as a child of its containing block in
one of the additional child lists. Floated frames are inserted into the
"Float-list" and absolutely positioned frames are inserted into the
"Absolute-list".</Body>
<SectionHeading>Frame Manager</SectionHeading>
<Body>The frame manager is owned by the presentation shell and used by both the
presentation shell and the frame construction code. It serves two main
purposes:
<Purposes>
<Purpose>provides a service for mapping from content object to frame and from out-of-flow
frame to placeholder frame</Purpose>
<Purpose>coordinates structural modifications to the frame model</Purpose>
</Purposes>
</Body>
<Body>In many places in the frame code we need to find the frame associated with
a particular content object. In order to quickly implement this operation we
maintain a mapping from content objects to frames. The frame construction adds
and removes entries from the map as frames are created and destroyed.</Body>
<Body>When creating new frames and removing existing frames, the frame construction
code doesn't directly modify the frame hierarchy. Instead if informs the frame
manager and has it coordinate the request. If the frame model lock is available,
the change is processed immediately; otherwise, the request is queued and
processed later.</Body>
<Body>The frame manager also coordinates processing of replaced elements that can't
be rendered (for example, an IMG or OBJECT element), and it allows client to
register to be notified when a particular frame is being destroyed. This is
needed because frames are not reference counted. It's used by the event manager
and other clients to ensure that any outstanding references to the frame are
cleaned up.</Body>
<SectionHeading><html:a name="Reflow">Reflow</html:a> Process</SectionHeading>
<Note>The fact that are two reflow interfaces reflects an early
goal of having core layout and HTML specific layout. The core reflow process would
be the same for all frames, and each class of formatting objects (for
example, CSS and DSSSL) would have their own reflow additions.</Note>
<Body>The reflow process is a top-down protocol where a frame is given some
available space and asked to reflow its child frames and return a desired
size.</Body>
<Body>The reflow process is not part of the nsIFrame interface. The generic reflow
interface is defined in the nsIFrameReflow interface, and the HTML/CSS specific
reflow interface is defined in the nsIHTMLReflow interface.</Body>
<Body>An important part of the reflow process is the calculation of the computed
values for the CSS properties. This includes things like 'width', 'height',
and 'margin', and involves calculation of the containing block width and height
and percentage based values and properties whose value is inherited.</Body>
<Body>This process is encapsulated in the HTML specific reflow state struct
(struct nsHTMLReflowState) that is passed in as part of reflow. The reflow
states are linked together with the reflow state for a child frame pointing
to its parent frame's reflow state. This allows us to walk up the reflow state
structures and calculate containing block width and height and percentage
based values.</Body>
<Body>In addition to the computed values for the CSS box model properties, the
following items are also included:
<Items>
<Item>reflow reason that indicates why the frame is being reflowed</Item>
<Item>a rendering context that can be used to measure text</Item>
<Item>reflow command (only used for incremental reflow)</Item>
<Item>space manager</Item>
</Items>
</Body>
<Body>The most common reflow reasons are 'eReflowReason_Resize' (the viewport
has changed size) and 'eReflowReason_Incremental' (processing of an incremental
reflow command).</Body>
<Body>Reflow commands (see nsHTMLReflowCommand in mozilla/layout/html/base/src) are used
to kick off an incremental reflow. They're generated either by the style system
(in response to a style change) or by a frame itself (for example, if a frame has
dirty child frames that need to be reflowed it will generate a reflow command).</Body>
<Body>Reflow commands are queued by the presentation shell and then dispatched. Reflow
commands have a target frame, which is the frame for which the reflow command
is destined. In the example above the target frame is the frame with dirty child
frames that need to be reflowed. Reflow command processing follows a path from
the root frame down to the target frame.</Body>
<Body>The space manager (see nsISpaceManager in mozilla/layout/base/public) is used
when flowing text around floated elements. It has an API for managing bands of
unavailable space (space that is reserved for a floated element). Internally it
organizes the band data similar to how a region data structure works.</Body>
<SectionHeading>Frame Classes</SectionHeading>
<Body>There are four main categories of frame classes, all of which are located
in mozilla/layout/html/src:
<Categories>
<Category>core frame classes</Category>
<Category>table frame classes</Category>
<Category>form frame classes</Category>
<Category>frameset frame classes</Category>
</Categories>
</Body>
<Body><RunIn>The core frame classes</RunIn> implement the CSS viewport abstraction, scrolling,
block and inline display of flowed elements, floats, and absolute positioning.</Body>
<Body>For more information on block layout, click
<A xlink:type="simple" xlink:show="replace" xlink:href="block.html">here</A>. For more information about
line layout, click <A xlink:type="simple" xlink:show="replace" xlink:href="line-layout.html">here</A>.</Body>
<Body><RunIn>The table frame classes</RunIn> correspond to the HTML4 table spec, and in addition
to the table frame there are row group frames, row frames, column group frames,
column frames, and cell frames. There is an "outer" table frame as well that's
really an anonymous frame that contains the caption frame and the table frame
itself.</Body>
<Body>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.</Body>
<SectionHeading>Event Manager</SectionHeading>
<Body>To be written</Body>
</Documentation>

View file

@ -0,0 +1,118 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.61 [en] (X11; I; Linux 2.2.5-22 i686) [Netscape]">
</head>
<body>
<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 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.</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.</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>
</ol>
nsLineLayout is also used by nsBlockFrame to construct text-run information;
this process is independent of normal line layout is pretty much a hack.
<p>When frames are reflowed they return a reflow status. During line layout,
there are several additions to the basic reflow status used by most frames:
<ul>
<li>
NS_FRAME_COMPLETE - this is a normal reflow status and indicates that the
frame is complete and doesn't need to be continued.</li>
<li>
NS_FRAME_NOT_COMPLETE - this is another normal reflow status and indicates
that the frame is not complete and will need a continuation frame created
for it (if it doesn't already have one).</li>
<li>
NS_INLINE_BREAK - some kind of break has been requested. Breaks types include
simple line breaks (like the BR tag in html sometime does) and more complex
breaks like page breaks, float breaks, etc. Currently, we only support
line breaks, and float 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 using
nsLineLayout.
<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" (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.
<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 separate inline elements.
<p>As a post-processing step, the TrimTrailingWhiteSpace logic is used
to remove those pesky pieces 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>

View file

@ -0,0 +1,902 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="Author" CONTENT="Kipp E.B. HIckman">
<META NAME="GENERATOR" CONTENT="Mozilla/4.03 [en] (WinNT; I) [Netscape]">
<TITLE>HTML</TITLE>
<BASE HREF="file:///s|/ns/xena/htmlpars/testhtml/">
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#FF0000" VLINK="#800080" ALINK="#0000FF">
<H2>
HTML</H2>
This documents describes the complete handling of HTML in magellan. The
document covers the parsing process - how HTML is lexically analysized
and then interprted. After the parsing process is discussed we give a detailed
analysis of each HTML tag and the attributes that are supported, the values
for the attributes and how the tag is treated by magellan.
<H2>
Parsing</H2>
HTML is tokenized by an HTML scanner. The scanner is fed unicode data to
parse. Stream converters are used to translate from various encodings to
unicode. The scanner separates the input stream into tokens which consist
of:
<UL>
<LI>
text</LI>
<LI>
tags</LI>
<LI>
entities</LI>
<LI>
script-entities</LI>
<LI>
comments</LI>
<LI>
conditional comments</LI>
</UL>
The HTML parsing engine uses the HTML scanner for lexical anlaysis. The
parsing engine operates by attacking the input stream in a set of well
defined steps:
<UL>
<LI>
The parser processes the head portion of the document first, without emitting
any output. This is done to discover a few special features of html:</LI>
<UL>
<LI>
The parser processes META tags looking for META TARGET</LI>
<LI>
The parser processes META tags looking for META tags which affect the character
set. Nav4 handles the very first character set defining meta tag (all others
are ignored) by reloading the document with the proper character conversion
module inserted into the stream pipeline.</LI>
</UL>
<LI>
After the head portion is processed the parser then proceeds to process
the body of the document</LI>
</UL>
<H3>
Tag Processing</H3>
Tags are processed by the parser by locating a <B>"tag handler"</B> for
the tag. The HTML parser serves as the tag handler for all of the builtin
tags documented below. Tag attribute handling is done during translation
of tags into content. This mapping translates the tag attributes into content
data and into style data. The translation to style data is documented below
by indicating the mapping from tag attributes to their CSS1 (plus extensions)
equivalents.
<H3>
Special Hacks</H3>
The following list describes hacks added to the magellan parsing engine
to deal with navigator compatibility. These are just the parser hacks,
not the layout or presentation hacks. Most hacks are intriduced for HTML
syntax error recovering. HTML doesn't specify much how to handle those
error conditions. Netscape has made big effort to render pages with non-prefect
HTML. For many reasons, new browsers need to keep compatible in thsi area.
<UL>
<LI>
Entities can be used as escape in quoted string. For value string in name-value
pair,&nbsp; see <A HREF="../testhtml/quote001.html">compatibility test
quote001.html</A>. Test line 70 shows that an entity quote at the begining
means the value is NOT quoted. Test line 90 shows that if the value is
started with a quote, then an entity quote does NOT terminate the value
string.</LI>
<LI>
Wrapping tags are special tags such as title, textarea, server, script,
style, and etc.. The comment in ns\lib\libparse\pa_parse.c says:</LI>
<BR>&nbsp; /*
<BR>&nbsp;&nbsp; * These tags are special in that, after opening one of
them, all other tags are ignored until the matching
<BR>&nbsp;&nbsp; * closing tag.
<BR>&nbsp;&nbsp; */
<BR>During the searching of an end tag, comments and quoted strings are
observed. see <A HREF="../testhtml/title01.html">compatibility test title01.html</A>.
6.0 handles comments now, need to add quoted string.
<LI>
If a &lt;tr> or &lt;td> tag is seen outside any &lt;table> scope, it is
ignored. see <A HREF="../testhtml/table110.htm">compatibility test table110.htm</A>.</LI>
<LI>
<FONT COLOR="#000000">In case of table in table but not in cell, table
tags before the last table tag are ignored. We found this problem in some
Netscape public pages, see bug #85118. For example, &lt;table> &lt;table
border> .....,or &lt;table> &lt;tr> &lt;table border>...,&nbsp; the table
will be displayed with border.&nbsp;</FONT> <A HREF="../testhtml/table201.html">compatibility
test table201.html</A>. There table and tr tags are buffered for this recovery.
When a TD or CAPTION tag is open, the buffer is flushed out, because we
cannot buffer contents of TD or CAPTION for performance and memory constrains.
They are subdoc's and can be very big. If we see a &lt;table> outside cell
after previous table is flushed out, the new &lt;table> tag is ignored.
Nav4.0 can discard previous table in such case. <A HREF="../testhtml/tableall.html">tableall.html
</A>is the index for table test cases.</LI>
<LI>
Caption is not a commonly used feature. In Nav4.0, captions can be anywhere.
For Captions outside cells, the first one takes effect. For captions inside
cells, the last one takes effect, and they also close TD and TR. In 6.0,
caption is limited to the standard position: after &lt;table>. Captions
in other places are ignored, their contents are treated as text. See test
case table05a.html to table05o.html.</LI>
<LI>
<FONT COLOR="#000000">For &lt;table> &lt;tr> &lt;tr>, the first &lt;tr>
takes effect.</FONT></LI>
<LI>
The nav4 parser notices when it hits EOF and it's in the middle of scanning
in a comment. When this happens, the parser goes back and looks for an
improperly closed comment (e.g. a simple > instead of a -->). If it finds
one, it reparses the input after closing out the comment.</LI>
<LI>
<FONT COLOR="#FF0000">XXX Brendan also pointed out that there is something
similar done for tags, but I don't recall what it is right now.</FONT></LI>
<LI>
<FONT COLOR="#000000">When Nav4.0 sees the '&lt;' sign, it searchs for
'>', observing quoted values. If it cannot find one till EOF, the '&lt;'
sign is treated as text. In Xena 6.0, a limit is set for how far the '>'
is searched. the default limit is 4096 char, and there is a API HTMLScanner.setMaxTagLength()
to changed it. setting -1 means no limit, which is same as Nav4.0.</FONT></LI>
</UL>
<FONT COLOR="#FF0000">TODO:</FONT>
<UL><FONT COLOR="#FF0000">Document the mapping of tag attributes into CSS1
style, including any new "css1" attributes</FONT>
<BR>&nbsp;</UL>
<B>List of 6.0 features incompatible with 4.0</B>
<UL>
<LI>
Navigator 4.0 value string is truncated at 82 characters. XENA60 limit
is MAX_STRING_LENGTH = 2000.</LI>
<BR>&nbsp;</UL>
<HR WIDTH="100%">
<H2>
Tags (Categorically sorted)</H2>
All line breaks are conditional. If the x coordinate is at the current
left margin then a soft line break does nothing. Hard line breaks are ignored
if the last tag did a hard line break.
<P><B>divalign</B> = left | right | center | justify
<BR><B>alignparam</B> = abscenter | left | right | texttop | absbottom
| baseline | center | bottom | top | middle | absmiddle
<BR><B>colorspec</B> = named-color | #xyz | #xxyyzz | #xxxyyyzzz | #xxxxyyyyzzzz
<BR><B>clip</B> = [auto | value-or-pct-xy](1..4) (pct of width for even
coordinates; pct of height for odd coordinates)
<BR><B>value-or-pct = </B>an integer with an optional %; ifthe percent
is present any following characters are ignored!
<BR><B>coord-list</B> = <FONT COLOR="#DD0000">XXX</FONT>
<BR><FONT COLOR="#000000"><B>whitespace-strip</B> = remove leading and
trailing and any embedded whitespace that is not an actual space (e.g.
newlines)</FONT>
<H1>
Head objects:</H1>
<B>TITLE</B>
<UL>The TITLE tag is a container tag whose contents are not HTML. The contents
are pure text and are processed by the parser until the closing tag is
found. There are no attributes on the tag and any whitespace present in
the tag is compressed down with leading and trailing whitespace eliminated.
The first TITLE tag found by the parser is used as the document's title
(subsequent tags are ignored).</UL>
<B>BASE</B>
<UL>Sets the base element in the head portion of the document. Defines
the base URL for <FONT COLOR="#DD0000">all</FONT>? links in the document.
<BR>Attributes:
<UL><B>HREF</B>=url [This is an absolute URL]
<BR><B>TARGET</B>=string [must start with XP_ALPHA|XP_DIGIT|underscore
otherwise nav4 ignores it]</UL>
</UL>
<B>META</B>
<UL>Can define several header fields (content-encoding, author, etc.)
<BR>Attributes:
<UL><B>REL</B>=SMALL_BOOKMARK_ICON|LARGE_BOOKMARK_ICON
<UL><B>SRC</B>=string</UL>
<B>HTTP-EQUIV</B>="header: value"
<UL><B>CONTENT</B>=string</UL>
</UL>
HTTP-EQUIV values (from libnet/mkutils.c NET_ParseMimeHeader):
<UL>ACCEPT-RANGES
<BR>CONTENT-DISPOSITION
<BR>CONTENT-ENCODING
<BR>CONTENT-RANGE
<BR>CONTENT-TYPE [ defines character set only ]
<BR>CONNECTION
<BR>DATE
<BR>EXPIRES
<BR>EXT-CACHE
<BR>LOCATION
<BR>LAST-MODIFIED
<BR>LINK
<BR>PROXY-AUTHENTICATE
<BR>PROXY-CONNECTION
<BR>PRAGMA
<BR>RANGE
<BR>REFRESH
<BR>SET-COOKIE
<BR>SERVER
<BR>WWW-AUTHENTICATE
<BR>WWW-PROTECTION-TEMPLATE
<BR>WINDOW-TARGET</UL>
Style sheets and HTML w3c spec adds this:
<UL>CONTENT-STYLE-TYPE [ last one wins; overrides header from server if
any ]</UL>
</UL>
<B>LINK</B>
<UL>List related resources. Used by extensions mechanism to find tag handlers.
<FONT COLOR="#0000FF">/LINK == LINK!</FONT>
<BR>Attributes:
<UL><B>REL</B>=FONTDEF
<UL><B>SRC</B>=url</UL>
<B>REL</B>=STYLESHEET [ If MEDIA param is defined it must ==nc screen ]
<UL><B>LANGUAGE</B>=LiveScript|Mocha|JavaScript1.1|JavaScript1.2
<BR><B>TYPE</B>="text/javascript" | "text/css"
<BR><B>HREF</B>=url
<BR><B>ARCHIVE</B>=url
<BR><B>CODEBASE</B>=url
<BR><B>ID</B>=string
<BR><B>SRC</B>=url</UL>
</UL>
Note: HREF takes precedence over SRC in nav4.</UL>
<B>HEAD</B>
<UL>/HEAD clears the "in_head" flag (but leaves the "in_body" flag alone.
<BR>Text in head clears in_head, and set in_body true, just as if the author
forgot the /HEAD tag.
<BR>Attributes: none</UL>
<B>HTML</B>
<UL>Ignored.
<BR>Attributes: none</UL>
<B>STYLE</B>
<UL>Allowed anywhere in the document. Note that entities are not parsed
in the style tag's content.
<BR>Attributes:
<UL><B>LANGUAGE</B>=LiveScript|Mocha|JavaScript1.1|JavaScript1.2
<BR><B>TYPE</B>="text/javascript" | "text/css"
<BR><B>HREF</B>=url
<BR><B>ARCHIVE</B>=url
<BR><B>CODEBASE</B>=url
<BR><B>ID</B>=string
<BR><B>SRC</B>=url</UL>
</UL>
<B>FRAMESET</B>
<UL>Frameset with rows=1 and cols=1 is ignored.
<BR>Attributes:
<UL><B>FRAMEBORDER</B>= no | 0 (zero) [default is no_edges=false]
<BR><B>BORDER</B>= int [clamped: >= 0 &amp;&amp; &lt;= 100]
<BR><B>BORDERCOLOR</B>= color
<BR><B>ROWS</B>= pct-list
<BR><B>COLS</B>= pct-list</UL>
</UL>
<B>FRAME</B>
<UL>Border width of zero disables edges.
<BR>Attributes:
<UL><B>FRAMEBORDER</B>= no | 0 (zero) [default is framesets value]
<BR><B>BORDER</B>= int [clamped; >= 0 &amp;&amp; &lt;= 100]
<BR><B>BORDERCOLOR</B>= color
<BR><B>NORESIZE</B>= true [default is false]
<BR><B>SCROLLING</B>= yes | scroll | on | no | noscroll | off
<BR><B>SRC</B>= url [clamped: prevent recursion by eliminating any anscestor
references]
<BR><B>NAME</B>= string
<BR><B>MARGINWIDTH</B>= int (clamped: >= 1)
<BR><B>MARGINHEIGHT</B>= int (clamped: >= 1)</UL>
</UL>
<B>NOFRAMES</B>
<UL>Used when frames are disabled or for backrev browsers. Has no stylistic
consequences.</UL>
<H1>
<HR WIDTH="100%">Body objects:</H1>
&nbsp;<B>BODY</B>
<UL>The tag is only processed on open tags and it is always processed.
See ns\lib\layout\laytags.c, searching for "case P_BODY". During tag processing
the in_head flag is set to false and the in_body flag is set to true. An
attribute is ignored if the document already has that attribute set. Attributes
can be set by style sheets, or by previous BODY tags. see <A HREF="../testhtml/head02.html">test
head02.html</A>.
<BR>Attributes:
<UL><B>MARGINWIDTH</B>=int [clamped: >= 0 &amp;&amp; &lt; (windowWidth/2
- 1)]
<BR><B>MARGINHEIGHT</B>=int [clamped: >= 0 &amp;&amp; &lt; (windowHeight/2
- 1)]
<BR><B>BACKGROUND</B>=url
<BR><B>BGCOLOR</B>=colorspec
<BR><B>TEXT</B>=colorspec
<BR><B>LINK</B>=colorspec
<BR><B>VLINK</B>=colorspec
<BR><B>ALINK</B>=colorspec
<BR><B>ONLOAD, ONUNLOAD, UNFOCUS, ONBLUR, ONHELP</B>=script
<BR><B>ID</B>=string</UL>
</UL>
<B>LAYER, ILAYER</B>
<UL>Open layer/ilayer tag automaticly close out an open form if one is
open. It does something to the soft linebreak state too.
<BR>Attributes:
<UL><B>LEFT</B>=value-or-pct (pct of <TT>right-left</TT> margin)
<BR><B>PAGEX</B>=x (if no LEFT)
<BR><B>TOP</B>=value-or-pct
<BR><B>PAGEY</B>=y (if no TOP)
<BR><B>CLIP</B>=clip
<BR><B>WIDTH</B>=value-or-pct (pct of <TT>right-left</TT> margin)
<BR><B>HEIGHT</B>=value-or-pct
<BR><B>OVERFLOW</B>=string
<BR><B>NAME</B>=string
<BR><B>ID</B>=string
<BR><B>ABOVE</B>=string
<BR><B>BELOW</B>=string
<BR><B>ZINDEX</B>=int [any value]
<BR><B>VISIBILITY</B>=string
<BR><B>BGCOLOR</B>=colorspec
<BR><B>BACKGROUND</B>=url</UL>
</UL>
<B>NOLAYER</B>
<UL>Container for content which is used when layers are disabled or unsupported.
The content has no style consequences (though it could if somebody stuck
in some CSS1 style rules for it).</UL>
<B>P</B>
<UL>Closes the paragraph. If the attribute is present then an alignment
gets pushed on the alignment stack. All values are supported by nav4.
<BR>Attributes:
<UL><B>ALIGN</B>=divalign</UL>
</UL>
<B>ADDRESS</B>
<UL>There are no attributes. ADDRESS closes out the open paragraph. The
open tag does a conditional soft line break and then pushes a merge of
the current style with italics enabled onto the style stack. The close
always pop the style stack and also does a conditional soft line break.</UL>
<B>PLAINTEXT, XMP</B>
<UL>PLAINTEXT causes the remaining content to no longer be parsed. XMP
causes the content to not parse entities or other tags. The XMP can be
closed by it's own tag (on any boundary); PLAINTEXT is not closed (html3.2
allows it to be closed). Both tags change the style to a fixed font of
a</UL>
<B>LISTING</B>
<UL>Closes the paragraph. Does a hard line break on open and close. Open
pushes a fixed width font style of a particular font size on the style
stack. The close tag pops the top of the style stack.
<BR>Attributes: none</UL>
<B>PRE</B>
<UL>Closes the paragraph. The open tag does a hard line break. A fixed
font style (unless VARIABLE is present) is pushed on the style stack. The
close tag pops the top of the style stack. It also does a hard line break.
<BR>Attributes:
<UL><B>WRAP</B>
<BR><B>COLS</B>=int [clamped: >= 0]
<BR><B>TABSTOP</B>=int [clamped: >= 0; clamped value is replaced with default
value]
<BR><B>VARIABLE</B></UL>
</UL>
<B>NOBR</B>
<UL>This tag doesn't nest. Instead it just sets or clears a flag in the
state machine. It has no effect on any other state.</UL>
<B>CENTER</B>
<UL>Closes the paragraph. Always does a conditional soft line break. The
open tag pushes an alignment on the aligment stack. The close tag pops
the top alignment off.
<BR>Attributes: none</UL>
<B>DIV</B>
<UL>Closes the paragraph. Always does a conditional soft line break. COLS
defines the number of columns to layout in (like MULTICOL). The open tag
pushes an alignment on the alignment stack (if COLS > 1 then it pretends
to be a MULTICOL tag). The close tag pops an aligment from the alignment
stack.
<BR>Attributes:
<UL><B>ALIGN</B>=divalign
<BR><B>COLS</B>=int [if cols > 1 then DIV acts like a MULTICOL tag else
DIV is just a container]
<UL><B>GUTTER</B>= int (clamped: >= 1)
<BR><B>WIDTH</B>= value-or-pct [pct of right-left margin; clamped >= 1/0
(strange code)]</UL>
</UL>
</UL>
<B>H1-H6</B>
<UL>Closes the paragraph. The open tag does a hard line break and pushes
a style item which enables bold and disables fixed and italic. The close
tag always pops the top item from the style stack. It also does a hard
line break. If the <B>ALIGN</B> attribute is present then the open tag
pushes an alignment on the alignment stack. The close tag will look at
the top of the alignment stack and if its a header of any kind (H1 through
H6) then the alignment is popped. In either case the close tag also does
a conditional soft line break (this happens before the hard line break).
<BR>Attributes:
<UL><B>ALIGN</B>=divalign</UL>
</UL>
A note regarding closing paragraphs: Any time a close paragraph is done
(for any tag) if the top of the alignment stack has a tag named "P" then
a conditional soft line break is done and the alignment is popped.
<H3>
<HR ALIGN=LEFT WIDTH="50%"></H3>
<B>TABLE</B>
<UL>Close the paragraph.
<BR>Attributes:
<UL><B>ALIGN=</B>left|right|center|abscenter
<BR><B>BORDER</B>=int [clamped: if null then -1, if &lt; 1 then 1 ]
<BR><B>BORDERCOLOR</B>=string [if not supplied then set to the text color
]
<BR><B>VSPACE</B>=int [ clamped: >= 0 ]
<BR><B>HSPACE</B>=int [ clamped: >= 0 ]
<BR><B>BGCOLOR</B>=color
<BR><B>BACKGROUND</B>=url
<BR><B>WIDTH</B>=value-or-pct [ % of win.width minus margins; clamped:
>= 0 ]
<BR><B>HEIGHT</B>=value-or-pct [ % of win.height minus margins; clamped:
>= 0 ]
<BR><B>CELLPADDING</B>=int [clamped: >= 0; separate pads take precedence
]
<BR><B>TOPPADDING</B>= int [clamped: >= 0 ]
<BR><B>BOTTOMPADDING</B>= int [clamped: >= 0 ]
<BR><B>LEFTPADDING</B>= int [clamped: >= 0 ]
<BR><B>RIGHTPADDING</B>= int [clamped: >= 0 ]
<BR><B>CELLSPACING</B>= int [clamped: >= 0 ]
<BR><B>COLS</B>=int [clamped: >= 0]</UL>
The code supports more attributes in the Table attribute handler than it
does in the code that gets the attributes from the tag! They are border_top,
border_left, border_right, border_bottom, border_style (defaults to outset;
allows for outset/dotted/none/dashed/solid/double/groove/ridge/inset).</UL>
<B>TR</B>
<UL>Open TR automatically closes an open table row (and an open table cell
if one is open). It also automatically closes a CAPTION tag.
<BR>Attributes:
<UL><B>BGCOLOR</B>=color
<BR><B>BACKGROUND</B>=url
<BR><B>VALIGN</B>=top|bottom|middle|center(==middle)|baseline; default
is top
<BR><B>ALIGN</B>=left|right|middle|center(==middle); default is left</UL>
</UL>
<B>TH, TD</B>
<UL>If no table then the tag is ignored (open or close). If no row is currently
opened or the current row is current done (because of a &lt;/TR> tag) then
a new row is begun. Oddly enough the tag parameters for the row come from
the TH/TD tag in this case. An open of either of these tags will automatically
close the previous cell.
<BR>Attributes:
<UL><B>COLSPAN</B>=int [clamped: >= 1 &amp;&amp; &lt;= 1000 ]
<BR><B>ROWSPAN</B>=int [clamped: >= 1 &amp;&amp; &lt;= 10000 ]
<BR><B>NOWRAP</B> [boolean: disables wrapping ]
<BR><B>BGCOLOR</B>=color [default: inherit from the row; if not row then
table; if not table then inherit from an outer table cell; this works because
the style is flattened so the outer table cell will have a color]
<BR><B>BACKGROUND</B>=url [same rules as bgcolor for inheritance; tile
mode is inherited too and not settable by TH/TD attributes (have to use
style sheets for that)]
<BR><B>VALIGN</B>=top|bottom|middle|center(==middle)|baseline; default
is top
<BR><B>ALIGN</B>=left|right|middle|center(==middle); default is left
<BR><B>WIDTH</B>=value-or-pct [ clamped: >= 0 ]
<BR><B>HEIGHT</B>=value-or-pct [ clamped: >= 0 ]</UL>
</UL>
<B>CAPTION</B>
<UL>An open caption tag will automatically close an open table row (and
an open cell).
<BR>Attributes:
<UL><B>ALIGN</B>=bottom</UL>
The code sets the vertical alignment to top w/o providing a mechanism for
the user to set it (there is no VALIGN attribute).</UL>
<B>MULTICOL</B>
<UL>The open tag does a hard line break. The close tag checks to see if
the state machine has an open multicol and if it does then it does a conditional
soft line break and then continues to break until both margins are cleared
of floating elements. It recomputes the margins based on the list indenting
level (?). After the synthetic table is output the close tag does a hard
line break.
<P>This tag will treat the input as source for a table with one row and
COLS columns. The data is laid out using the width divided by the number
of columns. After the total height is known, the content is partitioned
as evenly as possible between the columns in the table.
<BR>Attributes:
<UL><B>COLS</B>=int [clamped: values less than 2 cause the tag to be ignored]
<BR><B>GUTTER</B>=int [clamped: >= 1]
<BR><B>WIDTH</B>=value-or-pct [pct of right-left margin; clamped: >= 1/0
(strange code)]</UL>
</UL>
<H3>
<HR ALIGN=LEFT WIDTH="50%"></H3>
<B>BLOCKQUOTE</B>
<UL>Closes the paragraph. The open tag does a hard line break. A list with
the empty-bullet style is pushed on the list stack (unless TYPE=cite/jwz
then a styled list is pushed). The close tag pops any list and does a hard
line break.
<BR>Attributes:
<UL><B>TYPE</B>=cite | jwz</UL>
</UL>
<B>UL, OL, MENU, DIR</B>
<UL>For top-level lists (lists not in lists) a hard break is done on the
open tag, otherwise a conditional-soft-break is done. Tag always does a
close paragrah. The close tag does a conditional soft line break when nested;
when not nested the close tag does a hard line break (even if no list is
open). The open tag pushes the list on the list stack. The close tag pops
any list off the list stack.
<BR>Attributes:
<UL><B>TYPE</B>= none | disc | circle | round | square | decimal | lower-roman
| upper-roman | lower-alpha | upper-alpha | A | a | I | i [clamped: if
none of the above is picked and OL then the bullet type is "number" otherwise
the bullet type is "basic"]
<BR><B>START</B>=int [clamped: >= 1]
<BR><B>COMPACT</B></UL>
</UL>
<B>DL</B>
<UL>Closes the paragraph. For the open tag, if the list is nested then
a conditional soft line break is done otherwise a hard line break is done.
The open tag pushes a list on the list stack. The close tag pops any list
from the list stack. Closing the list acts like other lists closes.
<BR>Attributes:
<UL><B>COMPACT</B></UL>
</UL>
<B>LI</B>
<UL>Closes the paragraph. The open tag does a conditional soft line break.
Close tags are ignored (except for closing the paragraph).
<BR>Attributes:
<UL><B>TYPE</B>= A | a | I | i (if the containing list is an <B>OL</B>)
<BR><B>TYPE</B>= round | circle | square (if the containing list is not
<B>OL</B> and not <B>DL</B>)
<BR><B>VALUE</B>=int [clamped: >= 1]</UL>
The magellan html parser allows the full set of list item styles from the
OL/DL tag instead of just the limited set that nav4 allows.</UL>
<B>DD</B>
<UL>Closes the paragraph. Close tags are ignored (except for closing the
paragraph). DD outside a DL just advances the X coordinate of layout by
a small constant. DD inside a DL does a conditional soft line break and
other margin crud.
<BR>Attributes: none.</UL>
<B>DT</B>
<UL>Closes the paragraph (open or close). Close tags are otherwise ignored.
Does a conditional soft line break. Moves the X layout coordinate to the
left margin.
<BR>Attributes: none</UL>
<H3>
<HR ALIGN=LEFT WIDTH="50%"></H3>
<B>A</B>
<UL>Open anchors push a style on the style stack if the anchor has an <B>HREF</B>.
Close anchors pop as many styles off the top of the style stack that are
anchor tags (anchor tags don't nest in other words). In addition, any styles
on the stack that have the ANCHOR bit set have it cleared and fiddle with
the foreground and background colors.
<BR>Attributes:
<UL><B>NAME</B>=string
<BR><B>HREF</B>=url
<UL><B>TARGET</B>=target
<BR><B>SUPPRESS</B>=true</UL>
</UL>
</UL>
<B>STRIKE, S, TT, CODE, SAMPLE, KBD, B, STRONG, I, EM, VAR, CITE, BLINK,
BIG, SMALL, U, INLINEINPUT, SPELL</B>
<UL>The open tag pushes onto the style stack. The close tag always pops
the top item from the style stack.
<BR>Attributes: none</UL>
<B>SUP, SUB</B>
<UL>The open tag pushes a font size descrease on the style stack. The close
tag always pops the top of the style stack. The open and close tag impacts
the baselineThe only difference between SUP and SUB is how they impact
the baseline. Note that the baseline information is forgotten after a line
break; therefore a close SUP/SUB on the next line will do strange things.
<BR>Attributes: none</UL>
<B>SPAN</B>
<UL>Ignored by the navigator.
<BR>Attributes: none</UL>
<B>FONT</B>
<UL>The open font tag with no attributes resets the font size to the base
font size. The open tag always pushes a style stack entry. The close tag
always pops the top item off the style stack.
<BR>Attributes:
<UL><B>SIZE</B>=[+ int | - int | int ]&nbsp; [clamped: >=1 &amp;&amp; &lt;=
7]
<BR><B>POINT-SIZE=</B>[+ int | - int | int ] [clamped: >= 1 &amp;&amp;
&lt;= 1600]
<BR><B>FONT-WEIGHT</B>=[+ int | - int | int ] [clamped: >= 100 &amp;&amp;
&lt;= 900]
<BR><B>COLOR</B>=colorspec
<BR><B>FACE</B>=string</UL>
</UL>
A note regarding the style stack: The pop of the stack checks to see if
the top of the stack is an ANCHOR tag. If it is not an anchor then the
top item is unconditionally popped. If the top of the style stack is an
anchor tag then the code searches for either the bottom of the stack or
the first style stack entry not created by an anchor tag. If the entry
is followed by another entry then the entry is removed from the stack (an
out-of-order pop in other words). In this case the anchor style stack entry
is left untouched.
<H3>
<HR ALIGN=LEFT WIDTH="50%"></H3>
<B>text, entities</B>
<UL>These are basic content objects that get fed directly to the output.
In navigator the text is processed by doing line-breaking (entities have
been converted to text already by the parser). The line-breaking is controlled
by the margin settings and the list depth, the floating elements, the style
attributes (font size, etc.), the preformatted flag, the no-break flag
and so on.</UL>
<B>IMG, IMAGE</B>
<UL>Close tag is ignored.
<BR>Attributes:
<UL><B>ISMAP</B>
<BR><B>USEMAP</B>=url
<BR><B>ALIGN</B>=alignparam
<BR><B>SRC</B>=url [ whitespace is stripped ]
<BR><B>LOWSRC</B>=url
<BR><B>ALT</B>=string
<BR><B>WIDTH</B>=value-or-pct (pct of <TT>right-left</TT> width)
<BR><B>HEIGHT</B>=value-or-pct (pct of window height)
<BR><B>BORDER</B>=int [clamped: >= 0]
<BR><B>VSPACE</B>=int [clamped: >= 0]
<BR><B>HSPACE</B>=int [clamped: >= 0]
<BR><B>SUPPRESS</B>=true | false (only in blocked image layout???)</UL>
</UL>
<B>HR</B>
<UL>Closes the paragraph. If an open tag then does a conditional soft line
break. The rule inherits alignment from the parent container unless there
is no container (then it's centered) or if the tag defines it's own alignment.
After the object is inserted into the layout stream a soft line break is
inserted as well.
<BR>Attributes:
<UL><B>ALIGN</B>=divalign (sort of; in laytags.c it's divalign; in layhrule.c
it's left or right only)
<BR><B>SIZE</B>=int (1 to 100 inclusive)
<BR><B>WIDTH</B>=val-or-pct (pct of <TT>right-left</TT> width)
<BR><B>NOSHADE</B></UL>
</UL>
<B>BR</B>
<UL>Does an unconditional soft break. If clear is set then it will also
soft break until either the left or right or both margins are clear of
floating elements. Note that<FONT COLOR="#0000FF"> /BR == BR!</FONT>
<BR>Attributes:
<UL><B>CLEAR</B>=left | right | all | both</UL>
</UL>
<B>WBR</B>
<UL>Soft word break.
<BR>Attributes: none</UL>
<B>EMBED</B>
<UL>Close tag does nothing. Embed's operate inline just like images (they
don't close the paragraph).
<BR>Attributes:
<UL><B>HIDDEN</B>=no | false | off
<BR><B>ALIGN</B>=alignparam
<BR><B>SRC</B>=url
<BR><B>WIDTH</B>=val-or-pct (pct of <TT>right-left</TT> width)
<BR><B>HEIGHT</B>=val-of-pct; if val is &lt; 1 (sometimes) the element
gets HIDDEN automatically
<BR><B>BORDER</B>=int (unsupported by navigator)
<BR><B>VSPACE</B>=int [clamped: >= 0]
<BR><B>HSPACE</B>=int [clamped: >= 0]</UL>
</UL>
<B>NOEBMED</B>
<UL>Used when EMBED's are disabled. It is a container for regular content
that has no stylistic consequences (no line breaking, no style stack effect,
etc.).</UL>
<B>APPLET</B>
<UL>Applet tags don't nest (there is a notion of current_applet). The open
tag automatically closes an open applet tag.
<BR>Attributes:
<UL><B>ALIGN</B>=alignparam
<BR><B>CODE</B>=string
<BR><B>CODEBASE</B>=string
<BR><B>ARCHIVE</B>=string
<BR><B>MAYSCRIPT</B>
<BR><B>NAME</B>=string [clamped: white space is stripped out]
<BR><B>WIDTH</B>=value-or-pct [pct of right-left width; clamped: >= 1]
<BR><B>HEIGHT</B>=value-or-pct [pct of window height; clamped >= 1]
<BR><B>BORDER</B>=int [clamped: >= 0]
<BR><B>HSPACE</B>=int [clamped: >= 0]
<BR><B>VSPACE</B>=int [clamped: >= 0]</UL>
If no width is provided:
<UL>if a height was provided, use the height. Otherwise, use 90% of the
window width if percentage widths are allowed, otherwise use a value of
600.
<BR>&nbsp;</UL>
If no height is provided:
<UL>if a width was provided, use the width. Otherwise, use 50% of the window
height if percentage widths are allowed, otherwise use a value of 400.</UL>
If the applet is hidden, then the widht/height get forced to zero.</UL>
<B>PARAM</B>
<UL>The param tag is supported when contained by the APPLET tag or the
OBJECT tag. It has no stylistic consequences. The attribute values from
the tag are passed to the containing APPLET or OBJECT. Note that <FONT COLOR="#0000FF">/PARAM
== PARAM</FONT>.
<BR>Attributes:
<UL><B>NAME</B>=string [clamped: white space is stripped out]
<BR><B>VALUE</B>=string [clamped: white space is stripped out]</UL>
White space being stripped is done as follows: leading and trailing whitespace
is removed. Any embedded whitespace is left alone except if it's a non-space
whitespace in which case it is removed.</UL>
<B>OBJECT</B>
<UL>The open tag pushes an object onto the object stack. The close tag
pops from the object stack. I don't understand how the data stuff works.
<BR>Attributes:
<UL><B>CLASSID</B>=string (clsid:, java:, javaprogram:, javabean: are the
supported prefixes; maybe it's a url if no prefix shown?)
<BR><B>TYPE</B>=string (a mime type)
<BR><B>DATA</B>=string (data: prefix mentions a url)</UL>
There are more attributes that depend on the type of object being embedded
in the page. If the object is a java bean (?) then the applet parameters
are supported:
<UL>CLASSID
<BR>HIDDEN
<BR>ALIGN
<BR>CLASSID (instead of CODE)
<BR>CODEBASE
<BR>ARCHIVE
<BR>MAYSCRIPT
<BR>ID (applets use NAME)
<BR>WIDTH
<BR>HEIGHT
<BR>BORDER
<BR>HSPACE
<BR>VSPACE</UL>
</UL>
<B>MAP</B>
<UL>The open tag automatically closes an open map (maps don't nest). There
is no stylistic consequence of the map nor does it provide any visible
presentation in the normal layout case (an editor would do something different).
The map can be declared anywhere in the document.
<BR>Attributes:
<UL><B>NAME</B>=string [clamped: white space is stripped out]</UL>
</UL>
<B>AREA</B>
<UL>Does nothing if there is no current map or the tag is a close tag.
<BR>Attributes:
<UL><B>SHAPE</B>=default | rect | circle | poly | polygon
<BR><B>ALT</B>=string [clamped: newlines are stripped]
<BR><B>COORDS</B>=coord-list
<BR><B>HREF=</B>url
<UL><B>TARGET</B>=target (only if HREF is specified)</UL>
<B>SUPPRESS</B></UL>
</UL>
<B>SERVER</B>
<UL>A container for server-side javascript. Not evaluated by the client
(parsed and ignored). Note: The navigator parser doesn't expand entities
in a <B>SERVER </B>tag.</UL>
<B>SPACER</B>
<UL>Close tag is ignored. Open tag provides whitespace during layout: <B>TYPE</B>=line/vert/vertical
causes a conditional soft line break and then adds <B>SIZE </B>to the Y
layout coordinate. <B>TYPE</B>=word causes a conditional soft word break
and then adds <B>SIZE </B>to the X layout coordinate. <B>TYPE</B>=block
causes <FONT COLOR="#DD0000">blockish </FONT>layout stuff to happen.
<BR>Attributes:
<UL><B>TYPE</B>=line | vert | vertical | block (default: word)
<UL><B>ALIGN</B>=alignparam (these 3 params are only for <B>TYPE</B>=block)
<BR><B>WIDTH</B>=value-or-pct
<BR><B>HEIGHT</B>=value-or-pct</UL>
<B>SIZE</B>=int [clampled: >= 0]</UL>
</UL>
<H3>
<HR ALIGN=LEFT WIDTH="50%"></H3>
<B>SCRIPT</B>
<UL>Note: The navigator parser doesn't expand entities in a SCRIPT tag.
<BR>Attributes:
<UL><B>LANGUAGE</B>=LiveScript | Mocha | JavaScript1.1 | JavaScript1.2
<BR><B>TYPE</B>="text/javascript" | "text/css"
<BR><B>HREF</B>=url
<BR><B>ARCHIVE</B>=url
<BR><B>CODEBASE</B>=url
<BR><B>ID</B>=string
<BR><B>SRC</B>=url</UL>
</UL>
<B>NOSCRIPT</B>
<UL>Used when scripting is off or by backrev browsers. It is a container
that has no stylistic consequences.</UL>
<H3>
<HR ALIGN=LEFT WIDTH="50%"></H3>
<B>FORM&nbsp;</B>
<UL>Attributes:
<UL><B>ACTION</B>=href
<BR><B>ENCODING</B>=string
<BR><B>TARGET</B>=string
<BR><B>METHOD</B>=get | post</UL>
</UL>
<B>ISINDEX&nbsp;</B>
<UL>This tag is a shortcut for creating a form element with a submit button
and a single text field. If the PROMPT attribute is not present in the
tag then the value used is <B>"This is a searchable index. Enter search
keywords:"</B>.
<P>Attributes:
<UL><B>PROMPT</B>=string
<BR><B>ACTION</B>=href
<BR><B>ENCODING</B>=string
<BR><B>TARGET</B>=string
<BR><B>METHOD</B>=get | post</UL>
</UL>
<B>INPUT&nbsp;</B>
<UL>Attributes vary according to type:
<UL><B>TYPE</B>= text | radio | checkbox | hidden | submit | reset | password
| button | image | file | jot | readonly | object
<BR><B>NAME</B>= string
<BR>&nbsp;</UL>
<B>TYPE</B>=image
<UL>attributes are from the IMG tag (!)</UL>
<B>TYPE</B>= text | password | file
<UL>font style is forced to fixed
<BR><B>VALUE</B>= string
<BR><B>SIZE</B>= int (clamped; >= 1)
<BR><B>MAXLENGTH</B>= int (not clamped!)</UL>
<B>TYPE</B>= submit | reset | button | hidden | readonly
<UL><B>VALUE</B>=string; default if no value to the attribute varies according
to the type:
<UL><B>submit</B> -> "Submit Query"
<BR><B>reset</B> -> "Reset"
<BR>others -> "&nbsp; " (2 spaces)
<BR>Note also that the value has newlines stripped from it</UL>
<B>WIDTH</B>=int (clamped >=0 &amp;&amp; &lt;= 1000) (only for submit,
reset or button)
<BR><B>HEIGHT</B>=int (clamped >=0 &amp;&amp; &lt;= 1000) (only for submit,
reset or button)</UL>
<B>TYPE</B>=radio | checkbox
<UL><B>CHECKED</B> (flag - if present then set to true)
<BR><B>VALUE</B>= string (the default value is "on")</UL>
</UL>
<B>SELECT&nbsp;</B>
<UL>Attributes:
<UL><B>MULTIPLE</B> (boolean)
<BR><B>SIZE</B>= int (clamped >= 1)
<BR><B>NAME=</B> string
<BR><B>WIDTH</B>= int (clampled >= 0 &amp;&amp; &lt;= 1000)
<BR><B>HEIGHT</B>= int (clamped >= 0 &amp;&amp; &lt;= 1000; only examined
for single entry lists (!multiple || size==1))</UL>
</UL>
<B>OPTION&nbsp;</B>
<UL>Lives inside the SELECT tag (ignored otherwise).
<BR>Attributes:
<UL><B>VALUE</B>=string
<BR><B>SELECTED</B> boolean</UL>
</UL>
<B>TEXTAREA&nbsp;</B>
<UL>Attributes:
<UL><B>NAME</B>=string
<BR><B>ROWS</B>=int (clamped; >= 1)
<BR><B>COLS</B>=int (clamped; >= 1)
<BR><B>WRAP</B>= off | hard | soft (default is off; any value which is
not known turns into soft)</UL>
</UL>
<B>KEYGEN&nbsp;</B>
<UL>Attributes:
<UL><B>NAME</B>=string
<BR><B>CHALLENGE</B>=string
<BR><B>PQG</B>=string
<BR><B>KEYTYPE</B>=string</UL>
</UL>
<H3>
<HR ALIGN=LEFT WIDTH="50%"></H3>
<B>BASEFONT&nbsp;</B>
<UL>Sets the base font value which +/- size values in FONT tags are relative
to.
<BR>Attributes:
<UL>SIZE=+ int | - int | int (just like FONT)</UL>
</UL>
<H2>
<HR WIDTH="100%">Unsupported</H2>
<B>NSCP_CLOSE, NSCP_OPEN, NSCP_REBLOCK, MQUOTE, CELL, SUBDOC, CERTIFICATE,
INLINEINPUTTHICK, INLINEINPUTDOTTED, COLORMAP, HYPE, SPELL, NSDT</B>
<UL>These tags are unsupported because they are used internally by netscape
and are never seen in real content. If somebody does use them between 4.0
and magellan, tough beans. We never documented them so they lose.</UL>
</BODY>
</HTML>

180
layout/doc/overview.html Normal file
View file

@ -0,0 +1,180 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!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>Layout Documentation Overview</title>
</head>
<body>
<h1>Layout Documentation Overview</h1>
<blockquote> Authors: <br>
<ul>
<li>Marc Attinasi (attinasi@netscape.com)</li>
</ul>
History: <br>
<ul>
<li>12/17/2001 - created<br>
</li>
</ul>
</blockquote>
<h2>Background</h2>
The Layout module of Gecko has not been documented very well. This has lead
to some predictable problems: difficult maintenance, hard to get new people
involved in the module, problems assessing the risk of changes, hard to know
where bugs are likely to be in the source. &nbsp;One extreme result of the
lack of comprehensive has been an urge to rewrite some of the more impenetrable
parts of the layout component, the block and Line Layout areas. &nbsp;Rather
than throwing it all away and rewriting it, we have decided to put significant
effort into thoroughly documenting what we already have. this effort will
help us to understand what parts of the system we want to keep as-is, incrementally
revise, or wholesale rewrite. Additionally, we will make the code base more
accessible to new (and not-so-new) engineers.<br>
<br>
<h2>Strategy:</h2>
Documenting all of Block and Line layout is a large task, so it will be
divided up among knowledgeable and interested engineers. Progress will be
tracked in bugzilla <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=115310">
bug 115310</a>
. &nbsp;This document lays out the basic documentation scope and formatting
so that all of the individual contributions can be combined into a relatively
cohesive unit of linked documents. <br>
<br>
<h2>Scope:</h2>
The documentation will generally cover two levels of detail. There is room
for deviation from this as needed, but generally a High Level Design document
and a Detailed Design document will provide the necessary level of detail
for those trying to understand the system as a whole, and those trying to
get into the code.<br>
<br>
<h3>High Level Designs</h3>
High level designs provided an overview of the system being documented.
The general concept of the component is described, and the classes involved
are described briefly (no details of the class implementations). &nbsp;In
some cases the high level design vocabulary consists of other components
and not classes. &nbsp;The important thing is to describe the interactions
between the classes and/or components such that the reader gets an understanding
of which pieces talk to which other pieces, what kinds of data are shared
by various components or classes, how the data is modified and by whom, beginning
states and end states of a process, and external constraints or inputs into
the system begin described. <br>
<br>
A fundamental piece of the high-level design is the<b> data model</b>. This
is generally a graphical representation of the classes or components involved
in the system, showing the relationships between them in terms of has-a,
is-a, uses, owns, etc. the specific representation is not as important as
the content of the representation. For example, using UML or Booch notation
is fine, as is an ad-hoc diagram that shows the same types of information.<br>
<br>
Another important piece of the high-level design is a set of <b>use-cases</b>
that describe specific interaction that result from specific events in
the system. For example, we might want to show specifically what happens
when an attribute is changed on an element via the DOM. Use cases differ
from data models in that they show specific instances of objects or components,
actual data values where interesting or important, and often give a glimpse
into the algorithms employed. All of the components or objects in the use
cases must be documented in the data model.<br>
<b><br>
State Transition Diagrams</b> may be important to some systems, and they
should be documented in the high-level design as well. These should be described
in terms of the abstract states that the system may be in, not in terms of
how the state-machine is actually implemented.<br>
<br>
The high-level documents provide an overview of the components and classes
that make up a system. It can be used as a road map to the related detailed
design documents for the components and classes involved in the system. thus,
the classes, components, and algorithms referenced in the high-level design
document should be linked to the detailed design documents that correspond.
This link generally occurs at the first reference to the class or component,
but it can be provided in other contexts as well, for convenience to the reader.
&nbsp;Missing or invalid links are considered errors in the high-level design.
<br>
&nbsp;&nbsp; <br>
<h3>Detailed Designs</h3>
Detailed design documents provide specific information needed to implement
(or understand the implementation of) the components and classes described
in the high-level design. Users of the classes or components should also be
able to understand from the detailed design just how the classes, components
and API's are to be used. Special performance characteristics of methods or
interactions should be documented where pertinent.<br>
<br>
<h4>Public API</h4>
The public API of the component or class being documented is essential to
the detailed design. Each publicly accessible interface, method and data member
must be documented. Ideally this information is contained in the implementation
files for a class, interface or component. If this is the case, the actual
IDL or class header file can be used as the documentation for the public API.
This should be done as a link or embedded document to avoid the perpetual
need to keep the document up to date with the source file. &nbsp;Specific
items that are important to the description of the publicly available aspects
of the component, class, or interface include:<br>
<ul>
<li>entry-point semantics: what does the method do, or what does the data
member mean? Is the universe of expected clients limited or open (e.g.. who
can call it)?<br>
</li>
<li>preconditions: what are the legal states for the instance to be in
before the entry point is called? what are the legal values for the arguments?
what are the required states for the objects or components used in the entry-point?</li>
<li>postconditions: what is guaranteed when the entry-point is returned
from? what return values are legal? what is the status of the output arguments
for various return states?</li>
<li>special performance characteristics: if there are special concerns
about performance of the method, explain them. for example, is the method
O(n^2)? Is there considerable memory required? Is the method recursive?</li>
</ul>
Beyond the public interfaces, the private and protected methods need to
be documented as well. For protected methods and members, the expectations
of the subclasses must be made clear (e.g.. should the subclass call the
base class method? if so, when?) &nbsp;As with the public methods, the semantics,
preconditions, postconditions, and special performance considerations should
be described. Again, this may be by direct inclusion of the source code files
where appropriate.<br>
<br>
<h4>Algorithms</h4>
There is often a need to document specific algorithms used in methods and
functions. &nbsp;Generally, it is not a good idea to include this sort of
information in the source files, so they must be described fully in the detailed
design document. &nbsp;The extent of this information varies wildly from one
design to another. &nbsp;Be sure to include an Algorithms section to the
document when there are interesting or critical algorithms that the classes
or components employ. &nbsp;Spell out the algorithms in as much detail as
possible using pseudo-code or diagrams. Ideally, it should be possible to
implement the algorithm from the information in the design.<br>
<br>
<br>
Algorithms that involve several different components or object instances
require special attention. These algorithms tend to be more complex and more
difficult to completely specify. &nbsp;Start out by referring to the related
use cases in the high level design, and then drill down into the responsibilities
and requirements of the individual instances involved. &nbsp;Here, diagrams
and pseudo-code are indispensable in communicating how the algorithm is carried
out across the system.<br>
<h4></h4>
<h4> Tech Notes</h4>
The end of the detailed design document should contain a list of links to
Tech Notes. These will vary in depth and scope, but generally they provide
information geared toward helping developers work on the system. &nbsp;Tech
Notes might contain information about &nbsp;how code has been modified, how
a new feature was added, how to debug a certain class of problem, how to
use built-in debugging r logging facilities, or how to maintain or extend
unit tests. &nbsp;The Tech Notes should be stored in a publicly accessible
location, as a comment or attachment in a bugzilla bug, for example. &nbsp;The
text that holds the link should be descriptive of what the Tech Note addresses.<br>
<br>
</body>
</html>

BIN
layout/doc/raptor.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View file

@ -0,0 +1,212 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Layout Regression tests</title>
<style type="text/css">
body {font-family:arial}
.screen {background-color:silver; color:blue}
pre.screen {display:table-cell}
</style>
</head>
<body>
<h1>Table Regression Tests</h1>
<h6>Bernd Mielke</h6>
<h2>About This Document</h2>
<p>
This document describes my guerrilla approach to successfully running the table layout regression tests. It should encourage more people to run those tests.
<h2>Subject Overview</h2>
<p>
The table element and its children are one of the major layout components that can create some structure on the screen. They are widely (ab)used by page authors. Every small change in the table code can generate a bunch of bugzilla entries and a lot of seemingly unrelated dupes. With the high frequency of checkins in to the source tree it is difficult and time consuming to track the regression down to a single checkin. The risk of becoming very infamous can be reduced by running the layout regression tests.
<h2>Prerequisites</h2>
<p>
In order to run these tests, you will need to have:
<ol>
<li>a debug build with a working viewer, an optimized build will not work!
<li>a mozilla tree with the testfiles at <code>%MOZ_SRC%/layout/html/tests</code>,
<li> <code>DISABLE_TESTS</code> should not be defined,
<li>patience and time.
</ol>
<h2>Test Runs</h2>
<ul>
<li>Go to the <code>%MOZ_SRC%/layout/html/tests/block</code> directory.
<li> Avoid the nasty assertions to pop up by <code>set XPCOM_DEBUG_BREAK=warn</code>, the world would be a much better place if we could <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=152015">first fix those assertions</a>.
<li>The following shell scripts need a <code>sh</code> before the command under WinXX.
<li>Execute <code>rtest.sh baseline</code>
<li>Execute <code>rtest.sh verify&gt;outputfile.txt</code>
<li>Make a note which tests have failed (these are false positives. If you are in bad mood file a bug against Chris Waterson about them)
<li>you can grep the failures by:<br>
<code>grep 'rgd failed' &lt;outputfile.txt &gt;false_positive.txt</code>
<li> Make a copy of <code>gklayout.dll</code> and <code>gkcontent.dll</code> in the <code>dist</code> directory. If you would like to switch back, you will need them.
<li>Make your changes to the source, compile and install.
<li>execute in the <code>layout/html/tests/block</code> directory <code>rtest.sh verify &gt;regression.txt</code>
<li>Check how many tests have failed and analyse your results:
<ul>
<li>If the regression tests have failed at the same place as the previous diagnosed false positives =&gt; ignore
<ol>
<li>copy <code>rtest.sh</code> to <code>my_rtest.sh</code>
<li>create a new directory <code>my_files</code>.
<li>create in this directory a file <code>file_list.txt</code>, where you put the url's of your remaining test failures
<li>change <code>my_rtest.sh</code> to use only directory <code>my_files</code>
<li>go back to the original gklayout.dll and gkcontent.dll and repeat the regression test procedure on a much smaller set now.
</ol>
<li>Try to figure out what the other regressions are: Are they
improving the picture or are they regressions?
<li>Note the difficult to explain testfailures.
</ul>
<li> Change the source if necessary until the regression tests indicate that your patch does not hork the block and table layout
<li> Submit your patch and lists the remaining differences in the bug
</ul>
<p>Be prepared to cycle.
<h2>How the layout regression tests work</h2>
<p>First the URL's to test are red from <code>file_list.txt</code>.<p>
<table><caption>snippet from file_list.txt</caption><tr><td>
<pre>file:///s|/mozilla/layout/html/tests/table/dom/appendCells1.html
file:///s|/mozilla/layout/html/tests/table/dom/appendCellsRebuild1.html
file:///s|/mozilla/layout/html/tests/table/dom/appendCol1.html
file:///s|/mozilla/layout/html/tests/table/dom/appendCol2.html
file:///s|/mozilla/layout/html/tests/table/dom/appendColGroup1.html
file:///s|/mozilla/layout/html/tests/table/dom/appendRowsExpand1.html</pre>
</td></tr></table>
<p>The regression tests compare the frame tree dumps recorded at two different times. The URL's to test are red from <code>file_list.txt</code>
For every file in <code>file_list.txt</code>viewer takes the root frame and dumps the whole tree via
<a href="http://lxr.mozilla.org/seamonkey/search?string=nsFrame%3A%3ADumpRegression">
nsFrame::DumpRegression</a>.
<p>
The frame tree dumps are invoked by the <code>-o</code> switch to the <code>viewer</code> (see <a href="http://lxr.mozilla.org/seamonkey/ident?i=PrintHelpInfo">commandline arguments </a>).
When <code>-o</code> is specified together with a output directory for instance (<code>-o s:\mozilla\layout\html\tests\table\dom\</code>),
the frame trees are dumped to separate files in that directory for all URL's in <code>file_list.txt</code> (see:
<a href="http://lxr.mozilla.org/seamonkey/search?string=nsWebCrawler%3A%3ADumpRegression">
nsWebCrawler::DumpRegressionData</a>) .
<p>Their name is generated by replacing the old extension <code>.html</code> or <code>.xml</code> with <code>.rgd</code>. For <code>file:///s|/mozilla/layout/html/tests/table/dom/appendCells1.html</code> a file <code>appendCells1.rgd</code> will be created in the <code>s:\mozilla\layout\html\tests\table\dom\</code> directory.
<p>
There is a special type of frame dumps - the printing regression tests, they are invoked by the <code>-Prt</code> command line argument to the <code>viewer</code> and include first a display then a frame dump taking into account the printer pages. A typical beginning of a dump (<code>*.rgd</code> file) looks like:<p>
<pre class="screen">
&lt;frame va="15022440" type="Viewport(-1)" state="270340" parent="0"&gt;
&lt;view va="47171904"&gt;
&lt;/view&gt;
&lt;stylecontext va="15022232"&gt;
&lt;font serif 240 240 0 /&gt;
&lt;color data="-16777216"/&gt;
&lt;background data="0 2 3 -1 0 0 "/&gt;
&lt;spacing data="left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null left: 1[0x1]enum top: 1[0x1]enum right: 1[0x1]enum bottom: 1[0x1]enum left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0" /&gt;
&lt;list data="100 100 " /&gt;
&lt;position data="left: Auto top: Auto right: Auto bottom: Auto Auto 0[0x0]tw Null Auto 0[0x0]tw Null 0 Auto " /&gt;
&lt;text data="0 0 0 Normal Normal 0[0x0]tw Normal " /&gt;
&lt;textreset data="0 10[0xa]enum " /&gt;
&lt;display data="0 1 0 0 0 0 0 0 0 0 0 0 " /&gt;
&lt;visibility data="0 1 1.000000" /&gt;
&lt;table data="0 0 4 -1 1 " /&gt;
&lt;tableborder data="1 Null Null 0 2 " /&gt;
&lt;content data="0 0 0 Null " /&gt;
&lt;quotes data="0 " /&gt;
&lt;ui data="3 0 0 1 " /&gt;
&lt;uireset data="7 0 4" /&gt;
&lt;xul data="0 0 0 0 0 1 &lt;svg data="0 1.000000 1.000000 0 1.000000" /&gt;
&lt;/stylecontext&gt;</pre>
<p>The first run of the regression tests is started with the argument <code>baseline</code> and it creates the reference frame dumps.
<p>The <code>baseline</code> log will look like:
<pre class="screen">
Type Manifest File: C:\MOZ_SOUR\MOZILLA\MOZILLA\DIST\WIN32_D.OBJ\BIN\components\xpti.dat
nsNativeComponentLoader: autoregistering begins.
nsNativeComponentLoader: autoregistering succeeded
Going to create the event queue
WEBSHELL+ = 1
Note: verifyreflow is disabled
Note: styleverifytree is disabled
Note: frameverifytree is disabled
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendCells1.html: done loading (11810 msec)
appendCells1.rgd - being written
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendCellsRebuild1.html: done loading (1260 msec)
appendCellsRebuild1.rgd - being written
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendCol1.html: done loading (270 msec)
appendCol1.rgd - being written
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendCol2.html: done loading (220 msec)
appendCol2.rgd - being written
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendColGroup1.html: done loading (390 msec)
appendColGroup1.rgd - being written
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendRowsExpand1.html: done loading (220 msec)
appendRowsExpand1.rgd - being written
</pre>
<p>
The second run with the argument <code>verify</code> creates first the frame dumps in a subdirectory (<code>verify</code>) and <a href="http://lxr.mozilla.org/seamonkey/search?string=nsFrameUtil%3A%3ACompareTrees">compares</a> each frame dump with the corresponding reference frame dump. If they differ in critical points the test fails.
<p>A typical part of the <code>verify</code> log would look like:
<pre class="screen">
Type Manifest File: C:\MOZ_SOUR\MOZILLA\MOZILLA\DIST\WIN32_D.OBJ\BIN\components\xpti.dat
nsNativeComponentLoader: autoregistering begins.
nsNativeComponentLoader: autoregistering succeeded
Going to create the event queue
WEBSHELL+ = 1
Note: verifyreflow is disabled
Note: styleverifytree is disabled
Note: frameverifytree is disabled
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendCells1.html: done loading (2200 msec)
frame bbox mismatch: 0,285,930,435 vs. 0,285,1305,435
Node 1:
TableOuter(table)(1) 0x10004 0,285,930,435, |null attr|-16777216|left: 0[0x0]tw top: 0[0x0]tw right: 0[0x0]tw bottom: 0[0x0]tw left: 0[0x0]tw top: 0[0x0]tw right: 0[0x0]tw bottom: 0[0x0]tw left: 1[0x1]enum top: 1[0x1]enum right: 1[0x1]enum bottom: 1[0x1]enum left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0|100 100 |left: Inherit top: Inherit right: Inherit bottom: Inherit 0[0x0]tw 0[0x0]tw Null 0[0x0]tw 0[0x0]tw Null 0 Auto |0 0 0 Normal Normal 0[0x0]tw Normal |0 8 0 0 0 0 0 1 0 0 0 0 |0 0 4 -1 1 |0 0 0 Null
Node 2:
TableOuter(table)(1) 0x10004 0,285,1305,435, |null attr|-16777216|left: 0[0x0]tw top: 0[0x0]tw right: 0[0x0]tw bottom: 0[0x0]tw left: 0[0x0]tw top: 0[0x0]tw right: 0[0x0]tw bottom: 0[0x0]tw left: 1[0x1]enum top: 1[0x1]enum right: 1[0x1]enum bottom: 1[0x1]enum left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0|100 100 |left: Inherit top: Inherit right: Inherit bottom: Inherit 0[0x0]tw 0[0x0]tw Null 0[0x0]tw 0[0x0]tw Null 0 Auto |0 0 0 Normal Normal 0[0x0]tw Normal |0 8 0 0 0 0 0 1 0 0 0 0 |0 0 4 -1 1 |0 0 0 Null
frame bbox mismatch: 0,0,930,435 vs. 0,0,1305,435
Node 1:
Table(table)(1) 0x10004 0,0,930,435, |null attr|-16777216|left: Null top: 0[0x0]tw right: Null bottom: 0[0x0]tw left: Null top: Null right: Null bottom: Null left: 15[0xf]tw top: 15[0xf]tw right: 15[0xf]tw bottom: 15[0xf]tw left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0|100 100 |left: Auto top: Auto right: Auto bottom: Auto Auto 0[0x0]tw Null Auto 0[0x0]tw Null 2 Auto |0 0 0 Normal Normal 0[0x0]tw Normal |0 8 0 0 0 0 0 0 0 0 0 0 |0 8 4 -1 1 |0 0 0 Null
Node 2:
Table(table)(1) 0x10004 0,0,1305,435, |null attr|-16777216|left: Null top: 0[0x0]tw right: Null bottom: 0[0x0]tw left: Null top: Null right: Null bottom: Null left: 15[0xf]tw top: 15[0xf]tw right: 15[0xf]tw bottom: 15[0xf]tw left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0|100 100 |left: Auto top: Auto right: Auto bottom: Auto Auto 0[0x0]tw Null Auto 0[0x0]tw Null 2 Auto |0 0 0 Normal Normal 0[0x0]tw Normal |0 8 0 0 0 0 0 0 0 0 0 0 |0 8 4 -1 1 |0 0 0 Null
frame bbox mismatch: 45,15,840,405 vs. 45,15,1215,405
Node 1:
TableColGroup(table)(1) 0x80010004 45,15,840,405, |null attr|-16777216|left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null left: 1[0x1]enum top: 1[0x1]enum right: 1[0x1]enum bottom: 1[0x1]enum left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0|100 100 |left: Auto top: Auto right: Auto bottom: Auto Auto 0[0x0]tw Null Auto 0[0x0]tw Null 0 Auto |0 0 0 Normal Normal 0[0x0]tw Normal |0 12 0 0 0 0 0 0 0 0 0 0 |0 0 4 -1 1 |0 0 0 Null
Node 2:
TableColGroup(table)(1) 0x80010004 45,15,1215,405, |null attr|-16777216|left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null left: 1[0x1]enum top: 1[0x1]enum right: 1[0x1]enum bottom: 1[0x1]enum left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0|100 100 |left: Auto top: Auto right: Auto bottom: Auto Auto 0[0x0]tw Null Auto 0[0x0]tw Null 0 Auto |0 0 0 Normal Normal 0[0x0]tw Normal |0 12 0 0 0 0 0 0 0 0 0 0 |0 0 4 -1 1 |0 0 0 Null
frame state mismatch: 0x30010406 vs. 0x30010004
Node 1:
TableCol(table)(1) 0x30010406 0,0,0,0, |null attr|-16777216|left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null left: 1[0x1]enum top: 1[0x1]enum right: 1[0x1]enum bottom: 1[0x1]enum left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0|100 100 |left: Auto top: Auto right: Auto bottom: Auto Auto 0[0x0]tw Null Auto 0[0x0]tw Null 0 Auto |0 0 0 Normal Normal 0[0x0]tw Normal |0 11 0 0 0 0 0 0 0 0 0 0 |0 0 4 -1 1 |0 0 0 Null
Node 2:
TableCol(table)(1) 0x30010004 870,0,345,405, |null attr|-16777216|left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null left: 1[0x1]enum top: 1[0x1]enum right: 1[0x1]enum bottom: 1[0x1]enum left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0|100 100 |left: Auto top: Auto right: Auto bottom: Auto Auto 0[0x0]tw Null Auto 0[0x0]tw Null 0 Auto |0 0 0 Normal Normal 0[0x0]tw Normal |0 11 0 0 0 0 0 0 0 0 0 0 |0 0 4 -1 1 |0 0 0 Null
frame bbox mismatch: 0,0,0,0 vs. 870,0,345,405
Node 1:
TableCol(table)(1) 0x30010406 0,0,0,0, |null attr|-16777216|left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null left: 1[0x1]enum top: 1[0x1]enum right: 1[0x1]enum bottom: 1[0x1]enum left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0|100 100 |left: Auto top: Auto right: Auto bottom: Auto Auto 0[0x0]tw Null Auto 0[0x0]tw Null 0 Auto |0 0 0 Normal Normal 0[0x0]tw Normal |0 11 0 0 0 0 0 0 0 0 0 0 |0 0 4 -1 1 |0 0 0 Null
Node 2:
TableCol(table)(1) 0x30010004 870,0,345,405, |null attr|-16777216|left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null left: 1[0x1]enum top: 1[0x1]enum right: 1[0x1]enum bottom: 1[0x1]enum left: Null top: Null right: Null bottom: Null left: Null top: Null right: Null bottom: Null 1[0x1]enum 0|100 100 |left: Auto top: Auto right: Auto bottom: Auto Auto 0[0x0]tw Null Auto 0[0x0]tw Null 0 Auto |0 0 0 Normal Normal 0[0x0]tw Normal |0 11 0 0 0 0 0 0 0 0 0 0 |0 0 4 -1 1 |0 0 0 Null
regression test s:\mozilla\layout\html\tests\table\dom\verify\appendCells1.rgd failed
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendCellsRebuild1.html: done loading (390 msec)
044regression test s:\mozilla\layout\html\tests\table\dom\verify\appendCellsRebuild1.rgd passed
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendCol1.html: done loading (280 msec)
regression test s:\mozilla\layout\html\tests\table\dom\verify\appendCol1.rgd passed
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendCol2.html: done loading (220 msec)
regression test s:\mozilla\layout\html\tests\table\dom\verify\appendCol2.rgd passed
+++ file:///s|/mozilla/layout/html/tests/table/dom/appendColGroup1.html: done loading (220 msec)
regression test s:\mozilla\layout\html\tests\table\dom\verify\appendColGroup1.rgd passed
</pre>
<p>
The first regression test has failed and it is marked so.
<h2>Adding new regression tests</h2>
<p>
Once you have checked in the code:
<ul>
<li> please add your testcase for the bug to the regression tests.
<li>A testcase should only contain local files.
<li>Place the images in <code>table/images</code> (don't forget <code> cvs commit -kb </code>)
<li>and the testfile in the <code>table/bugs</code> directory.
<li>Update the <code>file_list<b>x</b>.txt</code> in order to include your file.
</ul>
<p>I would like to thank Chris Karnaze for his guidance and fantasai for his language support.
<div style="text-align:right"><i>&lt;regression.html&gt;&nbsp; &lt;Last updated:
2002-06-16 <a href="mailto:bernd.mielke@snafu.de">Bernd Mielke</a></i></div>
</body>
</html>

View file

@ -0,0 +1,888 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!-- vim:sw=2:et:ts=2:tw=72:
-->
<!DOCTYPE html public "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en-US">
<head>
<title>Table Reflow Tech Talk, 2002-08-05</title>
<style type="text/css">
html, body {
height: 100%;
overflow: visible;
}
body {
font-size: 1.4em;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-weight: bold;
background: white;
color: black;
}
h1, h2, p {
margin: 0;
}
h1 {
font: inherit;
font-size: 1.5em;
/* text-align: center; */
margin-bottom: 0.8em;
border-bottom: 0.1em solid #006;
color: #006;
}
h2 {
font: inherit;
font-size: 1.2em;
text-align: left;
margin: 0.15em 0;
}
ul {
padding: 0 0 0 1.4em;
margin: 0;
}
li { margin: 0;
margin-top: 0.5em;
padding: 0;
font-size: 1.0em;}
div.slide {
position: relative;
min-height: 100%;
}
div.nav {
/*
position: absolute;
top: 4px;
right: 4px;
*/
float: right;
margin: 4px;
}
div.nav :link, div.nav :visited, div.nav span {
text-decoration: none;
background: #006;
color: white;
padding: 0 0.4em 0.2em 0.4em;
line-height: 1.4em;
}
div.nav :link:hover, div.nav :visited:hover {
background: #00f;
}
table {
margin: auto;
}
table.box {
border-collapse: collapse;
border: 2px solid black;
box-sizing: border-box;
width:98%;
height:96%;
}
row {
border: 2px solid black;
}
row.title {
border: hidden;
}
table td {
/*text-align: center;*/
empty-cells: hide;
}
table td.box {
height:100%;
border: 2px solid black;
}
table td.title {
border-top: hidden;
border-right: hidden;
border-left: hidden;
font-size: .5em;
}
table td.title2 {
border-bottom: hidden;
border-right: hidden;
border-left: hidden;
font-size: .5em;
}
table.tree tr:not(.arrows) td {
font-family: monospace;
border: 0.1em solid;
font-size: .7em;
text-align:center;
}
table td.left-arrow {
text-align: right;
}
table td.right-arrow {
text-align: left;
}
table td.center-arrow {
text-align: center;
}
span.html {
color:purple;
}
table td.space {
width: 5%;
}
table td.frame {
width: 22%;
}
span.comment {
color: red;
}
</style>
</head>
<body>
<div class="slide" id="s0">
<div class="nav">
<a href="#s28">&lt;</a>
<a href="#s1">&gt;</a>
</div>
<table style="margin: auto"><tr><td>
<center>
<h1>Table Reflow Internals<br>Tech Talk</h1>
<p>Aug 5, 2002</p>
<p style="margin-top: 0.5em">Chris Karnaze</a></p>
</center>
</td></tr></table>
</div>
<div class="slide" id="s1">
<div class="nav">
<a href="#s0">&lt;</a>
<a href="#s2">&gt;</a>
</div>
<h1>Overview</h1>
<ul>
<li>Review of reflow</li>
<li>Table frames</li>
<li>Table reflow</li>
<li>Intro to paginated reflow</li>
<li>Table paginated reflow</li>
</ul>
</div>
<div class="slide" id="s2">
<div class="nav">
<a href="#s1">&lt;</a>
<a href="#s3">&gt;</a>
</div>
<h1>Review of Reflow</h1>
<ul>
<li>Reflow process starts when
<ul>
<li>An html document starts loading (the frame tree contains only viewport, scroll(s), canvas, html, body).</li>
<li>The initial chunk of an xml doc is loaded.</li>
<li>The initial chunk of an html doc (or a subsequent chunk of an xml doc) is loaded. The container posts a
dirty reflow command with itself as the target. </li>
<li>Content is inserted, appended, or deleted through the DOM. The container posts a dirty reflow command
with itself as the target.</li>
<li>Style changes through the DOM - javascript, browser change font (CTRL+/-), a preference changes, etc.</li>
</ul>
</li>
</ul>
</div>
<div class="slide" id="s3">
<div class="nav">
<a href="#s2">&lt;</a>
<a href="#s4">&gt;</a>
</div>
<h1>Review of Reflow</h1>
<ul>
<li>Reflow starts with pres shell
<ul>
<li>Which reflows the reflow root (usually the view port frame),</li>
<li>Which reflows it children, etc.</li>
</ul>
</li>
<li>Ususally it starts when the pres shell processes its queue of reflow commands.</li>
<li>The reflower
<ul>
<li>Positions reflowee (if it can) before actually reflowing in case views are involved
(e.g. absolutely positioned elements) </li>
<li>Reflows reflowee and passes a reflow state (in) and a reflow metrics (in/out)</li>
</ul>
</li>
</ul>
</div>
<div class="slide" id="s4">
<div class="nav">
<a href="#s3">&lt;</a>
<a href="#s5">&gt;</a>
</div>
<h1>Review of Reflow</h1>
<ul>
<li>The reflow state:
<ul>
<li>Is a node in a tree structurally equivalent to the frame tree of reflow participants</li>
<li>contains:
<ul>
<li>reflow type,</li>
<li>avail size,</li>
<li>various computed values,</li>
<li>resolved style structs</li>
<li>possible request for preferred size and more.</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<div class="slide" id="s5">
<div class="nav">
<a href="#s4">&lt;</a>
<a href="#s6">&gt;</a>
</div>
<h1>Review of Reflow</h1>
<ul>
</li>
<li>the reflow metrics contains:
<ul class=nested>
<li>max element size (if requested) - the minimum size it can be</li>
<li>preferred size (if requested) - the size it would like to be given no size constraints.</li>
<li>desired size - the size it would like to be given the avail size. This
is equivalent to preferred size if the avail size is not constrained.</li>
</ul>
</li>
</ul>
</div>
<div class="slide" id="s6">
<div class="nav">
<a href="#s5">&lt;</a>
<a href="#s7">&gt;</a>
</div>
<h1>Review of Reflow</h1>
<ul>
<li>The reflowee sets various sizes in the reflow metrics after (possibly) reflowing some or all of its children
which reflows it children, etc.</li>
<li>The reflowee returns a reflow status which indicates
<ul class=nested>
<li>if it is complete, and thus not have to continue (split)</li>
<li>breaking status (in the case of some inline frames)</li>
<li>if there is truncation (it can't fit in the space and can't split). This is just a convience mechanism.</li>
</ul>
</li>
</div>
<div class="slide" id="s7">
<div class="nav">
<a href="#s6">&lt;</a>
<a href="#s8">&gt;</a>
</div>
<h1>Kinds of reflows</h1>
<ul>
<li>Initial - reflowee's first reflow must be of this type (reflower's responsibility).</li>
<li>Resize - reflowee gets a change in available space only. Similar to initial, except it can reoccur.</li>
<li>Incremental - has a reflow path (tree) where each node has a command with a target frame, <br>reflow command types are:</li>
<ul class=nested>
<li>dirty - something changed inside a target (e.g. it gains, loses children)</li>
<li>style changed - a target changed stylisticly (recall, size is a style property)</li>
<li>content changed - a target's content changed (e.g. a text run)</li>
<li>user defined - currently only used for fixed positioned frames </li>
</ul>
</li>
</ul>
</div>
<div class="slide" id="s8">
<div class="nav">
<a href="#s7">&lt;</a>
<a href="#s9">&gt;</a>
</div>
<h1>Kinds of reflows</h1>
<ul>
<li>Incremental reflow (continued)
<ul class=nested>
<li>reflower not allowed to change available size of reflowee</li>
<li>reflow commands get coalesced to streamline processing</li>
</ul>
</li>
<li>Style change
<ul class=nested>
<li>a target changed stylistic if there is a target, otherwise every frame may need to respond</li>
<li>parent of target usually turns it into an incremental reflow with a style changed command type</li>
</ul>
</li>
</ul>
</div>
<div class="slide" id="s9">
<div class="nav">
<a href="#s8">&lt;</a>
<a href="#s10">&gt;</a>
</div>
<h1>Table Frames</h1>
<BR>
<table class="tree" width=90%>
<tr><td class=frame><td class=space style="width:2%"><td class=frame><td class=space style="width:2%">
<td class=frame><td class=space><td class=frame></tr>
<tr><td><td><td class=frame><td>
<td>nsTableOuter Frame<td><td></tr>
<tr class="arrows"><td><td><td><td class=left-arrow>&#x2199;<td><td class=right-arrow>&#x2198;</tr>
<tr><td><td><td>nsTable<BR>Frame<td><td><td><td>nsTableCaption<BR>Frame</tr>
<tr class="arrows"><td><td class=left-arrow>&#x2199;<td><td class=right-arrow>&#x2198;<td><td><td class=center-arrow>&darr;</tr>
<tr><td>nsTableCol<BR>GroupFrame<td><td><TD><td>nsTableRow<BR>GroupFrame<td><td>nsBlockFrame</tr>
<tr class="arrows"><td class=center-arrow>&darr;<td><td><td><td class=center-arrow>&darr;</tr>
<tr><td>nsTableCol<BR>Frame<td><TD><TD><td>nsTableRow<BR>Frame</tr>
<tr class="arrows"><td><td><td><td><td class=center-arrow>&darr;</tr>
<tr><td><td><td><TD><td>nsTableCell<BR>Frame</tr>
<tr class="arrows"><td><td><td><td><td class=center-arrow>&darr;</tr>
<tr><td><td><td><TD><td>nsBlock<BR>Frame</tr>
</table>
</div>
<div class="slide" id="s10">
<div class="nav">
<a href="#s9">&lt;</a>
<a href="#s11">&gt;</a>
</div>
<h1>Table Reflow</h1>
<ul>
<li>table wrapper reflows table and caption (if present)</li>
<li>Table reflows row groups in multiple passes</li>
<ul class=nested>
<li>Pass 1 - unconstrained width, height and requests max elem width.</li>
<li>The table figures out the column widths (balances) given the style width constraints
on the table, col groups, cols, cells the preferred and max element sizes of the cells
(from the pass 1 reflow), and considers colspans</li>
<li>Pass 2 - cell widths are constrained by the column widths (heights are only
constrained in paginated mode).</li>
</ul>
</li>
</ul>
</div>
<div class="slide" id="s11">
<div class="nav">
<a href="#s10">&lt;</a>
<a href="#s12">&gt;</a>
</div>
<h1>Table Reflow</h1>
<ul>
<li>Table reflows row groups (continued)</li>
<ul class=nested>
<li>The row group figures out the row heights given the its style height constraints
its rows and cells and the actual heights of its rows and cells from the pass 2 reflow</li>
<li>If the table has a style height, it allocates extra height to its row groups, rows and cells.</li>
</ul>
</li>
<li>In each pass, row groups reflow rows which reflow cells which reflow cell blocks</li>
</ul>
</div>
<div class="slide" id="s12">
<div class="nav">
<a href="#s11">&lt;</a>
<a href="#s13">&gt;</a>
</div>
<h1>Table Reflow Example</h1>
<table width=100%>
<tr>
<td width=100%>
<pre style="font-size:.6em;">
tblW 030176CC r=0 a=8940,UC c=0,0 cnt=429
tbl 030178C4 r=0 a=8940,UC c=4470,UC cnt=430
rowG 03017A7C r=0 a=UC,UC c=UC,UC cnt=431
row 03017C08 r=0 a=UC,UC c=UC,UC cnt=432
cell 03017DA8 r=0 a=UC,UC c=UC,UC cnt=433
block 03017E08 r=0 a=UC,UC c=UC,UC cnt=434
block 03017E08 d=870,300 me=480
cell 03017DA8 d=930,360 me=540
cell 0301A8CC r=0 a=UC,UC c=UC,UC cnt=436
block 0301A92C r=0 a=UC,UC c=UC,UC cnt=437
block 0301A92C d=1335,300 me=465
cell 0301A8CC d=1395,360 me=525
row 03017C08 d=UC,360
rowG 03017A7C d=UC,360
rowG 03017A7C r=2 a=4470,UC c=4470,UC cnt=442
row 03017C08 r=2 a=4470,UC c=4470,UC cnt=443
cell 03017DA8 r=2 a=1755,UC c=1695,UC cnt=444
block 03017E08 r=2 a=1695,UC c=1695,UC cnt=445
block 03017E08 d=1695,300
cell 03017DA8 d=1755,360
cell 0301A8CC r=2 a=2625,UC c=2565,UC cnt=446
block 0301A92C r=2 a=2565,UC c=2565,UC cnt=447
block 0301A92C d=2565,300
cell 0301A8CC d=2625,360
row 03017C08 d=4470,360
rowG 03017A7C d=4470,360
tbl 030178C4 d=4500,450
tblW 030176CC d=4500,450
<a href="frame_reflow_debug.html">frame reflow debugging</a> gives instructions
for turning this on.
</pre>
</td>
<td>
<pre style="font-size:.7em;">
&lt;<span class=html>table</span> width=300&gt;
&lt;<span class=html>tr</span>&gt;
&lt;<span class=html>td</span>&gt;foo&lt;<span class=html>/td</span>&gt;
&lt;<span class=html>td</span>&gt;bar zap&lt;<span class=html>/td</span>&gt;
&lt;<span class=html>/tr</span>&gt;
&lt;<span class=html>/table</span>&gt;
</pre>
<BR>
<BR>
<pre style="font-size:.7em;">
Key:
r = reflow reason,
0 (initial),
2 (resize)
a = avail w, h
c = computed w, h
d = desired w, h
me = max elem w
<pre>
</td>
</tr>
</table>
</div>
<div class="slide" id="s13">
<div class="nav">
<a href="#s12">&lt;</a>
<a href="#s14">&gt;</a>
</div>
<h1>Table reflow optimizations</h1>
<ul>
<li>If the table is already balanced, pass 1 constrains the width (like a normal pass 2) based on the current
column widths. The pass 2 will get skipped if the table doesn't need to rebalance. <!--<span class="comment">please clarify when can this happen</span>--></li>
<li>Nested table reflowed with an unconstrained width (i.e. an ancestor is doing a pass 1 reflow)
will only do a pass 1 reflow on its children</li>
<li>table wrapper caches last avail width and avoids reflowing children if resize reflow is the same as previous</li>
<li>Table caches max element, preferred widths in case they are requested and it isn't rebalanced</li>
<li>Cell caches prior avail width. if this doesn't change, the row may not have to reflow the cell</li>
</ul>
</div>
<div class="slide" id="s14">
<div class="nav">
<a href="#s13">&lt;</a>
<a href="#s15">&gt;</a>
</div>
<h1>Table incremental reflow</h1>
<ul>
<li>table wrapper is a target when a caption is added or removed (dirty) or the table or caption margin
changes (style changed).</li>
<li>Caption is a target when it changes stylistically (style changed).</li>
<li>Table, row group, row, col group, col is a target when a child is added or removed (dirty) or it changes
stylistically (style changed). <!--<span class="comment">please show how the column style change is propagated
into the cell reflows as the cells are reflowed by their parent rows and not cols</span>--></li>
<li>In the dirty cases, a target posted the reflow command in AppendFrames, InsertFrames, or DeleteFrame.</li>
</ul>
</div>
<div class="slide" id="s15">
<div class="nav">
<a href="#s14">&lt;</a>
<a href="#s16">&gt;</a>
</div>
<h1>Table incremental reflow</h1>
<ul>
<li>In the style change cases where a target is between the table and the cell, the table is told to rebalance.</li>
<li>When a target is the cell or below and the cell changes size, the row tells the table so it can decide if
it needs to rebalance</li>
<li>When a target is inside the cell's block, the cell
requests max element, preferred sizes of its block in case they change</li>
<li>After the table reflows the row group(s) containing the targets, if it rebalances, it then does a pass 2 reflow.</li>
</ul>
</div>
<div class="slide" id="s16">
<div class="nav">
<a href="#s15">&lt;</a>
<a href="#s17">&gt;</a>
</div>
<h1>Special height reflow</h1>
<ul>
<li>When there is a % height frame inside a cell without a computed height</li>
<ul class=nested>
<li>the frame will never get a chance to size based on the final cell height</li>
<li>in paginated mode when there is a height on the table, the table doesn't allocate
extra height to rows until after it does a pass 2 reflow and then it is too late</li>
</ul>
</li>
<li>This can be fixed by doing a special 3rd pass reflow</li>
</ul>
</div>
</div>
<div class="slide" id="s17">
<div class="nav">
<a href="#s16">&lt;</a>
<a href="#s18">&gt;</a>
</div>
<h1>Special Reflow Example</h1>
<table width=100% style="text-align:left;">
<tr>
<td>
<pre style="font-size:.7em; text-align:left;">
&lt;<span class=html>table</span> border=2 width=300&gt;
&lt;<span class=html>tr</span>&gt;
&lt;<span class=html>td</span>&gt;
This cell's width is
constrained by the
table and image widths.
Its exact height is
hard to determine.
&lt;<span class=html>/td</span>&gt;
&lt;<span class=html>td</span>&gt;
&lt;<span class=html>img</span> src=raptor.jpg
width=200 height=100%>
&lt;<span class=html>/td</span>&gt;
&lt;<span class=html>/tr</span>&gt;
&lt;<span class=html>/table</span>&gt;
</pre>
</td>
<td>
<table border=2 width=300>
<tr>
<td style="font-size:.7em;">This cell's width is constrained
by the table and image widths. <BR><BR>Its height
is hard to determine.<BR><BR> The image needs to be as high as the cell.
<td>
<!-- need ?raw=1 for lxr to cough up the image data, not a pretty page -->
<img src="raptor.jpg?raw=1"
width=200 height=100%>
</td>
</tr>
</table>
</tr>
</table>
</div>
<div class="slide" id="s18">
<div class="nav">
<a href="#s17">&lt;</a>
<a href="#s19">&gt;</a>
</div>
<h1>Special height reflow</h1>
<ul>
<li>The reflow state holds an observer and initiator</li>
<li>Observer</li>
<ul class=nested>
<li>is the table cell used as the height basis</li>
<li>set by frame without computed height in DidReflow</li>
<li>gives its block a computed height during 3rd pass</li>
<li>doesn't change height during 3rd pass</li>
</ul>
</li>
<li>Initiator</li>
<ul class=nested>
<li>is the table containing the observer</li>
<li>starts the 3rd pass reflow and sets a bit in the reflow state</li>
<li>gives its block a computed height during 3rd pass</li>
<li>could also be inside a cell which is an observer</li>
</ul>
</li>
</div>
<div class="slide" id="s19">
<div class="nav">
<a href="#s18">&lt;</a>
<a href="#s20">&gt;</a>
</div>
<h1>Special height reflow</h1>
<ul>
<li>Optimizations</li>
<ul class=nested>
<li>only frames needing 3rd pass actually get it</li>
<li>frames gettting a 3rd pass only get it once</li>
</ul>
</li>
</div>
<div class="slide" id="s20">
<div class="nav">
<a href="#s19">&lt;</a>
<a href="#s21">&gt;</a>
</div>
<h1>Intro to paginated reflow</h1>
<ul>
<li>When a reflowee's available height is constrained, it may not fit and need to either
split/continue on the next page, or start on the next page.</li>
<ul class=nested>
<li>If it can continue, it returns an incomplete status.</li>
<li>If it can't continue it returns a complete status.</li>
</ul>
</li>
<li>A continuation may also need to be continued</li>
<li>Continuations are linked together by prevInFlow and nextInFlow pointers </li>
</ul>
</div>
<div class="slide" id="s21">
<div class="nav">
<a href="#s20">&lt;</a>
<a href="#s22">&gt;</a>
</div>
<h1>Pagination Illustration</h1>
<table class=box style="height:500px">
<tr><td class="title">nsSimplePageSequence</td></tr>
<tr>
<td class=box>
<table class=box style="height:40%;">
<tr><td class=title>nsPageFrame</td></tr>
<tr>
<td class=box>
<table class=box style="height:100%;">
<tr><td class=title>nsPageContentFrame</td></tr>
<tr>
<td class=box style="border-bottom: hidden">
<table class=box style="height:100%; border-bottom:hidden">
<tr><td class=title>areaFrame (html)</td></tr>
<tr>
<td class=box>
<table class=box style="height:100%; border-bottom:hidden">
<tr><td class=title>blockFrame (body)</td></tr>
<tr>
<td class=box>
<table class=box style="height:100%; border-bottom:hidden">
<tr><td class=title>nsTableWrapperFrame</td></tr>
<tr>
<td class=box></td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</tr>
</table>
</td>
</tr>
</table>
<BR>
<table class=box style="height:40%;">
<tr>
<td class=box>
<table class=box style="height:100%;">
<tr>
<td class=box style="border-top: hidden">
<table class=box style="height:100%; border-top:hidden">
<tr>
<td class=box>
<table class=box style="height:100%; border-top:hidden">
<tr>
<td class=box>
<table class=box style="height:100%; border-top:hidden">
<tr>
<td class=box></td>
</tr>
<tr><td class=title2>nsTableWrapperFrame</td></tr>
</table>
</td>
</tr>
<tr><td class=title2>blockFrame (body)</td></tr>
</table>
</td>
</tr>
<tr><td class=title2>areaFrame (html)</td></tr>
</table>
</tr>
<tr><td class=title2>nsPageContentFrame continued</td></tr>
</table>
</td>
</tr>
<tr><td class=title2>nsPageFrame continued</td></tr>
</table>
</td>
</tr>
</table>
</div>
<div class="slide" id="s22">
<div class="nav">
<a href="#s21">&lt;</a>
<a href="#s23">&gt;</a>
</div>
<h1>Intro to paginated reflow</h1>
<ul>
<li>The page sequence starts with one page and reflows it. If the page is incomplete then the page sequence
creates a continuation for the page and sets it as the page's next sibling (it is also the page's
nextInFlow).</li>
<li>The page was incomplete because the page content was incomplete because the doc root was incomplete</li>
<li>The doc root was incomplete because it contained lines that didn't fit (or if it was mapped to a table,
because the table didn't fit) becacause a line contained something that didn't fit, etc.</li>
</ul>
</div>
<div class="slide" id="s23">
<div class="nav">
<a href="#s22">&lt;</a>
<a href="#s24">&gt;</a>
</div>
<h1>Intro to paginated reflow</h1>
<ul>
<li>If the reflowee is incomplete, the reflower has the responsiblity to:
<ul>
<li>Create a continuation for the reflowee</li>
<li>Ensure that the continuation gets put in the frame hierarchy at the right place
and gets reflowed at the right time.</li>
<li>Typically, a reflower accomplishes this by putting the continuation (c) on an overflow
list which the reflower owns. When the reflower's continuation gets reflowed, it takes c
and its siblings as children and reflows them.</li>
</ul>
</li>
<li>If the reflowee is complete, truncated (it didn't fit), not at the top of page,
the reflower should put the reflowee on its overflow list and return an incomplete status.</li>
</ul>
</div>
<div class="slide" id="s24">
<div class="nav">
<a href="#s23">&lt;</a>
<a href="#s25">&gt;</a>
</div>
<h1>Intro to paginated reflow</h1>
<ul>
<li>Special assumptions
<ul>
<li>There are only initial and (possibly) resize reflows. Incremental
and style change reflows are not allowed.</li>
<li>Multiple resize reflows may be necessary (e.g. a child is truncated and gets reflowed on a
subsequent page) but they should not change the available width from the last time.</li>
<li>Multiple resize reflows may require special handling if a frame split previously. It may need
to "pull up" children from a continuation.</li>
</ul>
</li>
</ul>
</div>
<div class="slide" id="s25">
<div class="nav">
<a href="#s24">&lt;</a>
<a href="#s26">&gt;</a>
</div>
<h1>Table paginated reflow</h1>
<ul>
<li>The block containing the table wrapper reflows it. If it is incomplete, the block will
<ul>
<li>create a continuation for the table wrapper (which also creates a continuation for the table).</li>
<li>put the continuation on a new line and place that line on its overflow lines property.</li>
</ul>
</li>
<li>The table wrapper reflows the table and just returns the status of the table.</li>
<li>The table does a pass 1 reflow and balances. If it is incomplete,</li>
<ul>
<li>it will become the first-in-flow</li>
<li>it will be the only frame among its continuations to ever balance or calc the cell map, and it only
does this once</li>
</ul>
</li>
</ul>
</div>
<div class="slide" id="s26">
<div class="nav">
<a href="#s25">&lt;</a>
<a href="#s27">&gt;</a>
</div>
<h1>Table paginated reflow</h1>
<ul>
<li>The table does a pass 2 reflow constraining both avail heights and widths. If a row group is incomplete, the table
<ul>
<li>creates a continuation for the row group</li>
<li>puts the continuation in its overflow frames property</li>
</ul>
</li>
<li>What follows only applies during the pass 2 reflow.</li>
<li>The row group</li>
<ul>
<li>reflows all of its rows with unconstrained heights and calculates the row heights,</li>
<li>figures out which row falls on a page boundary and reflows it with a constrained height. If there
will be a pass 3 reflow then this should (bug) happen at that time instead.</li>
</ul>
</li>
</ul>
</div>
<div class="slide" id="s27">
<div class="nav">
<a href="#s26">&lt;</a>
<a href="#s28">&gt;</a>
</div>
<h1>Table paginated reflow</h1>
<ul>
<li>The row group (continued)</li>
<ul>
<li>creates a continuation for the incomplete row (which also creates continuations for all of its cells
and all of the cell blocks)</li>
<li>puts the continuation in its overflow frames property. If the row was truncated and not top of page,
the row is put in the overflow frames property.
</ul>
</li>
</ul>
</div>
<div class="slide" id="s28">
<div class="nav">
<a href="#s27">&lt;</a>
<a href="#s0">&gt;</a>
</div>
<h1>Table paginated reflow</h1>
<ul>
<li>The row and cells (getting the constrained height reflow) just reflow their children with a constrained height.
They don't need an overflow list for continued children because the continuations were created when the
row group created the row's continutation.</li>
<li>A cell is incomplete because its block is incomplete. The block uses the overflow lines mechanism
(mentioned above) for its continued children</li>
</li>
<li>There are two splitting scenarios for a table
<ul>
<li>An incomplete cells block causes the cell, row, row group, table, table wrapper to
be incomplete</li>
<li>A truncated row or a row that started too far down the page causes the row group,
table, table wrapper to be incomplete.</li>
</ul>
</li>
</ul>
</div>
</body>
</html>