layout/doc/DD-SpaceManager.html

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/doc/DD-SpaceManager.html	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,743 @@
     1.4 +<!-- This Source Code Form is subject to the terms of the Mozilla Public
     1.5 +   - License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 +   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
     1.7 +
     1.8 +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
     1.9 +<html>
    1.10 +<head>
    1.11 +          
    1.12 +  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
    1.13 +  <title>Detailed Design Template</title>
    1.14 +</head>
    1.15 +  <body>
    1.16 + 
    1.17 +<h1><font color="#cc0000">Gecko Layout Detailed Design Document</font></h1>
    1.18 + 
    1.19 +<h1>Space Manager Detailed Design</h1>
    1.20 + 
    1.21 +<h2>Overview</h2>
    1.22 +<p>
    1.23 +  The Space Manager and related classes and structures are an important of
    1.24 + the Gecko Layout system, specifically Block Layout. &nbsp;See the High Level
    1.25 + Design document for an overview of the Space Manager, and as an introduction
    1.26 + to the classes, structures and algorithms container in this, the Detailed
    1.27 + Design Document.
    1.28 +</p>
    1.29 + 
    1.30 +
    1.31 + 
    1.32 +<hr width="100%" size="2"> 
    1.33 +<h2>nsSpaceManager</h2>
    1.34 +<p>
    1.35 +   The Space Manager is the central class is a group of classes that manage
    1.36 + the occupied and available space that exists in horizontal bands across
    1.37 +a  canvas. &nbsp;The primary goal of the Space Manager is to provide information
    1.38 + about those bands of space to support the CSS notion of floated elements.
    1.39 +</p>
    1.40 + 
    1.41 +<p>
    1.42 +  There are three important parts to the Space Manager API: the parts that 
    1.43 +deal with the coordinate space of the Space Manager, the parts that deal with
    1.44 +the regions managed by the Space Manager, and the parts that manage float
    1.45 +impact intervals.
    1.46 +</p>
    1.47 + 
    1.48 +<p>
    1.49 +  The class nsSpaceManager is declared in the file <a href="http://lxr.mozilla.org/seamonkey/source/layout/base/src/nsSpaceManager.h">
    1.50 +  nsSpaceManger.h</a>
    1.51 +  . &nbsp;The class is only used in the layout module and cannot be exported
    1.52 + outside of that module (nor does it need to be). &nbsp;It is not a general
    1.53 + purpose class, and is not intended to be subclasses<font color="#cc0000">
    1.54 + .</font>
    1.55 +</p>
    1.56 + 
    1.57 +<p>
    1.58 +  Here is the class declaration, taken from the source file as of 01.08.02
    1.59 +</p>
    1.60 + 
    1.61 +
    1.62 + 
    1.63 +<pre>/**
    1.64 + * Class for dealing with bands of available space. The space manager
    1.65 + * defines a coordinate space with an origin at (0, 0) that grows down
    1.66 + * and to the right.
    1.67 + */
    1.68 +class nsSpaceManager {
    1.69 +public:
    1.70 +  nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
    1.71 +  ~nsSpaceManager();
    1.72 +
    1.73 +  void* operator new(size_t aSize);
    1.74 +  void operator delete(void* aPtr, size_t aSize);
    1.75 +
    1.76 +  static void Shutdown();
    1.77 +
    1.78 +  /*
    1.79 +   * Get the frame that's associated with the space manager. This frame
    1.80 +   * created the space manager, and the world coordinate space is
    1.81 +   * relative to this frame.
    1.82 +   *
    1.83 +   * You can use QueryInterface() on this frame to get any additional
    1.84 +   * interfaces.
    1.85 +   */
    1.86 +  nsIFrame* GetFrame() const { return mFrame; }
    1.87 +
    1.88 +  /**
    1.89 +   * Translate the current origin by the specified (dx, dy). This
    1.90 +   * creates a new local coordinate space relative to the current
    1.91 +   * coordinate space.
    1.92 +   */
    1.93 +  void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
    1.94 +
    1.95 +  /**
    1.96 +   * Returns the current translation from local coordinate space to
    1.97 +   * world coordinate space. This represents the accumulated calls to
    1.98 +   * Translate().
    1.99 +   */
   1.100 +  void GetTranslation(nscoord&amp; aX, nscoord&amp; aY) const { aX = mX; aY = mY; }
   1.101 +
   1.102 +  /**
   1.103 +   * Returns the y-most of the bottommost band or 0 if there are no bands.
   1.104 +   *
   1.105 +   * @return  PR_TRUE if there are bands and PR_FALSE if there are no bands
   1.106 +   */
   1.107 +  PRBool YMost(nscoord&amp; aYMost) const;
   1.108 +
   1.109 +  /**
   1.110 +   * Returns a band starting at the specified y-offset. The band data
   1.111 +   * indicates which parts of the band are available, and which parts
   1.112 +   * are unavailable
   1.113 +   *
   1.114 +   * The band data that is returned is in the coordinate space of the
   1.115 +   * local coordinate system.
   1.116 +   *
   1.117 +   * The local coordinate space origin, the y-offset, and the max size
   1.118 +   * describe a rectangle that's used to clip the underlying band of
   1.119 +   * available space, i.e.
   1.120 +   * {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
   1.121 +   * coordinate space
   1.122 +   *
   1.123 +   * @param   aYOffset the y-offset of where the band begins. The coordinate is
   1.124 +   *            relative to the upper-left corner of the local coordinate space
   1.125 +   * @param   aMaxSize the size to use to constrain the band data
   1.126 +   * @param   aBandData [in,out] used to return the list of trapezoids that
   1.127 +   *            describe the available space and the unavailable space
   1.128 +   * @return  NS_OK if successful and NS_ERROR_FAILURE if the band data is not
   1.129 +   *            not large enough. The 'count' member of the band data struct
   1.130 +   *            indicates how large the array of trapezoids needs to be
   1.131 +   */
   1.132 +  nsresult GetBandData(nscoord       aYOffset,
   1.133 +                       const nsSize&amp; aMaxSize,
   1.134 +                       nsBandData&amp;   aBandData) const;
   1.135 +
   1.136 +  /**
   1.137 +   * Add a rectangular region of unavailable space. The space is
   1.138 +   * relative to the local coordinate system.
   1.139 +   *
   1.140 +   * The region is tagged with a frame
   1.141 +   *
   1.142 +   * @param   aFrame the frame used to identify the region. Must not be NULL
   1.143 +   * @param   aUnavailableSpace the bounding rect of the unavailable space
   1.144 +   * @return  NS_OK if successful
   1.145 +   *          NS_ERROR_FAILURE if there is already a region tagged with aFrame
   1.146 +   */
   1.147 +  nsresult AddRectRegion(nsIFrame*     aFrame,
   1.148 +                         const nsRect&amp; aUnavailableSpace);
   1.149 +
   1.150 +  /**
   1.151 +   * Resize the rectangular region associated with aFrame by the specified
   1.152 +   * deltas. The height change always applies to the bottom edge or the existing
   1.153 +   * rect. You specify whether the width change applies to the left or right edge
   1.154 +   *
   1.155 +   * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
   1.156 +   * tagged with aFrame
   1.157 +   */
   1.158 +  enum AffectedEdge {LeftEdge, RightEdge};
   1.159 +  nsresult ResizeRectRegion(nsIFrame*    aFrame,
   1.160 +                            nscoord      aDeltaWidth,
   1.161 +                            nscoord      aDeltaHeight,
   1.162 +                            AffectedEdge aEdge = RightEdge);
   1.163 +
   1.164 +  /**
   1.165 +   * Offset the region associated with aFrame by the specified amount.
   1.166 +   *
   1.167 +   * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
   1.168 +   * tagged with aFrame
   1.169 +   */
   1.170 +  nsresult OffsetRegion(nsIFrame* aFrame, nscoord dx, nscoord dy);
   1.171 +
   1.172 +  /**
   1.173 +   * Remove the region associated with aFrane.
   1.174 +   *
   1.175 +   * Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
   1.176 +   * tagged with aFrame
   1.177 +   */
   1.178 +  nsresult RemoveRegion(nsIFrame* aFrame);
   1.179 +
   1.180 +  /**
   1.181 +   * Clears the list of regions representing the unavailable space.
   1.182 +   */
   1.183 +  void ClearRegions();
   1.184 +
   1.185 +  /**
   1.186 +   * Methods for dealing with the propagation of float damage during
   1.187 +   * reflow.
   1.188 +   */
   1.189 +  PRBool HasFloatDamage()
   1.190 +  {
   1.191 +    return !mFloatDamage.IsEmpty();
   1.192 +  }
   1.193 +
   1.194 +  void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
   1.195 +  {
   1.196 +    mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
   1.197 +  }
   1.198 +
   1.199 +  PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
   1.200 +  {
   1.201 +    return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
   1.202 +  }
   1.203 +
   1.204 +#ifdef DEBUG
   1.205 +  /**
   1.206 +   * Dump the state of the spacemanager out to a file
   1.207 +   */
   1.208 +  nsresult List(FILE* out);
   1.209 +
   1.210 +  void SizeOf(nsISizeOfHandler* aHandler, uint32_t* aResult) const;
   1.211 +#endif
   1.212 +
   1.213 +private:
   1.214 +  // Structure that maintains information about the region associated
   1.215 +  // with a particular frame
   1.216 +  struct FrameInfo {
   1.217 +    nsIFrame* const mFrame;
   1.218 +    nsRect          mRect;       // rectangular region
   1.219 +    FrameInfo*      mNext;
   1.220 +
   1.221 +    FrameInfo(nsIFrame* aFrame, const nsRect&amp; aRect);
   1.222 +#ifdef NS_BUILD_REFCNT_LOGGING
   1.223 +    ~FrameInfo();
   1.224 +#endif
   1.225 +  };
   1.226 +
   1.227 +  // Doubly linked list of band rects
   1.228 +  struct BandRect : PRCListStr {
   1.229 +    nscoord   mLeft, mTop;
   1.230 +    nscoord   mRight, mBottom;
   1.231 +    int32_t   mNumFrames;    // number of frames occupying this rect
   1.232 +    union {
   1.233 +      nsIFrame*    mFrame;   // single frame occupying the space
   1.234 +      nsVoidArray* mFrames;  // list of frames occupying the space
   1.235 +    };
   1.236 +
   1.237 +    BandRect(nscoord aLeft, nscoord aTop,
   1.238 +             nscoord aRight, nscoord aBottom,
   1.239 +             nsIFrame*);
   1.240 +    BandRect(nscoord aLeft, nscoord aTop,
   1.241 +             nscoord aRight, nscoord aBottom,
   1.242 +             nsVoidArray*);
   1.243 +    ~BandRect();
   1.244 +
   1.245 +    // List operations
   1.246 +    BandRect* Next() const {return (BandRect*)PR_NEXT_LINK(this);}
   1.247 +    BandRect* Prev() const {return (BandRect*)PR_PREV_LINK(this);}
   1.248 +    void      InsertBefore(BandRect* aBandRect) {PR_INSERT_BEFORE(aBandRect, this);}
   1.249 +    void      InsertAfter(BandRect* aBandRect) {PR_INSERT_AFTER(aBandRect, this);}
   1.250 +    void      Remove() {PR_REMOVE_LINK(this);}
   1.251 +
   1.252 +    // Split the band rect into two vertically, with this band rect becoming
   1.253 +    // the top part, and a new band rect being allocated and returned for the
   1.254 +    // bottom part
   1.255 +    //
   1.256 +    // Does not insert the new band rect into the linked list
   1.257 +    BandRect* SplitVertically(nscoord aBottom);
   1.258 +
   1.259 +    // Split the band rect into two horizontally, with this band rect becoming
   1.260 +    // the left part, and a new band rect being allocated and returned for the
   1.261 +    // right part
   1.262 +    //
   1.263 +    // Does not insert the new band rect into the linked list
   1.264 +    BandRect* SplitHorizontally(nscoord aRight);
   1.265 +
   1.266 +    // Accessor functions
   1.267 +    PRBool  IsOccupiedBy(const nsIFrame*) const;
   1.268 +    void    AddFrame(const nsIFrame*);
   1.269 +    void    RemoveFrame(const nsIFrame*);
   1.270 +    PRBool  HasSameFrameList(const BandRect* aBandRect) const;
   1.271 +    int32_t Length() const;
   1.272 +  };
   1.273 +
   1.274 +  // Circular linked list of band rects
   1.275 +  struct BandList : BandRect {
   1.276 +    BandList();
   1.277 +
   1.278 +    // Accessors
   1.279 +    PRBool    IsEmpty() const {return PR_CLIST_IS_EMPTY((PRCListStr*)this);}
   1.280 +    BandRect* Head() const {return (BandRect*)PR_LIST_HEAD(this);}
   1.281 +    BandRect* Tail() const {return (BandRect*)PR_LIST_TAIL(this);}
   1.282 +
   1.283 +    // Operations
   1.284 +    void      Append(BandRect* aBandRect) {PR_APPEND_LINK(aBandRect, this);}
   1.285 +
   1.286 +    // Remove and delete all the band rects in the list
   1.287 +    void      Clear();
   1.288 +  };
   1.289 +
   1.290 +
   1.291 +  FrameInfo* GetFrameInfoFor(nsIFrame* aFrame);
   1.292 +  FrameInfo* CreateFrameInfo(nsIFrame* aFrame, const nsRect&amp; aRect);
   1.293 +  void       DestroyFrameInfo(FrameInfo*);
   1.294 +
   1.295 +  void       ClearFrameInfo();
   1.296 +  void       ClearBandRects();
   1.297 +
   1.298 +  BandRect*  GetNextBand(const BandRect* aBandRect) const;
   1.299 +  void       DivideBand(BandRect* aBand, nscoord aBottom);
   1.300 +  PRBool     CanJoinBands(BandRect* aBand, BandRect* aPrevBand);
   1.301 +  PRBool     JoinBands(BandRect* aBand, BandRect* aPrevBand);
   1.302 +  void       AddRectToBand(BandRect* aBand, BandRect* aBandRect);
   1.303 +  void       InsertBandRect(BandRect* aBandRect);
   1.304 +
   1.305 +  nsresult   GetBandAvailableSpace(const BandRect* aBand,
   1.306 +                                   nscoord         aY,
   1.307 +                                   const nsSize&amp;   aMaxSize,
   1.308 +                                   nsBandData&amp;     aAvailableSpace) const;
   1.309 +
   1.310 +  nsIFrame* const mFrame;     // frame associated with the space manager
   1.311 +  nscoord         mX, mY;     // translation from local to global coordinate space
   1.312 +  BandList        mBandList;  // header/sentinel for circular linked list of band rects
   1.313 +  FrameInfo*      mFrameInfoMap;
   1.314 +  nsIntervalSet   mFloatDamage;
   1.315 +
   1.316 +  static int32_t sCachedSpaceManagerCount;
   1.317 +  static void* sCachedSpaceManagers[NS_SPACE_MANAGER_CACHE_SIZE];
   1.318 +
   1.319 +  nsSpaceManager(const nsSpaceManager&amp;);  // no implementation
   1.320 +  void operator=(const nsSpaceManager&amp;);  // no implementation
   1.321 +};
   1.322 +
   1.323 +</pre>
   1.324 + 
   1.325 +<h3>Public API</h3>
   1.326 + 
   1.327 +<h4>Life Cycle:</h4>
   1.328 +<p>
   1.329 +  The Constructor requires a Presentation Shell, used for arena allocations
   1.330 + mostly, and a frame that this Space Manager is rooted on. &nbsp;The coordinate
   1.331 + space of this Space Manager is relative to the frame passed in to the constructor.
   1.332 +</p>
   1.333 + 
   1.334 +<pre>  nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
   1.335 +  ~nsSpaceManager();
   1.336 +</pre>
   1.337 +<p>
   1.338 +  Operators 'new' and 'delete' are overridden to support a recycler. &nbsp;Space
   1.339 + Manager instances come and go pretty frequently, and this recycler prevents
   1.340 + excessive heap allocations and the performance penalties associated with
   1.341 +it. The #define NS_SPACE_MANAGER_CACHE_SIZE is used to control the number
   1.342 +of Space Manager instances that can be present in the recycler, currently
   1.343 +4. &nbsp;If more than NS_SPACE_MANAGER_CACHE_SIZE are allocated at a time,
   1.344 +then standard allocation is used.
   1.345 +</p>
   1.346 + 
   1.347 +<pre>
   1.348 +  void* operator new(size_t aSize);
   1.349 +  void operator delete(void* aPtr, size_t aSize);
   1.350 +
   1.351 +</pre>
   1.352 +<p>
   1.353 + A Static method is used to shutdown the Space Manager recycling. &nbsp;This 
   1.354 +method deletes all of the Space Mangers inthe recycler,and prevents further 
   1.355 +recycling. &nbsp;It is meant to be called only when the layout module is being
   1.356 +terminated.
   1.357 +</p>
   1.358 + 
   1.359 +<pre>  static void Shutdown();
   1.360 +
   1.361 +</pre>
   1.362 + 
   1.363 +<h4>Origin / Coordinate Space Translation</h4>
   1.364 + 
   1.365 +<pre>  /**
   1.366 +   * Translate the current origin by the specified (dx, dy). This
   1.367 +   * creates a new local coordinate space relative to the current
   1.368 +   * coordinate space.
   1.369 +   */
   1.370 +  void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
   1.371 +
   1.372 +  /**
   1.373 +   * Returns the current translation from local coordinate space to
   1.374 +   * world coordinate space. This represents the accumulated calls to
   1.375 +   * Translate().
   1.376 +   */
   1.377 +  void GetTranslation(nscoord&amp; aX, nscoord&amp; aY) const { aX = mX; aY = mY; }
   1.378 +
   1.379 +  /**
   1.380 +   * Returns the y-most of the bottommost band or 0 if there are no bands.
   1.381 +   *
   1.382 +   * @return  PR_TRUE if there are bands and PR_FALSE if there are no bands
   1.383 +   */
   1.384 +  PRBool YMost(nscoord&amp; aYMost) const;
   1.385 +</pre>
   1.386 + 
   1.387 +<h4>Region Management</h4>
   1.388 + 
   1.389 +<pre>  /**
   1.390 +   * Returns a band starting at the specified y-offset. The band data
   1.391 +   * indicates which parts of the band are available, and which parts
   1.392 +   * are unavailable
   1.393 +   *
   1.394 +   * The band data that is returned is in the coordinate space of the
   1.395 +   * local coordinate system.
   1.396 +   *
   1.397 +   * The local coordinate space origin, the y-offset, and the max size
   1.398 +   * describe a rectangle that's used to clip the underlying band of
   1.399 +   * available space, i.e.
   1.400 +   * {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
   1.401 +   * coordinate space
   1.402 +   *
   1.403 +   * @param   aYOffset the y-offset of where the band begins. The coordinate is
   1.404 +   *            relative to the upper-left corner of the local coordinate space
   1.405 +   * @param   aMaxSize the size to use to constrain the band data
   1.406 +   * @param   aBandData [in,out] used to return the list of trapezoids that
   1.407 +   *            describe the available space and the unavailable space
   1.408 +   * @return  NS_OK if successful and NS_ERROR_FAILURE if the band data is not
   1.409 +   *            not large enough. The 'count' member of the band data struct
   1.410 +   *            indicates how large the array of trapezoids needs to be
   1.411 +   */
   1.412 +  nsresult GetBandData(nscoord       aYOffset,
   1.413 +                       const nsSize&amp; aMaxSize,
   1.414 +                       nsBandData&amp;   aBandData) const;
   1.415 +
   1.416 +  /**
   1.417 +   * Add a rectangular region of unavailable space. The space is
   1.418 +   * relative to the local coordinate system.
   1.419 +   *
   1.420 +   * The region is tagged with a frame
   1.421 +   *
   1.422 +   * @param   aFrame the frame used to identify the region. Must not be NULL
   1.423 +   * @param   aUnavailableSpace the bounding rect of the unavailable space
   1.424 +   * @return  NS_OK if successful
   1.425 +   *          NS_ERROR_FAILURE if there is already a region tagged with aFrame
   1.426 +   */
   1.427 +  nsresult AddRectRegion(nsIFrame*     aFrame,
   1.428 +                         const nsRect&amp; aUnavailableSpace);
   1.429 +
   1.430 +  /**
   1.431 +   * Resize the rectangular region associated with aFrame by the specified
   1.432 +   * deltas. The height change always applies to the bottom edge or the existing
   1.433 +   * rect. You specify whether the width change applies to the left or right edge
   1.434 +   *
   1.435 +   * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
   1.436 +   * tagged with aFrame
   1.437 +   */
   1.438 +  enum AffectedEdge {LeftEdge, RightEdge};
   1.439 +  nsresult ResizeRectRegion(nsIFrame*    aFrame,
   1.440 +                            nscoord      aDeltaWidth,
   1.441 +                            nscoord      aDeltaHeight,
   1.442 +                            AffectedEdge aEdge = RightEdge);
   1.443 +
   1.444 +  /**
   1.445 +   * Offset the region associated with aFrame by the specified amount.
   1.446 +   *
   1.447 +   * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
   1.448 +   * tagged with aFrame
   1.449 +   */
   1.450 +  nsresult OffsetRegion(nsIFrame* aFrame, nscoord dx, nscoord dy);
   1.451 +
   1.452 +  /**
   1.453 +   * Remove the region associated with aFrane.
   1.454 +   *
   1.455 +   * Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
   1.456 +   * tagged with aFrame
   1.457 +   */
   1.458 +  nsresult RemoveRegion(nsIFrame* aFrame);
   1.459 +
   1.460 +  /**
   1.461 +   * Clears the list of regions representing the unavailable space.
   1.462 +   */
   1.463 +  void ClearRegions();
   1.464 +</pre>
   1.465 + 
   1.466 +<h4>Float Impact</h4>
   1.467 + 
   1.468 +<pre>  /**
   1.469 +   * Methods for dealing with the propagation of float damage during
   1.470 +   * reflow.
   1.471 +   */
   1.472 +  PRBool HasFloatDamage()
   1.473 +  {
   1.474 +    return !mFloatDamage.IsEmpty();
   1.475 +  }
   1.476 +
   1.477 +  void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
   1.478 +  {
   1.479 +    mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
   1.480 +  }
   1.481 +
   1.482 +  PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
   1.483 +  {
   1.484 +    return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
   1.485 +  }
   1.486 +</pre>
   1.487 + 
   1.488 +<h4>Debug Only Methods</h4>
   1.489 + 
   1.490 +<pre>  /**
   1.491 +   * Dump the state of the spacemanager out to a file
   1.492 +   */
   1.493 +  nsresult List(FILE* out);
   1.494 +
   1.495 +  void SizeOf(nsISizeOfHandler* aHandler, uint32_t* aResult) const;
   1.496 +
   1.497 +</pre>
   1.498 + 
   1.499 +<h4>Unused / Obsolete Methods</h4>
   1.500 + 
   1.501 +<pre>  /*
   1.502 +   * Get the frame that's associated with the space manager. This frame
   1.503 +   * created the space manager, and the world coordinate space is
   1.504 +   * relative to this frame.
   1.505 +   *
   1.506 +   * You can use QueryInterface() on this frame to get any additional
   1.507 +   * interfaces.
   1.508 +   */
   1.509 +   nsIFrame* GetFrame() const { return mFrame; }
   1.510 +
   1.511 +</pre>
   1.512 + 
   1.513 +<h3>Implementation Notes</h3>
   1.514 + 
   1.515 +<h4></h4>
   1.516 + 
   1.517 +<h4>Algorithm 1: GetBandData</h4>
   1.518 +<p>
   1.519 +GetBandData is used to provide information to clients about what space if
   1.520 +available and unavailable in a band of space. &nbsp;The client provides a
   1.521 +vertical offset, the yOffset, that corresponds to the band that is of interest.
   1.522 +&nbsp;This will be the y offset of the frame that is being reflowed. &nbsp;The
   1.523 +caller also provides a collection of BandData objects (an array) and the
   1.524 +number of items that the collection can handle. &nbsp;If the collection is
   1.525 +too small, then an error is returned and the count is updated to indicate
   1.526 +the size required.
   1.527 +</p>
   1.528 +
   1.529 +<p>
   1.530 +The algorithm to provide the band data is as follows:
   1.531 +</p>
   1.532 +<ul>
   1.533 +  <li>Get a &nbsp;vertical offset in world coordinates (instead of frame-relative
   1.534 +coordinates) by adding the y-origin of the SpaceManager to the y offset passed
   1.535 +in</li>
   1.536 +  <li>If the (adjusted) y value passed in is greater than the greatest band
   1.537 +being managed, then all space is available so a single trapezoid is returned,
   1.538 +marked as available and sized to the maximum size value (passed in).</li>
   1.539 +  <li>If the (adjusted) y offset intersects a band, then gather the band
   1.540 +data:</li>
   1.541 +  <ul>
   1.542 +    <li>walk the internal bandData list from head to tail</li>
   1.543 +    <li>for each band data entry, see if the top of the band is greater than
   1.544 +the (adjusted) y offset requested</li>
   1.545 +    <li>if it is, then band is below the offset requested, so the area between
   1.546 +the band and the y offset is available - create a trapezoid with that region
   1.547 +and return it.</li>
   1.548 +    <li>if the (adjusted) y offset is between the band top and bottom, then
   1.549 +get the available space for the band by calling GetBandAvailableSpace</li>
   1.550 +    <li>otherwise, move to the next band</li>
   1.551 +  </ul>
   1.552 +</ul>
   1.553 +<h5>GetBandAvailableSpace:</h5>
   1.554 +This method is called from GetBandData only. It walks all of the bands in
   1.555 +the space manager and determines which bands intersect with the band passed
   1.556 +in, and if within those bands there are regions that are available or occupied.
   1.557 +
   1.558 +<ul>
   1.559 +  <li>First, walk all of the bands until a band that is to the right of the
   1.560 +desired offset is located</li>
   1.561 +  <li>Starting at that band, &nbsp;walk the remaining bands:</li>
   1.562 +  <ul>
   1.563 +    <li>if the current band is to the right of the requested band, then there
   1.564 +is available space.&nbsp;</li>
   1.565 +    <ul>
   1.566 +      <li>if there is more room in the bandData collection, then add a trapezoid
   1.567 +to the bandData collection such that it is marked as available and has a
   1.568 +rect that represents the space between the reference band tna dht band being
   1.569 +examined</li>
   1.570 +      <li>if there is no more room in the BandData collection, estimate the
   1.571 +number of entries requires as the current count + twice the number of bands
   1.572 +below the reference band, plus two. &nbsp;Return an error code so the caller
   1.573 +can reallocate the collection and try again.</li>
   1.574 +    </ul>
   1.575 +    <li>check the size of the collection again, if there is no room left
   1.576 +then estimate the number of items requires as the current count + twice the
   1.577 +number of bands below the band in question plus one.&nbsp;</li>
   1.578 +    <li>create a new trapezoid in the band collection that has a region corresponding
   1.579 +to the reference band rect, marked as occupied by either a single or multiple
   1.580 +frames.</li>
   1.581 +    <li>move to the next band</li>
   1.582 +  </ul>
   1.583 +  <li>after walking all of the band data, se if we have reached the right
   1.584 +edge of the band.&nbsp;</li>
   1.585 +  <ul>
   1.586 +    <li>If not, then check for space in the band collection</li>
   1.587 +    <ul>
   1.588 +      <li>if there is no room left, then set the count to the current count
   1.589 +plus 1 and return an error.</li>
   1.590 +      <li>otherwise, create another entry in the band collection, marked
   1.591 +as available, and with a rect corresponding to the area remainin in the band
   1.592 +(eg. from the right edge of the last band rect to the right edge of the band).</li>
   1.593 +    </ul>
   1.594 +  </ul>
   1.595 +</ul>
   1.596 + 
   1.597 +<h4>Algorithm 2: AddRectRegion</h4>
   1.598 +Clients call into this method to notify the Space Manager that a new frame
   1.599 +is occupying some space.
   1.600 +
   1.601 +<ul>
   1.602 +  <li>First, try to get frame info for the frame. If it is found, return
   1.603 +an error since the frame is already associated with a region in the Space
   1.604 +Manager.</li>
   1.605 +  <li>Next, create a rect from the occupied space passed in by the caller,
   1.606 +transforming it first to world-coordinates by adding the Space Manager's
   1.607 +offset to the occupied space rect passed in.</li>
   1.608 +  <li>Create a new Frame Info instance for the frame and rect, returning
   1.609 +an error if allocation fails.</li>
   1.610 +  <li>Check if the occupied space rect (adjusted) is empty, if so, return
   1.611 +an error &nbsp;(<font color="#cc0000">NOTE: this could be done earlier, or
   1.612 +prevented by the caller</font>)</li>
   1.613 +  <li>Allocate a new BandRect instance with the rect and frame as constructor
   1.614 +arguments, and insert it into the collection via InsertBandRect</li>
   1.615 +</ul>
   1.616 +<h5>InsertBandRect:</h5>
   1.617 +Internal method to insert a band rect into the BandList in the correct location.
   1.618 +There are several cases it has to handle, as specified in the source file
   1.619 +comments:
   1.620 +
   1.621 +<pre>// When comparing a rect to a band there are seven cases to consider.
   1.622 +// 'R' is the rect and 'B' is the band.
   1.623 +//
   1.624 +//      Case 1              Case 2              Case 3              Case 4
   1.625 +//      ------              ------              ------              ------
   1.626 +// +-----+             +-----+                      +-----+             +-----+
   1.627 +// |  R  |             |  R  |  +-----+    +-----+  |     |             |     |
   1.628 +// +-----+             +-----+  |     |    |  R  |  |  B  |             |  B  |
   1.629 +//          +-----+             |  B  |    +-----+  |     |    +-----+  |     |
   1.630 +//          |     |             |     |             +-----+    |  R  |  +-----+
   1.631 +//          |  B  |             +-----+                        +-----+
   1.632 +//          |     |
   1.633 +//          +-----+
   1.634 +//
   1.635 +//
   1.636 +//
   1.637 +//      Case 5              Case 6              Case 7
   1.638 +//      ------              ------              ------
   1.639 +//          +-----+    +-----+  +-----+    +-----+
   1.640 +//          |     |    |  R  |  |  B  |    |     |  +-----+
   1.641 +//          |  B  |    +-----+  +-----+    |  R  |  |  B  |
   1.642 +//          |     |                        |     |  +-----+
   1.643 +//          +-----+                        +-----+
   1.644 +// +-----+
   1.645 +// |  R  |
   1.646 +// +-----+
   1.647 +//
   1.648 +</pre>
   1.649 +<ul>
   1.650 +  <li>First, check for the easiest case, where there are no existing band
   1.651 +rects, or the band rect passed in is below the bottommost rect. In this case,
   1.652 +just append the band rect and return.</li>
   1.653 +  <li>Starting at the head of the list of bandRects, check for intersection
   1.654 +with the rect passed in:</li>
   1.655 +  <ul>
   1.656 +    <li>case #1: the rect is totally above the current band rect, so insert
   1.657 +a new band rect before the current bandRect</li>
   1.658 +    <li>cases #2 and #7: the rect is partially above the band rect, so it
   1.659 +is divided into two bandRects, one entirely above the band, and one containing
   1.660 +the remainder of the rect. &nbsp;Insert the part that is totally above the
   1.661 +bandRect before the current bandRect, as in case #1 above, and adjust the
   1.662 +other band rect to exclude the part already added.</li>
   1.663 +    <li>case #5: the rect is totally below the current bandRect, so just
   1.664 +skip to the next band</li>
   1.665 +    <li>case #3 and #4: rect is at least partially intersection with the
   1.666 +bandRect, so divide the current band into two parts, where the top part is
   1.667 +above the current rect. &nbsp;Move to the new band just created, which is
   1.668 +the next band.</li>
   1.669 +    <li>case #6: the rect shares the bottom and height with the bandRect,
   1.670 +so just add the rect to the band.</li>
   1.671 +    <li>case #4 and #7: create a new rect for the part that overlaps the
   1.672 +bandRect, and add it to the current bandRect (similar to case #6) and then
   1.673 +move on to the next band, removing that part from the rect passed in. &nbsp;If
   1.674 +no more bands, append the rect passed in to the end of the bandRect list.</li>
   1.675 +  </ul>
   1.676 +</ul>
   1.677 +<i>This algorithm is pretty confusing - basically what needs to happen is
   1.678 +that rects and bands need to be divided up so that complicated cases like
   1.679 +#2, #4, and #7, are reduced to simpler cases where the rects is totally above,
   1.680 +below, or between a band rect. &nbsp;From the current implementation, it
   1.681 +might be worth verifying that the final result of the inserts is a correctly
   1.682 +ordered liest of bandRects (debug mode only).</i>
   1.683 +
   1.684 + 
   1.685 +<h4>Algorithm 3: RemoveRegion</h4>
   1.686 + When a float is removed, the Space Manager is notified by a call to RemoveRegion,
   1.687 +passing in the frame that is being removed.
   1.688 +
   1.689 +<ul>
   1.690 +  <li>Get the FrameInfo for the frame passed in. If not found, an error is
   1.691 +returned.</li>
   1.692 +  <li>If the rect for the frame is not empty, then visit each band in the
   1.693 +bandList:</li>
   1.694 +  <ul>
   1.695 +    <li>for each rect in the band:
   1.696 +
   1.697 +    </li>
   1.698 +  </ul>
   1.699 +  <ul>
   1.700 +    <ul>
   1.701 +      <li>if the bandRect is occupied by the frame, either remove the frame
   1.702 +from the bandRect (if there are other frames sharing it) and remember that
   1.703 +it was shared</li>
   1.704 +      <li>otherwise simply remove the bandRect (no other frames share it).</li>
   1.705 +      <li>if the bandRect was shared, then try to coalesce adjacent bandRects</li>
   1.706 +      <ul>
   1.707 +        <li>if the previous bandRect is directly next to the current bandRect,
   1.708 +and they have the same frame list, then make the current bandRect cover the
   1.709 +previous bandRect's full region (adjust the left edge to be that of the previous
   1.710 +bandRect) and remove the previous bandRect.</li>
   1.711 +      </ul>
   1.712 +    </ul>
   1.713 +  </ul>
   1.714 +  <ul>
   1.715 +    <li>if the current band or prior band had a rect occupied byu the frame,
   1.716 +then try to join the two bands via JoinBands</li>
   1.717 +  </ul>
   1.718 +  <li>Finally, destroy the frameInfo for the frame.
   1.719 +
   1.720 +  </li>
   1.721 +</ul>
   1.722 +  
   1.723 +<br>
   1.724 + 
   1.725 +<hr width="100%" size="2"> 
   1.726 +<h2>Cross-Component Algorithms</h2>
   1.727 +
   1.728 +<br>
   1.729 + 
   1.730 +
   1.731 + 
   1.732 +<hr width="100%" size="2"> 
   1.733 +<h2>Tech Notes</h2>
   1.734 +<ul>
   1.735 +  <li>
   1.736 +
   1.737 +  </li>
   1.738 + 
   1.739 +</ul>
   1.740 + 
   1.741 +
   1.742 + 
   1.743 +
   1.744 + 
   1.745 +</body>
   1.746 +</html>

mercurial