layout/generic/nsFloatManager.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial