DD-SpaceManager.html 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. <!-- This Source Code Form is subject to the terms of the Mozilla Public
  2. - License, v. 2.0. If a copy of the MPL was not distributed with this
  3. - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
  4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  5. <html>
  6. <head>
  7. <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  8. <title>Detailed Design Template</title>
  9. </head>
  10. <body>
  11. <h1><font color="#cc0000">Gecko Layout Detailed Design Document</font></h1>
  12. <h1>Space Manager Detailed Design</h1>
  13. <h2>Overview</h2>
  14. <p>
  15. The Space Manager and related classes and structures are an important of
  16. the Gecko Layout system, specifically Block Layout. &nbsp;See the High Level
  17. Design document for an overview of the Space Manager, and as an introduction
  18. to the classes, structures and algorithms container in this, the Detailed
  19. Design Document.
  20. </p>
  21. <hr width="100%" size="2">
  22. <h2>nsSpaceManager</h2>
  23. <p>
  24. The Space Manager is the central class is a group of classes that manage
  25. the occupied and available space that exists in horizontal bands across
  26. a canvas. &nbsp;The primary goal of the Space Manager is to provide information
  27. about those bands of space to support the CSS notion of floated elements.
  28. </p>
  29. <p>
  30. There are three important parts to the Space Manager API: the parts that
  31. deal with the coordinate space of the Space Manager, the parts that deal with
  32. the regions managed by the Space Manager, and the parts that manage float
  33. impact intervals.
  34. </p>
  35. <p>
  36. The class nsSpaceManager is declared in the file <a href="http://lxr.mozilla.org/seamonkey/source/layout/base/src/nsSpaceManager.h">
  37. nsSpaceManger.h</a>
  38. . &nbsp;The class is only used in the layout module and cannot be exported
  39. outside of that module (nor does it need to be). &nbsp;It is not a general
  40. purpose class, and is not intended to be subclasses<font color="#cc0000">
  41. .</font>
  42. </p>
  43. <p>
  44. Here is the class declaration, taken from the source file as of 01.08.02
  45. </p>
  46. <pre>/**
  47. * Class for dealing with bands of available space. The space manager
  48. * defines a coordinate space with an origin at (0, 0) that grows down
  49. * and to the right.
  50. */
  51. class nsSpaceManager {
  52. public:
  53. nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
  54. ~nsSpaceManager();
  55. void* operator new(size_t aSize);
  56. void operator delete(void* aPtr, size_t aSize);
  57. static void Shutdown();
  58. /*
  59. * Get the frame that's associated with the space manager. This frame
  60. * created the space manager, and the world coordinate space is
  61. * relative to this frame.
  62. *
  63. * You can use QueryInterface() on this frame to get any additional
  64. * interfaces.
  65. */
  66. nsIFrame* GetFrame() const { return mFrame; }
  67. /**
  68. * Translate the current origin by the specified (dx, dy). This
  69. * creates a new local coordinate space relative to the current
  70. * coordinate space.
  71. */
  72. void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
  73. /**
  74. * Returns the current translation from local coordinate space to
  75. * world coordinate space. This represents the accumulated calls to
  76. * Translate().
  77. */
  78. void GetTranslation(nscoord&amp; aX, nscoord&amp; aY) const { aX = mX; aY = mY; }
  79. /**
  80. * Returns the y-most of the bottommost band or 0 if there are no bands.
  81. *
  82. * @return PR_TRUE if there are bands and PR_FALSE if there are no bands
  83. */
  84. PRBool YMost(nscoord&amp; aYMost) const;
  85. /**
  86. * Returns a band starting at the specified y-offset. The band data
  87. * indicates which parts of the band are available, and which parts
  88. * are unavailable
  89. *
  90. * The band data that is returned is in the coordinate space of the
  91. * local coordinate system.
  92. *
  93. * The local coordinate space origin, the y-offset, and the max size
  94. * describe a rectangle that's used to clip the underlying band of
  95. * available space, i.e.
  96. * {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
  97. * coordinate space
  98. *
  99. * @param aYOffset the y-offset of where the band begins. The coordinate is
  100. * relative to the upper-left corner of the local coordinate space
  101. * @param aMaxSize the size to use to constrain the band data
  102. * @param aBandData [in,out] used to return the list of trapezoids that
  103. * describe the available space and the unavailable space
  104. * @return NS_OK if successful and NS_ERROR_FAILURE if the band data is not
  105. * not large enough. The 'count' member of the band data struct
  106. * indicates how large the array of trapezoids needs to be
  107. */
  108. nsresult GetBandData(nscoord aYOffset,
  109. const nsSize&amp; aMaxSize,
  110. nsBandData&amp; aBandData) const;
  111. /**
  112. * Add a rectangular region of unavailable space. The space is
  113. * relative to the local coordinate system.
  114. *
  115. * The region is tagged with a frame
  116. *
  117. * @param aFrame the frame used to identify the region. Must not be NULL
  118. * @param aUnavailableSpace the bounding rect of the unavailable space
  119. * @return NS_OK if successful
  120. * NS_ERROR_FAILURE if there is already a region tagged with aFrame
  121. */
  122. nsresult AddRectRegion(nsIFrame* aFrame,
  123. const nsRect&amp; aUnavailableSpace);
  124. /**
  125. * Resize the rectangular region associated with aFrame by the specified
  126. * deltas. The height change always applies to the bottom edge or the existing
  127. * rect. You specify whether the width change applies to the left or right edge
  128. *
  129. * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
  130. * tagged with aFrame
  131. */
  132. enum AffectedEdge {LeftEdge, RightEdge};
  133. nsresult ResizeRectRegion(nsIFrame* aFrame,
  134. nscoord aDeltaWidth,
  135. nscoord aDeltaHeight,
  136. AffectedEdge aEdge = RightEdge);
  137. /**
  138. * Offset the region associated with aFrame by the specified amount.
  139. *
  140. * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
  141. * tagged with aFrame
  142. */
  143. nsresult OffsetRegion(nsIFrame* aFrame, nscoord dx, nscoord dy);
  144. /**
  145. * Remove the region associated with aFrane.
  146. *
  147. * Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
  148. * tagged with aFrame
  149. */
  150. nsresult RemoveRegion(nsIFrame* aFrame);
  151. /**
  152. * Clears the list of regions representing the unavailable space.
  153. */
  154. void ClearRegions();
  155. /**
  156. * Methods for dealing with the propagation of float damage during
  157. * reflow.
  158. */
  159. PRBool HasFloatDamage()
  160. {
  161. return !mFloatDamage.IsEmpty();
  162. }
  163. void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
  164. {
  165. mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
  166. }
  167. PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
  168. {
  169. return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
  170. }
  171. #ifdef DEBUG
  172. /**
  173. * Dump the state of the spacemanager out to a file
  174. */
  175. nsresult List(FILE* out);
  176. void SizeOf(nsISizeOfHandler* aHandler, uint32_t* aResult) const;
  177. #endif
  178. private:
  179. // Structure that maintains information about the region associated
  180. // with a particular frame
  181. struct FrameInfo {
  182. nsIFrame* const mFrame;
  183. nsRect mRect; // rectangular region
  184. FrameInfo* mNext;
  185. FrameInfo(nsIFrame* aFrame, const nsRect&amp; aRect);
  186. #ifdef NS_BUILD_REFCNT_LOGGING
  187. ~FrameInfo();
  188. #endif
  189. };
  190. // Doubly linked list of band rects
  191. struct BandRect : PRCListStr {
  192. nscoord mLeft, mTop;
  193. nscoord mRight, mBottom;
  194. int32_t mNumFrames; // number of frames occupying this rect
  195. union {
  196. nsIFrame* mFrame; // single frame occupying the space
  197. nsVoidArray* mFrames; // list of frames occupying the space
  198. };
  199. BandRect(nscoord aLeft, nscoord aTop,
  200. nscoord aRight, nscoord aBottom,
  201. nsIFrame*);
  202. BandRect(nscoord aLeft, nscoord aTop,
  203. nscoord aRight, nscoord aBottom,
  204. nsVoidArray*);
  205. ~BandRect();
  206. // List operations
  207. BandRect* Next() const {return (BandRect*)PR_NEXT_LINK(this);}
  208. BandRect* Prev() const {return (BandRect*)PR_PREV_LINK(this);}
  209. void InsertBefore(BandRect* aBandRect) {PR_INSERT_BEFORE(aBandRect, this);}
  210. void InsertAfter(BandRect* aBandRect) {PR_INSERT_AFTER(aBandRect, this);}
  211. void Remove() {PR_REMOVE_LINK(this);}
  212. // Split the band rect into two vertically, with this band rect becoming
  213. // the top part, and a new band rect being allocated and returned for the
  214. // bottom part
  215. //
  216. // Does not insert the new band rect into the linked list
  217. BandRect* SplitVertically(nscoord aBottom);
  218. // Split the band rect into two horizontally, with this band rect becoming
  219. // the left part, and a new band rect being allocated and returned for the
  220. // right part
  221. //
  222. // Does not insert the new band rect into the linked list
  223. BandRect* SplitHorizontally(nscoord aRight);
  224. // Accessor functions
  225. PRBool IsOccupiedBy(const nsIFrame*) const;
  226. void AddFrame(const nsIFrame*);
  227. void RemoveFrame(const nsIFrame*);
  228. PRBool HasSameFrameList(const BandRect* aBandRect) const;
  229. int32_t Length() const;
  230. };
  231. // Circular linked list of band rects
  232. struct BandList : BandRect {
  233. BandList();
  234. // Accessors
  235. PRBool IsEmpty() const {return PR_CLIST_IS_EMPTY((PRCListStr*)this);}
  236. BandRect* Head() const {return (BandRect*)PR_LIST_HEAD(this);}
  237. BandRect* Tail() const {return (BandRect*)PR_LIST_TAIL(this);}
  238. // Operations
  239. void Append(BandRect* aBandRect) {PR_APPEND_LINK(aBandRect, this);}
  240. // Remove and delete all the band rects in the list
  241. void Clear();
  242. };
  243. FrameInfo* GetFrameInfoFor(nsIFrame* aFrame);
  244. FrameInfo* CreateFrameInfo(nsIFrame* aFrame, const nsRect&amp; aRect);
  245. void DestroyFrameInfo(FrameInfo*);
  246. void ClearFrameInfo();
  247. void ClearBandRects();
  248. BandRect* GetNextBand(const BandRect* aBandRect) const;
  249. void DivideBand(BandRect* aBand, nscoord aBottom);
  250. PRBool CanJoinBands(BandRect* aBand, BandRect* aPrevBand);
  251. PRBool JoinBands(BandRect* aBand, BandRect* aPrevBand);
  252. void AddRectToBand(BandRect* aBand, BandRect* aBandRect);
  253. void InsertBandRect(BandRect* aBandRect);
  254. nsresult GetBandAvailableSpace(const BandRect* aBand,
  255. nscoord aY,
  256. const nsSize&amp; aMaxSize,
  257. nsBandData&amp; aAvailableSpace) const;
  258. nsIFrame* const mFrame; // frame associated with the space manager
  259. nscoord mX, mY; // translation from local to global coordinate space
  260. BandList mBandList; // header/sentinel for circular linked list of band rects
  261. FrameInfo* mFrameInfoMap;
  262. nsIntervalSet mFloatDamage;
  263. static int32_t sCachedSpaceManagerCount;
  264. static void* sCachedSpaceManagers[NS_SPACE_MANAGER_CACHE_SIZE];
  265. nsSpaceManager(const nsSpaceManager&amp;); // no implementation
  266. void operator=(const nsSpaceManager&amp;); // no implementation
  267. };
  268. </pre>
  269. <h3>Public API</h3>
  270. <h4>Life Cycle:</h4>
  271. <p>
  272. The Constructor requires a Presentation Shell, used for arena allocations
  273. mostly, and a frame that this Space Manager is rooted on. &nbsp;The coordinate
  274. space of this Space Manager is relative to the frame passed in to the constructor.
  275. </p>
  276. <pre> nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame);
  277. ~nsSpaceManager();
  278. </pre>
  279. <p>
  280. Operators 'new' and 'delete' are overridden to support a recycler. &nbsp;Space
  281. Manager instances come and go pretty frequently, and this recycler prevents
  282. excessive heap allocations and the performance penalties associated with
  283. it. The #define NS_SPACE_MANAGER_CACHE_SIZE is used to control the number
  284. of Space Manager instances that can be present in the recycler, currently
  285. 4. &nbsp;If more than NS_SPACE_MANAGER_CACHE_SIZE are allocated at a time,
  286. then standard allocation is used.
  287. </p>
  288. <pre>
  289. void* operator new(size_t aSize);
  290. void operator delete(void* aPtr, size_t aSize);
  291. </pre>
  292. <p>
  293. A Static method is used to shutdown the Space Manager recycling. &nbsp;This
  294. method deletes all of the Space Mangers inthe recycler,and prevents further
  295. recycling. &nbsp;It is meant to be called only when the layout module is being
  296. terminated.
  297. </p>
  298. <pre> static void Shutdown();
  299. </pre>
  300. <h4>Origin / Coordinate Space Translation</h4>
  301. <pre> /**
  302. * Translate the current origin by the specified (dx, dy). This
  303. * creates a new local coordinate space relative to the current
  304. * coordinate space.
  305. */
  306. void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
  307. /**
  308. * Returns the current translation from local coordinate space to
  309. * world coordinate space. This represents the accumulated calls to
  310. * Translate().
  311. */
  312. void GetTranslation(nscoord&amp; aX, nscoord&amp; aY) const { aX = mX; aY = mY; }
  313. /**
  314. * Returns the y-most of the bottommost band or 0 if there are no bands.
  315. *
  316. * @return PR_TRUE if there are bands and PR_FALSE if there are no bands
  317. */
  318. PRBool YMost(nscoord&amp; aYMost) const;
  319. </pre>
  320. <h4>Region Management</h4>
  321. <pre> /**
  322. * Returns a band starting at the specified y-offset. The band data
  323. * indicates which parts of the band are available, and which parts
  324. * are unavailable
  325. *
  326. * The band data that is returned is in the coordinate space of the
  327. * local coordinate system.
  328. *
  329. * The local coordinate space origin, the y-offset, and the max size
  330. * describe a rectangle that's used to clip the underlying band of
  331. * available space, i.e.
  332. * {0, aYOffset, aMaxSize.width, aMaxSize.height} in the local
  333. * coordinate space
  334. *
  335. * @param aYOffset the y-offset of where the band begins. The coordinate is
  336. * relative to the upper-left corner of the local coordinate space
  337. * @param aMaxSize the size to use to constrain the band data
  338. * @param aBandData [in,out] used to return the list of trapezoids that
  339. * describe the available space and the unavailable space
  340. * @return NS_OK if successful and NS_ERROR_FAILURE if the band data is not
  341. * not large enough. The 'count' member of the band data struct
  342. * indicates how large the array of trapezoids needs to be
  343. */
  344. nsresult GetBandData(nscoord aYOffset,
  345. const nsSize&amp; aMaxSize,
  346. nsBandData&amp; aBandData) const;
  347. /**
  348. * Add a rectangular region of unavailable space. The space is
  349. * relative to the local coordinate system.
  350. *
  351. * The region is tagged with a frame
  352. *
  353. * @param aFrame the frame used to identify the region. Must not be NULL
  354. * @param aUnavailableSpace the bounding rect of the unavailable space
  355. * @return NS_OK if successful
  356. * NS_ERROR_FAILURE if there is already a region tagged with aFrame
  357. */
  358. nsresult AddRectRegion(nsIFrame* aFrame,
  359. const nsRect&amp; aUnavailableSpace);
  360. /**
  361. * Resize the rectangular region associated with aFrame by the specified
  362. * deltas. The height change always applies to the bottom edge or the existing
  363. * rect. You specify whether the width change applies to the left or right edge
  364. *
  365. * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
  366. * tagged with aFrame
  367. */
  368. enum AffectedEdge {LeftEdge, RightEdge};
  369. nsresult ResizeRectRegion(nsIFrame* aFrame,
  370. nscoord aDeltaWidth,
  371. nscoord aDeltaHeight,
  372. AffectedEdge aEdge = RightEdge);
  373. /**
  374. * Offset the region associated with aFrame by the specified amount.
  375. *
  376. * Returns NS_OK if successful, NS_ERROR_INVALID_ARG if there is no region
  377. * tagged with aFrame
  378. */
  379. nsresult OffsetRegion(nsIFrame* aFrame, nscoord dx, nscoord dy);
  380. /**
  381. * Remove the region associated with aFrane.
  382. *
  383. * Returns NS_OK if successful and NS_ERROR_INVALID_ARG if there is no region
  384. * tagged with aFrame
  385. */
  386. nsresult RemoveRegion(nsIFrame* aFrame);
  387. /**
  388. * Clears the list of regions representing the unavailable space.
  389. */
  390. void ClearRegions();
  391. </pre>
  392. <h4>Float Impact</h4>
  393. <pre> /**
  394. * Methods for dealing with the propagation of float damage during
  395. * reflow.
  396. */
  397. PRBool HasFloatDamage()
  398. {
  399. return !mFloatDamage.IsEmpty();
  400. }
  401. void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
  402. {
  403. mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
  404. }
  405. PRBool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
  406. {
  407. return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
  408. }
  409. </pre>
  410. <h4>Debug Only Methods</h4>
  411. <pre> /**
  412. * Dump the state of the spacemanager out to a file
  413. */
  414. nsresult List(FILE* out);
  415. void SizeOf(nsISizeOfHandler* aHandler, uint32_t* aResult) const;
  416. </pre>
  417. <h4>Unused / Obsolete Methods</h4>
  418. <pre> /*
  419. * Get the frame that's associated with the space manager. This frame
  420. * created the space manager, and the world coordinate space is
  421. * relative to this frame.
  422. *
  423. * You can use QueryInterface() on this frame to get any additional
  424. * interfaces.
  425. */
  426. nsIFrame* GetFrame() const { return mFrame; }
  427. </pre>
  428. <h3>Implementation Notes</h3>
  429. <h4></h4>
  430. <h4>Algorithm 1: GetBandData</h4>
  431. <p>
  432. GetBandData is used to provide information to clients about what space if
  433. available and unavailable in a band of space. &nbsp;The client provides a
  434. vertical offset, the yOffset, that corresponds to the band that is of interest.
  435. &nbsp;This will be the y offset of the frame that is being reflowed. &nbsp;The
  436. caller also provides a collection of BandData objects (an array) and the
  437. number of items that the collection can handle. &nbsp;If the collection is
  438. too small, then an error is returned and the count is updated to indicate
  439. the size required.
  440. </p>
  441. <p>
  442. The algorithm to provide the band data is as follows:
  443. </p>
  444. <ul>
  445. <li>Get a &nbsp;vertical offset in world coordinates (instead of frame-relative
  446. coordinates) by adding the y-origin of the SpaceManager to the y offset passed
  447. in</li>
  448. <li>If the (adjusted) y value passed in is greater than the greatest band
  449. being managed, then all space is available so a single trapezoid is returned,
  450. marked as available and sized to the maximum size value (passed in).</li>
  451. <li>If the (adjusted) y offset intersects a band, then gather the band
  452. data:</li>
  453. <ul>
  454. <li>walk the internal bandData list from head to tail</li>
  455. <li>for each band data entry, see if the top of the band is greater than
  456. the (adjusted) y offset requested</li>
  457. <li>if it is, then band is below the offset requested, so the area between
  458. the band and the y offset is available - create a trapezoid with that region
  459. and return it.</li>
  460. <li>if the (adjusted) y offset is between the band top and bottom, then
  461. get the available space for the band by calling GetBandAvailableSpace</li>
  462. <li>otherwise, move to the next band</li>
  463. </ul>
  464. </ul>
  465. <h5>GetBandAvailableSpace:</h5>
  466. This method is called from GetBandData only. It walks all of the bands in
  467. the space manager and determines which bands intersect with the band passed
  468. in, and if within those bands there are regions that are available or occupied.
  469. <ul>
  470. <li>First, walk all of the bands until a band that is to the right of the
  471. desired offset is located</li>
  472. <li>Starting at that band, &nbsp;walk the remaining bands:</li>
  473. <ul>
  474. <li>if the current band is to the right of the requested band, then there
  475. is available space.&nbsp;</li>
  476. <ul>
  477. <li>if there is more room in the bandData collection, then add a trapezoid
  478. to the bandData collection such that it is marked as available and has a
  479. rect that represents the space between the reference band tna dht band being
  480. examined</li>
  481. <li>if there is no more room in the BandData collection, estimate the
  482. number of entries requires as the current count + twice the number of bands
  483. below the reference band, plus two. &nbsp;Return an error code so the caller
  484. can reallocate the collection and try again.</li>
  485. </ul>
  486. <li>check the size of the collection again, if there is no room left
  487. then estimate the number of items requires as the current count + twice the
  488. number of bands below the band in question plus one.&nbsp;</li>
  489. <li>create a new trapezoid in the band collection that has a region corresponding
  490. to the reference band rect, marked as occupied by either a single or multiple
  491. frames.</li>
  492. <li>move to the next band</li>
  493. </ul>
  494. <li>after walking all of the band data, se if we have reached the right
  495. edge of the band.&nbsp;</li>
  496. <ul>
  497. <li>If not, then check for space in the band collection</li>
  498. <ul>
  499. <li>if there is no room left, then set the count to the current count
  500. plus 1 and return an error.</li>
  501. <li>otherwise, create another entry in the band collection, marked
  502. as available, and with a rect corresponding to the area remainin in the band
  503. (eg. from the right edge of the last band rect to the right edge of the band).</li>
  504. </ul>
  505. </ul>
  506. </ul>
  507. <h4>Algorithm 2: AddRectRegion</h4>
  508. Clients call into this method to notify the Space Manager that a new frame
  509. is occupying some space.
  510. <ul>
  511. <li>First, try to get frame info for the frame. If it is found, return
  512. an error since the frame is already associated with a region in the Space
  513. Manager.</li>
  514. <li>Next, create a rect from the occupied space passed in by the caller,
  515. transforming it first to world-coordinates by adding the Space Manager's
  516. offset to the occupied space rect passed in.</li>
  517. <li>Create a new Frame Info instance for the frame and rect, returning
  518. an error if allocation fails.</li>
  519. <li>Check if the occupied space rect (adjusted) is empty, if so, return
  520. an error &nbsp;(<font color="#cc0000">NOTE: this could be done earlier, or
  521. prevented by the caller</font>)</li>
  522. <li>Allocate a new BandRect instance with the rect and frame as constructor
  523. arguments, and insert it into the collection via InsertBandRect</li>
  524. </ul>
  525. <h5>InsertBandRect:</h5>
  526. Internal method to insert a band rect into the BandList in the correct location.
  527. There are several cases it has to handle, as specified in the source file
  528. comments:
  529. <pre>// When comparing a rect to a band there are seven cases to consider.
  530. // 'R' is the rect and 'B' is the band.
  531. //
  532. // Case 1 Case 2 Case 3 Case 4
  533. // ------ ------ ------ ------
  534. // +-----+ +-----+ +-----+ +-----+
  535. // | R | | R | +-----+ +-----+ | | | |
  536. // +-----+ +-----+ | | | R | | B | | B |
  537. // +-----+ | B | +-----+ | | +-----+ | |
  538. // | | | | +-----+ | R | +-----+
  539. // | B | +-----+ +-----+
  540. // | |
  541. // +-----+
  542. //
  543. //
  544. //
  545. // Case 5 Case 6 Case 7
  546. // ------ ------ ------
  547. // +-----+ +-----+ +-----+ +-----+
  548. // | | | R | | B | | | +-----+
  549. // | B | +-----+ +-----+ | R | | B |
  550. // | | | | +-----+
  551. // +-----+ +-----+
  552. // +-----+
  553. // | R |
  554. // +-----+
  555. //
  556. </pre>
  557. <ul>
  558. <li>First, check for the easiest case, where there are no existing band
  559. rects, or the band rect passed in is below the bottommost rect. In this case,
  560. just append the band rect and return.</li>
  561. <li>Starting at the head of the list of bandRects, check for intersection
  562. with the rect passed in:</li>
  563. <ul>
  564. <li>case #1: the rect is totally above the current band rect, so insert
  565. a new band rect before the current bandRect</li>
  566. <li>cases #2 and #7: the rect is partially above the band rect, so it
  567. is divided into two bandRects, one entirely above the band, and one containing
  568. the remainder of the rect. &nbsp;Insert the part that is totally above the
  569. bandRect before the current bandRect, as in case #1 above, and adjust the
  570. other band rect to exclude the part already added.</li>
  571. <li>case #5: the rect is totally below the current bandRect, so just
  572. skip to the next band</li>
  573. <li>case #3 and #4: rect is at least partially intersection with the
  574. bandRect, so divide the current band into two parts, where the top part is
  575. above the current rect. &nbsp;Move to the new band just created, which is
  576. the next band.</li>
  577. <li>case #6: the rect shares the bottom and height with the bandRect,
  578. so just add the rect to the band.</li>
  579. <li>case #4 and #7: create a new rect for the part that overlaps the
  580. bandRect, and add it to the current bandRect (similar to case #6) and then
  581. move on to the next band, removing that part from the rect passed in. &nbsp;If
  582. no more bands, append the rect passed in to the end of the bandRect list.</li>
  583. </ul>
  584. </ul>
  585. <i>This algorithm is pretty confusing - basically what needs to happen is
  586. that rects and bands need to be divided up so that complicated cases like
  587. #2, #4, and #7, are reduced to simpler cases where the rects is totally above,
  588. below, or between a band rect. &nbsp;From the current implementation, it
  589. might be worth verifying that the final result of the inserts is a correctly
  590. ordered liest of bandRects (debug mode only).</i>
  591. <h4>Algorithm 3: RemoveRegion</h4>
  592. When a float is removed, the Space Manager is notified by a call to RemoveRegion,
  593. passing in the frame that is being removed.
  594. <ul>
  595. <li>Get the FrameInfo for the frame passed in. If not found, an error is
  596. returned.</li>
  597. <li>If the rect for the frame is not empty, then visit each band in the
  598. bandList:</li>
  599. <ul>
  600. <li>for each rect in the band:
  601. </li>
  602. </ul>
  603. <ul>
  604. <ul>
  605. <li>if the bandRect is occupied by the frame, either remove the frame
  606. from the bandRect (if there are other frames sharing it) and remember that
  607. it was shared</li>
  608. <li>otherwise simply remove the bandRect (no other frames share it).</li>
  609. <li>if the bandRect was shared, then try to coalesce adjacent bandRects</li>
  610. <ul>
  611. <li>if the previous bandRect is directly next to the current bandRect,
  612. and they have the same frame list, then make the current bandRect cover the
  613. previous bandRect's full region (adjust the left edge to be that of the previous
  614. bandRect) and remove the previous bandRect.</li>
  615. </ul>
  616. </ul>
  617. </ul>
  618. <ul>
  619. <li>if the current band or prior band had a rect occupied byu the frame,
  620. then try to join the two bands via JoinBands</li>
  621. </ul>
  622. <li>Finally, destroy the frameInfo for the frame.
  623. </li>
  624. </ul>
  625. <br>
  626. <hr width="100%" size="2">
  627. <h2>Cross-Component Algorithms</h2>
  628. <br>
  629. <hr width="100%" size="2">
  630. <h2>Tech Notes</h2>
  631. <ul>
  632. <li>
  633. </li>
  634. </ul>
  635. </body>
  636. </html>