1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /* class that manages rules for positioning floats */
40 :
41 : #include "nsFloatManager.h"
42 : #include "nsIPresShell.h"
43 : #include "nsMemory.h"
44 : #include "nsHTMLReflowState.h"
45 : #include "nsBlockDebugFlags.h"
46 : #include "nsContentErrors.h"
47 :
48 : using namespace mozilla;
49 :
50 : PRInt32 nsFloatManager::sCachedFloatManagerCount = 0;
51 : void* nsFloatManager::sCachedFloatManagers[NS_FLOAT_MANAGER_CACHE_SIZE];
52 :
53 : /////////////////////////////////////////////////////////////////////////////
54 :
55 : // PresShell Arena allocate callback (for nsIntervalSet use below)
56 : static void*
57 0 : PSArenaAllocCB(size_t aSize, void* aClosure)
58 : {
59 0 : return static_cast<nsIPresShell*>(aClosure)->AllocateMisc(aSize);
60 : }
61 :
62 : // PresShell Arena free callback (for nsIntervalSet use below)
63 : static void
64 0 : PSArenaFreeCB(size_t aSize, void* aPtr, void* aClosure)
65 : {
66 0 : static_cast<nsIPresShell*>(aClosure)->FreeMisc(aSize, aPtr);
67 0 : }
68 :
69 : /////////////////////////////////////////////////////////////////////////////
70 : // nsFloatManager
71 :
72 0 : nsFloatManager::nsFloatManager(nsIPresShell* aPresShell)
73 : : mX(0), mY(0),
74 : mFloatDamage(PSArenaAllocCB, PSArenaFreeCB, aPresShell),
75 : mPushedLeftFloatPastBreak(false),
76 : mPushedRightFloatPastBreak(false),
77 : mSplitLeftFloatAcrossBreak(false),
78 0 : mSplitRightFloatAcrossBreak(false)
79 : {
80 0 : MOZ_COUNT_CTOR(nsFloatManager);
81 0 : }
82 :
83 0 : nsFloatManager::~nsFloatManager()
84 : {
85 0 : MOZ_COUNT_DTOR(nsFloatManager);
86 0 : }
87 :
88 : // static
89 0 : void* nsFloatManager::operator new(size_t aSize) CPP_THROW_NEW
90 : {
91 0 : if (sCachedFloatManagerCount > 0) {
92 : // We have cached unused instances of this class, return a cached
93 : // instance in stead of always creating a new one.
94 0 : return sCachedFloatManagers[--sCachedFloatManagerCount];
95 : }
96 :
97 : // The cache is empty, this means we haveto create a new instance using
98 : // the global |operator new|.
99 0 : return nsMemory::Alloc(aSize);
100 : }
101 :
102 : void
103 0 : nsFloatManager::operator delete(void* aPtr, size_t aSize)
104 : {
105 0 : if (!aPtr)
106 0 : return;
107 : // This float manager is no longer used, if there's still room in
108 : // the cache we'll cache this float manager, unless the layout
109 : // module was already shut down.
110 :
111 0 : if (sCachedFloatManagerCount < NS_FLOAT_MANAGER_CACHE_SIZE &&
112 : sCachedFloatManagerCount >= 0) {
113 : // There's still space in the cache for more instances, put this
114 : // instance in the cache in stead of deleting it.
115 :
116 0 : sCachedFloatManagers[sCachedFloatManagerCount++] = aPtr;
117 0 : return;
118 : }
119 :
120 : // The cache is full, or the layout module has been shut down,
121 : // delete this float manager.
122 0 : nsMemory::Free(aPtr);
123 : }
124 :
125 :
126 : /* static */
127 1403 : void nsFloatManager::Shutdown()
128 : {
129 : // The layout module is being shut down, clean up the cache and
130 : // disable further caching.
131 :
132 : PRInt32 i;
133 :
134 1403 : for (i = 0; i < sCachedFloatManagerCount; i++) {
135 0 : void* floatManager = sCachedFloatManagers[i];
136 0 : if (floatManager)
137 0 : nsMemory::Free(floatManager);
138 : }
139 :
140 : // Disable further caching.
141 1403 : sCachedFloatManagerCount = -1;
142 1403 : }
143 :
144 : nsFlowAreaRect
145 0 : nsFloatManager::GetFlowArea(nscoord aYOffset, BandInfoType aInfoType,
146 : nscoord aHeight, nsRect aContentArea,
147 : SavedState* aState) const
148 : {
149 0 : NS_ASSERTION(aHeight >= 0, "unexpected max height");
150 0 : NS_ASSERTION(aContentArea.width >= 0, "unexpected content area width");
151 :
152 0 : nscoord top = aYOffset + mY;
153 0 : if (top < nscoord_MIN) {
154 0 : NS_WARNING("bad value");
155 0 : top = nscoord_MIN;
156 : }
157 :
158 : // Determine the last float that we should consider.
159 : PRUint32 floatCount;
160 0 : if (aState) {
161 : // Use the provided state.
162 0 : floatCount = aState->mFloatInfoCount;
163 0 : NS_ABORT_IF_FALSE(floatCount <= mFloats.Length(), "bad state");
164 : } else {
165 : // Use our current state.
166 0 : floatCount = mFloats.Length();
167 : }
168 :
169 : // If there are no floats at all, or we're below the last one, return
170 : // quickly.
171 0 : if (floatCount == 0 ||
172 0 : (mFloats[floatCount-1].mLeftYMost <= top &&
173 0 : mFloats[floatCount-1].mRightYMost <= top)) {
174 : return nsFlowAreaRect(aContentArea.x, aYOffset, aContentArea.width,
175 0 : aHeight, false);
176 : }
177 :
178 : nscoord bottom;
179 0 : if (aHeight == nscoord_MAX) {
180 : // This warning (and the two below) are possible to hit on pages
181 : // with really large objects.
182 0 : NS_WARN_IF_FALSE(aInfoType == BAND_FROM_POINT,
183 : "bad height");
184 0 : bottom = nscoord_MAX;
185 : } else {
186 0 : bottom = top + aHeight;
187 0 : if (bottom < top || bottom > nscoord_MAX) {
188 0 : NS_WARNING("bad value");
189 0 : bottom = nscoord_MAX;
190 : }
191 : }
192 0 : nscoord left = mX + aContentArea.x;
193 0 : nscoord right = mX + aContentArea.XMost();
194 0 : if (right < left) {
195 0 : NS_WARNING("bad value");
196 0 : right = left;
197 : }
198 :
199 : // Walk backwards through the floats until we either hit the front of
200 : // the list or we're above |top|.
201 0 : bool haveFloats = false;
202 0 : for (PRUint32 i = floatCount; i > 0; --i) {
203 0 : const FloatInfo &fi = mFloats[i-1];
204 0 : if (fi.mLeftYMost <= top && fi.mRightYMost <= top) {
205 : // There aren't any more floats that could intersect this band.
206 0 : break;
207 : }
208 0 : if (fi.mRect.IsEmpty()) {
209 : // For compatibility, ignore floats with empty rects, even though it
210 : // disagrees with the spec. (We might want to fix this in the
211 : // future, though.)
212 0 : continue;
213 : }
214 0 : nscoord floatTop = fi.mRect.y, floatBottom = fi.mRect.YMost();
215 0 : if (top < floatTop && aInfoType == BAND_FROM_POINT) {
216 : // This float is below our band. Shrink our band's height if needed.
217 0 : if (floatTop < bottom) {
218 0 : bottom = floatTop;
219 : }
220 : }
221 : // If top == bottom (which happens only with WIDTH_WITHIN_HEIGHT),
222 : // we include floats that begin at our 0-height vertical area. We
223 : // need to to this to satisfy the invariant that a
224 : // WIDTH_WITHIN_HEIGHT call is at least as narrow on both sides as a
225 : // BAND_WITHIN_POINT call beginning at its top.
226 0 : else if (top < floatBottom &&
227 : (floatTop < bottom || (floatTop == bottom && top == bottom))) {
228 : // This float is in our band.
229 :
230 : // Shrink our band's height if needed.
231 0 : if (floatBottom < bottom && aInfoType == BAND_FROM_POINT) {
232 0 : bottom = floatBottom;
233 : }
234 :
235 : // Shrink our band's width if needed.
236 0 : if (fi.mFrame->GetStyleDisplay()->mFloats == NS_STYLE_FLOAT_LEFT) {
237 : // A left float.
238 0 : nscoord rightEdge = fi.mRect.XMost();
239 0 : if (rightEdge > left) {
240 0 : left = rightEdge;
241 : // Only set haveFloats to true if the float is inside our
242 : // containing block. This matches the spec for what some
243 : // callers want and disagrees for other callers, so we should
244 : // probably provide better information at some point.
245 0 : haveFloats = true;
246 : }
247 : } else {
248 : // A right float.
249 0 : nscoord leftEdge = fi.mRect.x;
250 0 : if (leftEdge < right) {
251 0 : right = leftEdge;
252 : // See above.
253 0 : haveFloats = true;
254 : }
255 : }
256 : }
257 : }
258 :
259 0 : nscoord height = (bottom == nscoord_MAX) ? nscoord_MAX : (bottom - top);
260 0 : return nsFlowAreaRect(left - mX, top - mY, right - left, height, haveFloats);
261 : }
262 :
263 : nsresult
264 0 : nsFloatManager::AddFloat(nsIFrame* aFloatFrame, const nsRect& aMarginRect)
265 : {
266 0 : NS_ASSERTION(aMarginRect.width >= 0, "negative width!");
267 0 : NS_ASSERTION(aMarginRect.height >= 0, "negative height!");
268 :
269 0 : FloatInfo info(aFloatFrame, aMarginRect + nsPoint(mX, mY));
270 :
271 : // Set mLeftYMost and mRightYMost.
272 0 : if (HasAnyFloats()) {
273 0 : FloatInfo &tail = mFloats[mFloats.Length() - 1];
274 0 : info.mLeftYMost = tail.mLeftYMost;
275 0 : info.mRightYMost = tail.mRightYMost;
276 : } else {
277 0 : info.mLeftYMost = nscoord_MIN;
278 0 : info.mRightYMost = nscoord_MIN;
279 : }
280 0 : PRUint8 floatStyle = aFloatFrame->GetStyleDisplay()->mFloats;
281 0 : NS_ASSERTION(floatStyle == NS_STYLE_FLOAT_LEFT ||
282 : floatStyle == NS_STYLE_FLOAT_RIGHT, "unexpected float");
283 : nscoord& sideYMost = (floatStyle == NS_STYLE_FLOAT_LEFT) ? info.mLeftYMost
284 0 : : info.mRightYMost;
285 0 : nscoord thisYMost = info.mRect.YMost();
286 0 : if (thisYMost > sideYMost)
287 0 : sideYMost = thisYMost;
288 :
289 0 : if (!mFloats.AppendElement(info))
290 0 : return NS_ERROR_OUT_OF_MEMORY;
291 :
292 0 : return NS_OK;
293 : }
294 :
295 : nsRect
296 0 : nsFloatManager::CalculateRegionFor(nsIFrame* aFloat,
297 : const nsMargin& aMargin)
298 : {
299 0 : nsRect region = aFloat->GetRect();
300 :
301 : // Float region includes its margin
302 0 : region.Inflate(aMargin);
303 :
304 : // If the element is relatively positioned, then adjust x and y
305 : // accordingly so that we consider relatively positioned frames
306 : // at their original position.
307 0 : const nsStyleDisplay* display = aFloat->GetStyleDisplay();
308 0 : region -= aFloat->GetRelativeOffset(display);
309 :
310 : // Don't store rectangles with negative margin-box width or height in
311 : // the float manager; it can't deal with them.
312 0 : if (region.width < 0) {
313 : // Preserve the right margin-edge for left floats and the left
314 : // margin-edge for right floats
315 0 : if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
316 0 : region.x = region.XMost();
317 : }
318 0 : region.width = 0;
319 : }
320 0 : if (region.height < 0) {
321 0 : region.height = 0;
322 : }
323 : return region;
324 : }
325 :
326 0 : NS_DECLARE_FRAME_PROPERTY(FloatRegionProperty, nsIFrame::DestroyMargin)
327 :
328 : nsRect
329 0 : nsFloatManager::GetRegionFor(nsIFrame* aFloat)
330 : {
331 0 : nsRect region = aFloat->GetRect();
332 0 : void* storedRegion = aFloat->Properties().Get(FloatRegionProperty());
333 0 : if (storedRegion) {
334 0 : nsMargin margin = *static_cast<nsMargin*>(storedRegion);
335 0 : region.Inflate(margin);
336 : }
337 : return region;
338 : }
339 :
340 : void
341 0 : nsFloatManager::StoreRegionFor(nsIFrame* aFloat,
342 : nsRect& aRegion)
343 : {
344 0 : nsRect rect = aFloat->GetRect();
345 0 : FrameProperties props = aFloat->Properties();
346 0 : if (aRegion.IsEqualEdges(rect)) {
347 0 : props.Delete(FloatRegionProperty());
348 : }
349 : else {
350 : nsMargin* storedMargin = static_cast<nsMargin*>
351 0 : (props.Get(FloatRegionProperty()));
352 0 : if (!storedMargin) {
353 0 : storedMargin = new nsMargin();
354 0 : props.Set(FloatRegionProperty(), storedMargin);
355 : }
356 0 : *storedMargin = aRegion - rect;
357 : }
358 0 : }
359 :
360 : nsresult
361 0 : nsFloatManager::RemoveTrailingRegions(nsIFrame* aFrameList)
362 : {
363 0 : if (!aFrameList) {
364 0 : return NS_OK;
365 : }
366 : // This could be a good bit simpler if we could guarantee that the
367 : // floats given were at the end of our list, so we could just search
368 : // for the head of aFrameList. (But we can't;
369 : // layout/reftests/bugs/421710-1.html crashes.)
370 0 : nsTHashtable<nsPtrHashKey<nsIFrame> > frameSet;
371 :
372 0 : frameSet.Init(1);
373 0 : for (nsIFrame* f = aFrameList; f; f = f->GetNextSibling()) {
374 0 : frameSet.PutEntry(f);
375 : }
376 :
377 0 : PRUint32 newLength = mFloats.Length();
378 0 : while (newLength > 0) {
379 0 : if (!frameSet.Contains(mFloats[newLength - 1].mFrame)) {
380 0 : break;
381 : }
382 0 : --newLength;
383 : }
384 0 : mFloats.TruncateLength(newLength);
385 :
386 : #ifdef DEBUG
387 0 : for (PRUint32 i = 0; i < mFloats.Length(); ++i) {
388 0 : NS_ASSERTION(!frameSet.Contains(mFloats[i].mFrame),
389 : "Frame region deletion was requested but we couldn't delete it");
390 : }
391 : #endif
392 :
393 0 : return NS_OK;
394 : }
395 :
396 : void
397 0 : nsFloatManager::PushState(SavedState* aState)
398 : {
399 0 : NS_PRECONDITION(aState, "Need a place to save state");
400 :
401 : // This is a cheap push implementation, which
402 : // only saves the (x,y) and last frame in the mFrameInfoMap
403 : // which is enough info to get us back to where we should be
404 : // when pop is called.
405 : //
406 : // This push/pop mechanism is used to undo any
407 : // floats that were added during the unconstrained reflow
408 : // in nsBlockReflowContext::DoReflowBlock(). (See bug 96736)
409 : //
410 : // It should also be noted that the state for mFloatDamage is
411 : // intentionally not saved or restored in PushState() and PopState(),
412 : // since that could lead to bugs where damage is missed/dropped when
413 : // we move from position A to B (during the intermediate incremental
414 : // reflow mentioned above) and then from B to C during the subsequent
415 : // reflow. In the typical case A and C will be the same, but not always.
416 : // Allowing mFloatDamage to accumulate the damage incurred during both
417 : // reflows ensures that nothing gets missed.
418 0 : aState->mX = mX;
419 0 : aState->mY = mY;
420 0 : aState->mPushedLeftFloatPastBreak = mPushedLeftFloatPastBreak;
421 0 : aState->mPushedRightFloatPastBreak = mPushedRightFloatPastBreak;
422 0 : aState->mSplitLeftFloatAcrossBreak = mSplitLeftFloatAcrossBreak;
423 0 : aState->mSplitRightFloatAcrossBreak = mSplitRightFloatAcrossBreak;
424 0 : aState->mFloatInfoCount = mFloats.Length();
425 0 : }
426 :
427 : void
428 0 : nsFloatManager::PopState(SavedState* aState)
429 : {
430 0 : NS_PRECONDITION(aState, "No state to restore?");
431 :
432 0 : mX = aState->mX;
433 0 : mY = aState->mY;
434 0 : mPushedLeftFloatPastBreak = aState->mPushedLeftFloatPastBreak;
435 0 : mPushedRightFloatPastBreak = aState->mPushedRightFloatPastBreak;
436 0 : mSplitLeftFloatAcrossBreak = aState->mSplitLeftFloatAcrossBreak;
437 0 : mSplitRightFloatAcrossBreak = aState->mSplitRightFloatAcrossBreak;
438 :
439 0 : NS_ASSERTION(aState->mFloatInfoCount <= mFloats.Length(),
440 : "somebody misused PushState/PopState");
441 0 : mFloats.TruncateLength(aState->mFloatInfoCount);
442 0 : }
443 :
444 : nscoord
445 0 : nsFloatManager::GetLowestFloatTop() const
446 : {
447 0 : if (mPushedLeftFloatPastBreak || mPushedRightFloatPastBreak) {
448 0 : return nscoord_MAX;
449 : }
450 0 : if (!HasAnyFloats()) {
451 0 : return nscoord_MIN;
452 : }
453 0 : return mFloats[mFloats.Length() - 1].mRect.y - mY;
454 : }
455 :
456 : #ifdef DEBUG
457 : void
458 0 : DebugListFloatManager(const nsFloatManager *aFloatManager)
459 : {
460 0 : aFloatManager->List(stdout);
461 0 : }
462 :
463 : nsresult
464 0 : nsFloatManager::List(FILE* out) const
465 : {
466 0 : if (!HasAnyFloats())
467 0 : return NS_OK;
468 :
469 0 : for (PRUint32 i = 0; i < mFloats.Length(); ++i) {
470 0 : const FloatInfo &fi = mFloats[i];
471 : printf("Float %u: frame=%p rect={%d,%d,%d,%d} ymost={l:%d, r:%d}\n",
472 : i, static_cast<void*>(fi.mFrame),
473 : fi.mRect.x, fi.mRect.y, fi.mRect.width, fi.mRect.height,
474 0 : fi.mLeftYMost, fi.mRightYMost);
475 : }
476 0 : return NS_OK;
477 : }
478 : #endif
479 :
480 : nscoord
481 0 : nsFloatManager::ClearFloats(nscoord aY, PRUint8 aBreakType,
482 : PRUint32 aFlags) const
483 : {
484 0 : if (!(aFlags & DONT_CLEAR_PUSHED_FLOATS) && ClearContinues(aBreakType)) {
485 0 : return nscoord_MAX;
486 : }
487 0 : if (!HasAnyFloats()) {
488 0 : return aY;
489 : }
490 :
491 0 : nscoord bottom = aY + mY;
492 :
493 0 : const FloatInfo &tail = mFloats[mFloats.Length() - 1];
494 0 : switch (aBreakType) {
495 : case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
496 0 : bottom = NS_MAX(bottom, tail.mLeftYMost);
497 0 : bottom = NS_MAX(bottom, tail.mRightYMost);
498 0 : break;
499 : case NS_STYLE_CLEAR_LEFT:
500 0 : bottom = NS_MAX(bottom, tail.mLeftYMost);
501 0 : break;
502 : case NS_STYLE_CLEAR_RIGHT:
503 0 : bottom = NS_MAX(bottom, tail.mRightYMost);
504 0 : break;
505 : default:
506 : // Do nothing
507 0 : break;
508 : }
509 :
510 0 : bottom -= mY;
511 :
512 0 : return bottom;
513 : }
514 :
515 : bool
516 0 : nsFloatManager::ClearContinues(PRUint8 aBreakType) const
517 : {
518 : return ((mPushedLeftFloatPastBreak || mSplitLeftFloatAcrossBreak) &&
519 : (aBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT ||
520 : aBreakType == NS_STYLE_CLEAR_LEFT)) ||
521 : ((mPushedRightFloatPastBreak || mSplitRightFloatAcrossBreak) &&
522 : (aBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT ||
523 0 : aBreakType == NS_STYLE_CLEAR_RIGHT));
524 : }
525 :
526 : /////////////////////////////////////////////////////////////////////////////
527 : // FloatInfo
528 :
529 0 : nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame, const nsRect& aRect)
530 0 : : mFrame(aFrame), mRect(aRect)
531 : {
532 0 : MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
533 0 : }
534 :
535 : #ifdef NS_BUILD_REFCNT_LOGGING
536 0 : nsFloatManager::FloatInfo::FloatInfo(const FloatInfo& aOther)
537 : : mFrame(aOther.mFrame),
538 : mRect(aOther.mRect),
539 : mLeftYMost(aOther.mLeftYMost),
540 0 : mRightYMost(aOther.mRightYMost)
541 : {
542 0 : MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
543 0 : }
544 :
545 0 : nsFloatManager::FloatInfo::~FloatInfo()
546 : {
547 0 : MOZ_COUNT_DTOR(nsFloatManager::FloatInfo);
548 0 : }
549 : #endif
550 :
551 : //----------------------------------------------------------------------
552 :
553 0 : nsAutoFloatManager::~nsAutoFloatManager()
554 : {
555 : // Restore the old float manager in the reflow state if necessary.
556 0 : if (mNew) {
557 : #ifdef NOISY_FLOATMANAGER
558 : printf("restoring old float manager %p\n", mOld);
559 : #endif
560 :
561 0 : mReflowState.mFloatManager = mOld;
562 :
563 : #ifdef NOISY_FLOATMANAGER
564 : if (mOld) {
565 : static_cast<nsFrame *>(mReflowState.frame)->ListTag(stdout);
566 : printf(": space-manager %p after reflow\n", mOld);
567 : mOld->List(stdout);
568 : }
569 : #endif
570 :
571 0 : delete mNew;
572 : }
573 0 : }
574 :
575 : nsresult
576 0 : nsAutoFloatManager::CreateFloatManager(nsPresContext *aPresContext)
577 : {
578 : // Create a new float manager and install it in the reflow
579 : // state. `Remember' the old float manager so we can restore it
580 : // later.
581 0 : mNew = new nsFloatManager(aPresContext->PresShell());
582 0 : if (! mNew)
583 0 : return NS_ERROR_OUT_OF_MEMORY;
584 :
585 : #ifdef NOISY_FLOATMANAGER
586 : printf("constructed new float manager %p (replacing %p)\n",
587 : mNew, mReflowState.mFloatManager);
588 : #endif
589 :
590 : // Set the float manager in the existing reflow state
591 0 : mOld = mReflowState.mFloatManager;
592 0 : mReflowState.mFloatManager = mNew;
593 0 : return NS_OK;
594 : }
|