1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/generic/nsLineBox.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,988 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +// vim:cindent:ts=2:et:sw=2: 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* representation of one line within a block frame, a CSS line box */ 1.11 + 1.12 +#include "nsLineBox.h" 1.13 +#include "prprf.h" 1.14 +#include "nsFrame.h" 1.15 +#include "nsPresArena.h" 1.16 +#include "nsBidiPresUtils.h" 1.17 +#include "nsIFrameInlines.h" 1.18 +#include "WritingModes.h" 1.19 +#include "mozilla/Assertions.h" 1.20 +#include "mozilla/Likely.h" 1.21 +#include "nsPrintfCString.h" 1.22 + 1.23 +#ifdef DEBUG 1.24 +static int32_t ctorCount; 1.25 +int32_t nsLineBox::GetCtorCount() { return ctorCount; } 1.26 +#endif 1.27 + 1.28 +#ifndef _MSC_VER 1.29 +// static nsLineBox constant; initialized in the header file. 1.30 +const uint32_t nsLineBox::kMinChildCountForHashtable; 1.31 +#endif 1.32 + 1.33 +using namespace mozilla; 1.34 + 1.35 +nsLineBox::nsLineBox(nsIFrame* aFrame, int32_t aCount, bool aIsBlock) 1.36 + : mFirstChild(aFrame) 1.37 + , mContainerWidth(-1) 1.38 + , mBounds(WritingMode()) // mBounds will be initialized with the correct 1.39 + // writing mode when it is set 1.40 +// NOTE: memory is already zeroed since we allocate with AllocateByObjectID. 1.41 +{ 1.42 + MOZ_COUNT_CTOR(nsLineBox); 1.43 +#ifdef DEBUG 1.44 + ++ctorCount; 1.45 + NS_ASSERTION(!aIsBlock || aCount == 1, "Blocks must have exactly one child"); 1.46 + nsIFrame* f = aFrame; 1.47 + for (int32_t n = aCount; n > 0; f = f->GetNextSibling(), --n) { 1.48 + NS_ASSERTION(aIsBlock == f->IsBlockOutside(), 1.49 + "wrong kind of child frame"); 1.50 + } 1.51 +#endif 1.52 + 1.53 + static_assert(NS_STYLE_CLEAR_MAX <= 15, 1.54 + "FlagBits needs more bits to store the full range of " 1.55 + "break type ('clear') values"); 1.56 +#if NS_STYLE_CLEAR_NONE > 0 1.57 + mFlags.mBreakType = NS_STYLE_CLEAR_NONE; 1.58 +#endif 1.59 + mChildCount = aCount; 1.60 + MarkDirty(); 1.61 + mFlags.mBlock = aIsBlock; 1.62 +} 1.63 + 1.64 +nsLineBox::~nsLineBox() 1.65 +{ 1.66 + MOZ_COUNT_DTOR(nsLineBox); 1.67 + if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) { 1.68 + delete mFrames; 1.69 + } 1.70 + Cleanup(); 1.71 +} 1.72 + 1.73 +nsLineBox* 1.74 +NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame, bool aIsBlock) 1.75 +{ 1.76 + return new (aPresShell) nsLineBox(aFrame, 1, aIsBlock); 1.77 +} 1.78 + 1.79 +nsLineBox* 1.80 +NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine, 1.81 + nsIFrame* aFrame, int32_t aCount) 1.82 +{ 1.83 + nsLineBox* newLine = new (aPresShell) nsLineBox(aFrame, aCount, false); 1.84 + newLine->NoteFramesMovedFrom(aFromLine); 1.85 + newLine->mContainerWidth = aFromLine->mContainerWidth; 1.86 + return newLine; 1.87 +} 1.88 + 1.89 +void 1.90 +nsLineBox::StealHashTableFrom(nsLineBox* aFromLine, uint32_t aFromLineNewCount) 1.91 +{ 1.92 + MOZ_ASSERT(!mFlags.mHasHashedFrames); 1.93 + MOZ_ASSERT(GetChildCount() >= int32_t(aFromLineNewCount)); 1.94 + mFrames = aFromLine->mFrames; 1.95 + mFlags.mHasHashedFrames = 1; 1.96 + aFromLine->mFlags.mHasHashedFrames = 0; 1.97 + aFromLine->mChildCount = aFromLineNewCount; 1.98 + // remove aFromLine's frames that aren't on this line 1.99 + nsIFrame* f = aFromLine->mFirstChild; 1.100 + for (uint32_t i = 0; i < aFromLineNewCount; f = f->GetNextSibling(), ++i) { 1.101 + mFrames->RemoveEntry(f); 1.102 + } 1.103 +} 1.104 + 1.105 +void 1.106 +nsLineBox::NoteFramesMovedFrom(nsLineBox* aFromLine) 1.107 +{ 1.108 + uint32_t fromCount = aFromLine->GetChildCount(); 1.109 + uint32_t toCount = GetChildCount(); 1.110 + MOZ_ASSERT(toCount <= fromCount, "moved more frames than aFromLine has"); 1.111 + uint32_t fromNewCount = fromCount - toCount; 1.112 + if (MOZ_LIKELY(!aFromLine->mFlags.mHasHashedFrames)) { 1.113 + aFromLine->mChildCount = fromNewCount; 1.114 + MOZ_ASSERT(toCount < kMinChildCountForHashtable); 1.115 + } else if (fromNewCount < kMinChildCountForHashtable) { 1.116 + // aFromLine has a hash table but will not have it after moving the frames 1.117 + // so this line can steal the hash table if it needs it. 1.118 + if (toCount >= kMinChildCountForHashtable) { 1.119 + StealHashTableFrom(aFromLine, fromNewCount); 1.120 + } else { 1.121 + delete aFromLine->mFrames; 1.122 + aFromLine->mFlags.mHasHashedFrames = 0; 1.123 + aFromLine->mChildCount = fromNewCount; 1.124 + } 1.125 + } else { 1.126 + // aFromLine still needs a hash table. 1.127 + if (toCount < kMinChildCountForHashtable) { 1.128 + // remove the moved frames from it 1.129 + nsIFrame* f = mFirstChild; 1.130 + for (uint32_t i = 0; i < toCount; f = f->GetNextSibling(), ++i) { 1.131 + aFromLine->mFrames->RemoveEntry(f); 1.132 + } 1.133 + } else if (toCount <= fromNewCount) { 1.134 + // This line needs a hash table, allocate a hash table for it since that 1.135 + // means fewer hash ops. 1.136 + nsIFrame* f = mFirstChild; 1.137 + for (uint32_t i = 0; i < toCount; f = f->GetNextSibling(), ++i) { 1.138 + aFromLine->mFrames->RemoveEntry(f); // toCount RemoveEntry 1.139 + } 1.140 + SwitchToHashtable(); // toCount PutEntry 1.141 + } else { 1.142 + // This line needs a hash table, but it's fewer hash ops to steal 1.143 + // aFromLine's hash table and allocate a new hash table for that line. 1.144 + StealHashTableFrom(aFromLine, fromNewCount); // fromNewCount RemoveEntry 1.145 + aFromLine->SwitchToHashtable(); // fromNewCount PutEntry 1.146 + } 1.147 + } 1.148 +} 1.149 + 1.150 +// Overloaded new operator. Uses an arena (which comes from the presShell) 1.151 +// to perform the allocation. 1.152 +void* 1.153 +nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW 1.154 +{ 1.155 + return aPresShell->AllocateByObjectID(nsPresArena::nsLineBox_id, sz); 1.156 +} 1.157 + 1.158 +void 1.159 +nsLineBox::Destroy(nsIPresShell* aPresShell) 1.160 +{ 1.161 + this->nsLineBox::~nsLineBox(); 1.162 + aPresShell->FreeByObjectID(nsPresArena::nsLineBox_id, this); 1.163 +} 1.164 + 1.165 +void 1.166 +nsLineBox::Cleanup() 1.167 +{ 1.168 + if (mData) { 1.169 + if (IsBlock()) { 1.170 + delete mBlockData; 1.171 + } 1.172 + else { 1.173 + delete mInlineData; 1.174 + } 1.175 + mData = nullptr; 1.176 + } 1.177 +} 1.178 + 1.179 +#ifdef DEBUG_FRAME_DUMP 1.180 +static void 1.181 +ListFloats(FILE* out, const char* aPrefix, const nsFloatCacheList& aFloats) 1.182 +{ 1.183 + nsFloatCache* fc = aFloats.Head(); 1.184 + while (fc) { 1.185 + nsCString str(aPrefix); 1.186 + nsIFrame* frame = fc->mFloat; 1.187 + str += nsPrintfCString("floatframe@%p ", static_cast<void*>(frame)); 1.188 + if (frame) { 1.189 + nsAutoString frameName; 1.190 + frame->GetFrameName(frameName); 1.191 + str += NS_ConvertUTF16toUTF8(frameName).get(); 1.192 + } 1.193 + else { 1.194 + str += "\n###!!! NULL out-of-flow frame"; 1.195 + } 1.196 + fprintf_stderr(out, "%s\n", str.get()); 1.197 + fc = fc->Next(); 1.198 + } 1.199 +} 1.200 + 1.201 +const char * 1.202 +BreakTypeToString(uint8_t aBreakType) 1.203 +{ 1.204 + switch (aBreakType) { 1.205 + case NS_STYLE_CLEAR_NONE: return "nobr"; 1.206 + case NS_STYLE_CLEAR_LEFT: return "leftbr"; 1.207 + case NS_STYLE_CLEAR_RIGHT: return "rightbr"; 1.208 + case NS_STYLE_CLEAR_BOTH: return "leftbr+rightbr"; 1.209 + case NS_STYLE_CLEAR_LINE: return "linebr"; 1.210 + default: 1.211 + break; 1.212 + } 1.213 + return "unknown"; 1.214 +} 1.215 + 1.216 +char* 1.217 +nsLineBox::StateToString(char* aBuf, int32_t aBufSize) const 1.218 +{ 1.219 + PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s,%s,before:%s,after:%s[0x%x]", 1.220 + IsBlock() ? "block" : "inline", 1.221 + IsDirty() ? "dirty" : "clean", 1.222 + IsPreviousMarginDirty() ? "prevmargindirty" : "prevmarginclean", 1.223 + IsImpactedByFloat() ? "impacted" : "not impacted", 1.224 + IsLineWrapped() ? "wrapped" : "not wrapped", 1.225 + BreakTypeToString(GetBreakTypeBefore()), 1.226 + BreakTypeToString(GetBreakTypeAfter()), 1.227 + mAllFlags); 1.228 + return aBuf; 1.229 +} 1.230 + 1.231 +void 1.232 +nsLineBox::List(FILE* out, int32_t aIndent, uint32_t aFlags) const 1.233 +{ 1.234 + nsCString str; 1.235 + while (aIndent-- > 0) { 1.236 + str += " "; 1.237 + } 1.238 + List(out, str.get(), aFlags); 1.239 +} 1.240 + 1.241 +void 1.242 +nsLineBox::List(FILE* out, const char* aPrefix, uint32_t aFlags) const 1.243 +{ 1.244 + nsCString str(aPrefix); 1.245 + char cbuf[100]; 1.246 + str += nsPrintfCString("line %p: count=%d state=%s ", 1.247 + static_cast<const void*>(this), GetChildCount(), 1.248 + StateToString(cbuf, sizeof(cbuf))); 1.249 + if (IsBlock() && !GetCarriedOutBottomMargin().IsZero()) { 1.250 + str += nsPrintfCString("bm=%d ", GetCarriedOutBottomMargin().get()); 1.251 + } 1.252 + nsRect bounds = GetPhysicalBounds(); 1.253 + str += nsPrintfCString("{%d,%d,%d,%d} ", 1.254 + bounds.x, bounds.y, bounds.width, bounds.height); 1.255 + if (mData && 1.256 + (!mData->mOverflowAreas.VisualOverflow().IsEqualEdges(bounds) || 1.257 + !mData->mOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds))) { 1.258 + str += nsPrintfCString("vis-overflow=%d,%d,%d,%d scr-overflow=%d,%d,%d,%d ", 1.259 + mData->mOverflowAreas.VisualOverflow().x, 1.260 + mData->mOverflowAreas.VisualOverflow().y, 1.261 + mData->mOverflowAreas.VisualOverflow().width, 1.262 + mData->mOverflowAreas.VisualOverflow().height, 1.263 + mData->mOverflowAreas.ScrollableOverflow().x, 1.264 + mData->mOverflowAreas.ScrollableOverflow().y, 1.265 + mData->mOverflowAreas.ScrollableOverflow().width, 1.266 + mData->mOverflowAreas.ScrollableOverflow().height); 1.267 + } 1.268 + fprintf_stderr(out, "%s<\n", str.get()); 1.269 + 1.270 + nsIFrame* frame = mFirstChild; 1.271 + int32_t n = GetChildCount(); 1.272 + nsCString pfx(aPrefix); 1.273 + pfx += " "; 1.274 + while (--n >= 0) { 1.275 + frame->List(out, pfx.get(), aFlags); 1.276 + frame = frame->GetNextSibling(); 1.277 + } 1.278 + 1.279 + if (HasFloats()) { 1.280 + fprintf_stderr(out, "%s> floats <\n", aPrefix); 1.281 + ListFloats(out, pfx.get(), mInlineData->mFloats); 1.282 + } 1.283 + fprintf_stderr(out, "%s>\n", aPrefix); 1.284 +} 1.285 +#endif 1.286 + 1.287 +#ifdef DEBUG 1.288 +nsIFrame* 1.289 +nsLineBox::LastChild() const 1.290 +{ 1.291 + nsIFrame* frame = mFirstChild; 1.292 + int32_t n = GetChildCount() - 1; 1.293 + while (--n >= 0) { 1.294 + frame = frame->GetNextSibling(); 1.295 + } 1.296 + return frame; 1.297 +} 1.298 +#endif 1.299 + 1.300 +int32_t 1.301 +nsLineBox::IndexOf(nsIFrame* aFrame) const 1.302 +{ 1.303 + int32_t i, n = GetChildCount(); 1.304 + nsIFrame* frame = mFirstChild; 1.305 + for (i = 0; i < n; i++) { 1.306 + if (frame == aFrame) { 1.307 + return i; 1.308 + } 1.309 + frame = frame->GetNextSibling(); 1.310 + } 1.311 + return -1; 1.312 +} 1.313 + 1.314 +bool 1.315 +nsLineBox::IsEmpty() const 1.316 +{ 1.317 + if (IsBlock()) 1.318 + return mFirstChild->IsEmpty(); 1.319 + 1.320 + int32_t n; 1.321 + nsIFrame *kid; 1.322 + for (n = GetChildCount(), kid = mFirstChild; 1.323 + n > 0; 1.324 + --n, kid = kid->GetNextSibling()) 1.325 + { 1.326 + if (!kid->IsEmpty()) 1.327 + return false; 1.328 + } 1.329 + if (HasBullet()) { 1.330 + return false; 1.331 + } 1.332 + return true; 1.333 +} 1.334 + 1.335 +bool 1.336 +nsLineBox::CachedIsEmpty() 1.337 +{ 1.338 + if (mFlags.mDirty) { 1.339 + return IsEmpty(); 1.340 + } 1.341 + 1.342 + if (mFlags.mEmptyCacheValid) { 1.343 + return mFlags.mEmptyCacheState; 1.344 + } 1.345 + 1.346 + bool result; 1.347 + if (IsBlock()) { 1.348 + result = mFirstChild->CachedIsEmpty(); 1.349 + } else { 1.350 + int32_t n; 1.351 + nsIFrame *kid; 1.352 + result = true; 1.353 + for (n = GetChildCount(), kid = mFirstChild; 1.354 + n > 0; 1.355 + --n, kid = kid->GetNextSibling()) 1.356 + { 1.357 + if (!kid->CachedIsEmpty()) { 1.358 + result = false; 1.359 + break; 1.360 + } 1.361 + } 1.362 + if (HasBullet()) { 1.363 + result = false; 1.364 + } 1.365 + } 1.366 + 1.367 + mFlags.mEmptyCacheValid = true; 1.368 + mFlags.mEmptyCacheState = result; 1.369 + return result; 1.370 +} 1.371 + 1.372 +void 1.373 +nsLineBox::DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines, 1.374 + nsIFrame* aDestructRoot, nsFrameList* aFrames) 1.375 +{ 1.376 + nsIPresShell* shell = aPresContext->PresShell(); 1.377 + 1.378 + // Keep our line list and frame list up to date as we 1.379 + // remove frames, in case something wants to traverse the 1.380 + // frame tree while we're destroying. 1.381 + while (!aLines.empty()) { 1.382 + nsLineBox* line = aLines.front(); 1.383 + if (MOZ_UNLIKELY(line->mFlags.mHasHashedFrames)) { 1.384 + line->SwitchToCounter(); // Avoid expensive has table removals. 1.385 + } 1.386 + while (line->GetChildCount() > 0) { 1.387 + nsIFrame* child = aFrames->RemoveFirstChild(); 1.388 + MOZ_ASSERT(child == line->mFirstChild, "Lines out of sync"); 1.389 + line->mFirstChild = aFrames->FirstChild(); 1.390 + line->NoteFrameRemoved(child); 1.391 + child->DestroyFrom(aDestructRoot); 1.392 + } 1.393 + 1.394 + aLines.pop_front(); 1.395 + line->Destroy(shell); 1.396 + } 1.397 +} 1.398 + 1.399 +bool 1.400 +nsLineBox::RFindLineContaining(nsIFrame* aFrame, 1.401 + const nsLineList::iterator& aBegin, 1.402 + nsLineList::iterator& aEnd, 1.403 + nsIFrame* aLastFrameBeforeEnd, 1.404 + int32_t* aFrameIndexInLine) 1.405 +{ 1.406 + NS_PRECONDITION(aFrame, "null ptr"); 1.407 + 1.408 + nsIFrame* curFrame = aLastFrameBeforeEnd; 1.409 + while (aBegin != aEnd) { 1.410 + --aEnd; 1.411 + NS_ASSERTION(aEnd->LastChild() == curFrame, "Unexpected curFrame"); 1.412 + if (MOZ_UNLIKELY(aEnd->mFlags.mHasHashedFrames) && 1.413 + !aEnd->Contains(aFrame)) { 1.414 + if (aEnd->mFirstChild) { 1.415 + curFrame = aEnd->mFirstChild->GetPrevSibling(); 1.416 + } 1.417 + continue; 1.418 + } 1.419 + // i is the index of curFrame in aEnd 1.420 + int32_t i = aEnd->GetChildCount() - 1; 1.421 + while (i >= 0) { 1.422 + if (curFrame == aFrame) { 1.423 + *aFrameIndexInLine = i; 1.424 + return true; 1.425 + } 1.426 + --i; 1.427 + curFrame = curFrame->GetPrevSibling(); 1.428 + } 1.429 + MOZ_ASSERT(!aEnd->mFlags.mHasHashedFrames, "Contains lied to us!"); 1.430 + } 1.431 + *aFrameIndexInLine = -1; 1.432 + return false; 1.433 +} 1.434 + 1.435 +nsCollapsingMargin 1.436 +nsLineBox::GetCarriedOutBottomMargin() const 1.437 +{ 1.438 + NS_ASSERTION(IsBlock(), 1.439 + "GetCarriedOutBottomMargin called on non-block line."); 1.440 + return (IsBlock() && mBlockData) 1.441 + ? mBlockData->mCarriedOutBottomMargin 1.442 + : nsCollapsingMargin(); 1.443 +} 1.444 + 1.445 +bool 1.446 +nsLineBox::SetCarriedOutBottomMargin(nsCollapsingMargin aValue) 1.447 +{ 1.448 + bool changed = false; 1.449 + if (IsBlock()) { 1.450 + if (!aValue.IsZero()) { 1.451 + if (!mBlockData) { 1.452 + mBlockData = new ExtraBlockData(GetPhysicalBounds()); 1.453 + } 1.454 + changed = aValue != mBlockData->mCarriedOutBottomMargin; 1.455 + mBlockData->mCarriedOutBottomMargin = aValue; 1.456 + } 1.457 + else if (mBlockData) { 1.458 + changed = aValue != mBlockData->mCarriedOutBottomMargin; 1.459 + mBlockData->mCarriedOutBottomMargin = aValue; 1.460 + MaybeFreeData(); 1.461 + } 1.462 + } 1.463 + return changed; 1.464 +} 1.465 + 1.466 +void 1.467 +nsLineBox::MaybeFreeData() 1.468 +{ 1.469 + nsRect bounds = GetPhysicalBounds(); 1.470 + if (mData && mData->mOverflowAreas == nsOverflowAreas(bounds, bounds)) { 1.471 + if (IsInline()) { 1.472 + if (mInlineData->mFloats.IsEmpty()) { 1.473 + delete mInlineData; 1.474 + mInlineData = nullptr; 1.475 + } 1.476 + } 1.477 + else if (mBlockData->mCarriedOutBottomMargin.IsZero()) { 1.478 + delete mBlockData; 1.479 + mBlockData = nullptr; 1.480 + } 1.481 + } 1.482 +} 1.483 + 1.484 +// XXX get rid of this??? 1.485 +nsFloatCache* 1.486 +nsLineBox::GetFirstFloat() 1.487 +{ 1.488 + NS_ABORT_IF_FALSE(IsInline(), "block line can't have floats"); 1.489 + return mInlineData ? mInlineData->mFloats.Head() : nullptr; 1.490 +} 1.491 + 1.492 +// XXX this might be too eager to free memory 1.493 +void 1.494 +nsLineBox::FreeFloats(nsFloatCacheFreeList& aFreeList) 1.495 +{ 1.496 + NS_ABORT_IF_FALSE(IsInline(), "block line can't have floats"); 1.497 + if (IsInline() && mInlineData) { 1.498 + if (mInlineData->mFloats.NotEmpty()) { 1.499 + aFreeList.Append(mInlineData->mFloats); 1.500 + } 1.501 + MaybeFreeData(); 1.502 + } 1.503 +} 1.504 + 1.505 +void 1.506 +nsLineBox::AppendFloats(nsFloatCacheFreeList& aFreeList) 1.507 +{ 1.508 + NS_ABORT_IF_FALSE(IsInline(), "block line can't have floats"); 1.509 + if (IsInline()) { 1.510 + if (aFreeList.NotEmpty()) { 1.511 + if (!mInlineData) { 1.512 + mInlineData = new ExtraInlineData(GetPhysicalBounds()); 1.513 + } 1.514 + mInlineData->mFloats.Append(aFreeList); 1.515 + } 1.516 + } 1.517 +} 1.518 + 1.519 +bool 1.520 +nsLineBox::RemoveFloat(nsIFrame* aFrame) 1.521 +{ 1.522 + NS_ABORT_IF_FALSE(IsInline(), "block line can't have floats"); 1.523 + if (IsInline() && mInlineData) { 1.524 + nsFloatCache* fc = mInlineData->mFloats.Find(aFrame); 1.525 + if (fc) { 1.526 + // Note: the placeholder is part of the line's child list 1.527 + // and will be removed later. 1.528 + mInlineData->mFloats.Remove(fc); 1.529 + delete fc; 1.530 + MaybeFreeData(); 1.531 + return true; 1.532 + } 1.533 + } 1.534 + return false; 1.535 +} 1.536 + 1.537 +void 1.538 +nsLineBox::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas) 1.539 +{ 1.540 + NS_FOR_FRAME_OVERFLOW_TYPES(otype) { 1.541 + NS_ASSERTION(aOverflowAreas.Overflow(otype).width >= 0, 1.542 + "illegal width for combined area"); 1.543 + NS_ASSERTION(aOverflowAreas.Overflow(otype).height >= 0, 1.544 + "illegal height for combined area"); 1.545 + } 1.546 + nsRect bounds = GetPhysicalBounds(); 1.547 + if (!aOverflowAreas.VisualOverflow().IsEqualInterior(bounds) || 1.548 + !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) { 1.549 + if (!mData) { 1.550 + if (IsInline()) { 1.551 + mInlineData = new ExtraInlineData(bounds); 1.552 + } 1.553 + else { 1.554 + mBlockData = new ExtraBlockData(bounds); 1.555 + } 1.556 + } 1.557 + mData->mOverflowAreas = aOverflowAreas; 1.558 + } 1.559 + else if (mData) { 1.560 + // Store away new value so that MaybeFreeData compares against 1.561 + // the right value. 1.562 + mData->mOverflowAreas = aOverflowAreas; 1.563 + MaybeFreeData(); 1.564 + } 1.565 +} 1.566 + 1.567 +//---------------------------------------------------------------------- 1.568 + 1.569 + 1.570 +static nsLineBox* gDummyLines[1]; 1.571 + 1.572 +nsLineIterator::nsLineIterator() 1.573 +{ 1.574 + mLines = gDummyLines; 1.575 + mNumLines = 0; 1.576 + mIndex = 0; 1.577 + mRightToLeft = false; 1.578 +} 1.579 + 1.580 +nsLineIterator::~nsLineIterator() 1.581 +{ 1.582 + if (mLines != gDummyLines) { 1.583 + delete [] mLines; 1.584 + } 1.585 +} 1.586 + 1.587 +/* virtual */ void 1.588 +nsLineIterator::DisposeLineIterator() 1.589 +{ 1.590 + delete this; 1.591 +} 1.592 + 1.593 +nsresult 1.594 +nsLineIterator::Init(nsLineList& aLines, bool aRightToLeft) 1.595 +{ 1.596 + mRightToLeft = aRightToLeft; 1.597 + 1.598 + // Count the lines 1.599 + int32_t numLines = aLines.size(); 1.600 + if (0 == numLines) { 1.601 + // Use gDummyLines so that we don't need null pointer checks in 1.602 + // the accessor methods 1.603 + mLines = gDummyLines; 1.604 + return NS_OK; 1.605 + } 1.606 + 1.607 + // Make a linear array of the lines 1.608 + mLines = new nsLineBox*[numLines]; 1.609 + if (!mLines) { 1.610 + // Use gDummyLines so that we don't need null pointer checks in 1.611 + // the accessor methods 1.612 + mLines = gDummyLines; 1.613 + return NS_ERROR_OUT_OF_MEMORY; 1.614 + } 1.615 + nsLineBox** lp = mLines; 1.616 + for (nsLineList::iterator line = aLines.begin(), line_end = aLines.end() ; 1.617 + line != line_end; 1.618 + ++line) 1.619 + { 1.620 + *lp++ = line; 1.621 + } 1.622 + mNumLines = numLines; 1.623 + return NS_OK; 1.624 +} 1.625 + 1.626 +int32_t 1.627 +nsLineIterator::GetNumLines() 1.628 +{ 1.629 + return mNumLines; 1.630 +} 1.631 + 1.632 +bool 1.633 +nsLineIterator::GetDirection() 1.634 +{ 1.635 + return mRightToLeft; 1.636 +} 1.637 + 1.638 +NS_IMETHODIMP 1.639 +nsLineIterator::GetLine(int32_t aLineNumber, 1.640 + nsIFrame** aFirstFrameOnLine, 1.641 + int32_t* aNumFramesOnLine, 1.642 + nsRect& aLineBounds, 1.643 + uint32_t* aLineFlags) 1.644 +{ 1.645 + NS_ENSURE_ARG_POINTER(aFirstFrameOnLine); 1.646 + NS_ENSURE_ARG_POINTER(aNumFramesOnLine); 1.647 + NS_ENSURE_ARG_POINTER(aLineFlags); 1.648 + 1.649 + if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) { 1.650 + *aFirstFrameOnLine = nullptr; 1.651 + *aNumFramesOnLine = 0; 1.652 + aLineBounds.SetRect(0, 0, 0, 0); 1.653 + return NS_OK; 1.654 + } 1.655 + nsLineBox* line = mLines[aLineNumber]; 1.656 + *aFirstFrameOnLine = line->mFirstChild; 1.657 + *aNumFramesOnLine = line->GetChildCount(); 1.658 + aLineBounds = line->GetPhysicalBounds(); 1.659 + 1.660 + uint32_t flags = 0; 1.661 + if (line->IsBlock()) { 1.662 + flags |= NS_LINE_FLAG_IS_BLOCK; 1.663 + } 1.664 + else { 1.665 + if (line->HasBreakAfter()) 1.666 + flags |= NS_LINE_FLAG_ENDS_IN_BREAK; 1.667 + } 1.668 + *aLineFlags = flags; 1.669 + 1.670 + return NS_OK; 1.671 +} 1.672 + 1.673 +int32_t 1.674 +nsLineIterator::FindLineContaining(nsIFrame* aFrame, int32_t aStartLine) 1.675 +{ 1.676 + NS_PRECONDITION(aStartLine <= mNumLines, "Bogus line numbers"); 1.677 + int32_t lineNumber = aStartLine; 1.678 + while (lineNumber != mNumLines) { 1.679 + nsLineBox* line = mLines[lineNumber]; 1.680 + if (line->Contains(aFrame)) { 1.681 + return lineNumber; 1.682 + } 1.683 + ++lineNumber; 1.684 + } 1.685 + return -1; 1.686 +} 1.687 + 1.688 +NS_IMETHODIMP 1.689 +nsLineIterator::CheckLineOrder(int32_t aLine, 1.690 + bool *aIsReordered, 1.691 + nsIFrame **aFirstVisual, 1.692 + nsIFrame **aLastVisual) 1.693 +{ 1.694 + NS_ASSERTION (aLine >= 0 && aLine < mNumLines, "aLine out of range!"); 1.695 + nsLineBox* line = mLines[aLine]; 1.696 + 1.697 + if (!line->mFirstChild) { // empty line 1.698 + *aIsReordered = false; 1.699 + *aFirstVisual = nullptr; 1.700 + *aLastVisual = nullptr; 1.701 + return NS_OK; 1.702 + } 1.703 + 1.704 + nsIFrame* leftmostFrame; 1.705 + nsIFrame* rightmostFrame; 1.706 + *aIsReordered = nsBidiPresUtils::CheckLineOrder(line->mFirstChild, line->GetChildCount(), &leftmostFrame, &rightmostFrame); 1.707 + 1.708 + // map leftmost/rightmost to first/last according to paragraph direction 1.709 + *aFirstVisual = mRightToLeft ? rightmostFrame : leftmostFrame; 1.710 + *aLastVisual = mRightToLeft ? leftmostFrame : rightmostFrame; 1.711 + 1.712 + return NS_OK; 1.713 +} 1.714 + 1.715 +NS_IMETHODIMP 1.716 +nsLineIterator::FindFrameAt(int32_t aLineNumber, 1.717 + nscoord aX, 1.718 + nsIFrame** aFrameFound, 1.719 + bool* aXIsBeforeFirstFrame, 1.720 + bool* aXIsAfterLastFrame) 1.721 +{ 1.722 + NS_PRECONDITION(aFrameFound && aXIsBeforeFirstFrame && aXIsAfterLastFrame, 1.723 + "null OUT ptr"); 1.724 + if (!aFrameFound || !aXIsBeforeFirstFrame || !aXIsAfterLastFrame) { 1.725 + return NS_ERROR_NULL_POINTER; 1.726 + } 1.727 + if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) { 1.728 + return NS_ERROR_INVALID_ARG; 1.729 + } 1.730 + 1.731 + nsLineBox* line = mLines[aLineNumber]; 1.732 + if (!line) { 1.733 + *aFrameFound = nullptr; 1.734 + *aXIsBeforeFirstFrame = true; 1.735 + *aXIsAfterLastFrame = false; 1.736 + return NS_OK; 1.737 + } 1.738 + 1.739 + if (line->ISize() == 0 && line->BSize() == 0) 1.740 + return NS_ERROR_FAILURE; 1.741 + 1.742 + nsIFrame* frame = line->mFirstChild; 1.743 + nsIFrame* closestFromLeft = nullptr; 1.744 + nsIFrame* closestFromRight = nullptr; 1.745 + int32_t n = line->GetChildCount(); 1.746 + while (n--) { 1.747 + nsRect rect = frame->GetRect(); 1.748 + if (rect.width > 0) { 1.749 + // If aX is inside this frame - this is it 1.750 + if (rect.x <= aX && rect.XMost() > aX) { 1.751 + closestFromLeft = closestFromRight = frame; 1.752 + break; 1.753 + } 1.754 + if (rect.x < aX) { 1.755 + if (!closestFromLeft || 1.756 + rect.XMost() > closestFromLeft->GetRect().XMost()) 1.757 + closestFromLeft = frame; 1.758 + } 1.759 + else { 1.760 + if (!closestFromRight || 1.761 + rect.x < closestFromRight->GetRect().x) 1.762 + closestFromRight = frame; 1.763 + } 1.764 + } 1.765 + frame = frame->GetNextSibling(); 1.766 + } 1.767 + if (!closestFromLeft && !closestFromRight) { 1.768 + // All frames were zero-width. Just take the first one. 1.769 + closestFromLeft = closestFromRight = line->mFirstChild; 1.770 + } 1.771 + *aXIsBeforeFirstFrame = mRightToLeft ? !closestFromRight : !closestFromLeft; 1.772 + *aXIsAfterLastFrame = mRightToLeft ? !closestFromLeft : !closestFromRight; 1.773 + if (closestFromLeft == closestFromRight) { 1.774 + *aFrameFound = closestFromLeft; 1.775 + } 1.776 + else if (!closestFromLeft) { 1.777 + *aFrameFound = closestFromRight; 1.778 + } 1.779 + else if (!closestFromRight) { 1.780 + *aFrameFound = closestFromLeft; 1.781 + } 1.782 + else { // we're between two frames 1.783 + nscoord delta = closestFromRight->GetRect().x - closestFromLeft->GetRect().XMost(); 1.784 + if (aX < closestFromLeft->GetRect().XMost() + delta/2) 1.785 + *aFrameFound = closestFromLeft; 1.786 + else 1.787 + *aFrameFound = closestFromRight; 1.788 + } 1.789 + return NS_OK; 1.790 +} 1.791 + 1.792 +NS_IMETHODIMP 1.793 +nsLineIterator::GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber) 1.794 +{ 1.795 + aFrame = aFrame->GetNextSibling(); 1.796 + return NS_OK; 1.797 +} 1.798 + 1.799 +//---------------------------------------------------------------------- 1.800 + 1.801 +#ifdef NS_BUILD_REFCNT_LOGGING 1.802 +nsFloatCacheList::nsFloatCacheList() : 1.803 + mHead(nullptr) 1.804 +{ 1.805 + MOZ_COUNT_CTOR(nsFloatCacheList); 1.806 +} 1.807 +#endif 1.808 + 1.809 +nsFloatCacheList::~nsFloatCacheList() 1.810 +{ 1.811 + DeleteAll(); 1.812 + MOZ_COUNT_DTOR(nsFloatCacheList); 1.813 +} 1.814 + 1.815 +void 1.816 +nsFloatCacheList::DeleteAll() 1.817 +{ 1.818 + nsFloatCache* c = mHead; 1.819 + while (c) { 1.820 + nsFloatCache* next = c->Next(); 1.821 + delete c; 1.822 + c = next; 1.823 + } 1.824 + mHead = nullptr; 1.825 +} 1.826 + 1.827 +nsFloatCache* 1.828 +nsFloatCacheList::Tail() const 1.829 +{ 1.830 + nsFloatCache* fc = mHead; 1.831 + while (fc) { 1.832 + if (!fc->mNext) { 1.833 + break; 1.834 + } 1.835 + fc = fc->mNext; 1.836 + } 1.837 + return fc; 1.838 +} 1.839 + 1.840 +void 1.841 +nsFloatCacheList::Append(nsFloatCacheFreeList& aList) 1.842 +{ 1.843 + NS_PRECONDITION(aList.NotEmpty(), "Appending empty list will fail"); 1.844 + 1.845 + nsFloatCache* tail = Tail(); 1.846 + if (tail) { 1.847 + NS_ASSERTION(!tail->mNext, "Bogus!"); 1.848 + tail->mNext = aList.mHead; 1.849 + } 1.850 + else { 1.851 + NS_ASSERTION(!mHead, "Bogus!"); 1.852 + mHead = aList.mHead; 1.853 + } 1.854 + aList.mHead = nullptr; 1.855 + aList.mTail = nullptr; 1.856 +} 1.857 + 1.858 +nsFloatCache* 1.859 +nsFloatCacheList::Find(nsIFrame* aOutOfFlowFrame) 1.860 +{ 1.861 + nsFloatCache* fc = mHead; 1.862 + while (fc) { 1.863 + if (fc->mFloat == aOutOfFlowFrame) { 1.864 + break; 1.865 + } 1.866 + fc = fc->Next(); 1.867 + } 1.868 + return fc; 1.869 +} 1.870 + 1.871 +nsFloatCache* 1.872 +nsFloatCacheList::RemoveAndReturnPrev(nsFloatCache* aElement) 1.873 +{ 1.874 + nsFloatCache* fc = mHead; 1.875 + nsFloatCache* prev = nullptr; 1.876 + while (fc) { 1.877 + if (fc == aElement) { 1.878 + if (prev) { 1.879 + prev->mNext = fc->mNext; 1.880 + } else { 1.881 + mHead = fc->mNext; 1.882 + } 1.883 + return prev; 1.884 + } 1.885 + prev = fc; 1.886 + fc = fc->mNext; 1.887 + } 1.888 + return nullptr; 1.889 +} 1.890 + 1.891 +//---------------------------------------------------------------------- 1.892 + 1.893 +#ifdef NS_BUILD_REFCNT_LOGGING 1.894 +nsFloatCacheFreeList::nsFloatCacheFreeList() : 1.895 + mTail(nullptr) 1.896 +{ 1.897 + MOZ_COUNT_CTOR(nsFloatCacheFreeList); 1.898 +} 1.899 + 1.900 +nsFloatCacheFreeList::~nsFloatCacheFreeList() 1.901 +{ 1.902 + MOZ_COUNT_DTOR(nsFloatCacheFreeList); 1.903 +} 1.904 +#endif 1.905 + 1.906 +void 1.907 +nsFloatCacheFreeList::Append(nsFloatCacheList& aList) 1.908 +{ 1.909 + NS_PRECONDITION(aList.NotEmpty(), "Appending empty list will fail"); 1.910 + 1.911 + if (mTail) { 1.912 + NS_ASSERTION(!mTail->mNext, "Bogus"); 1.913 + mTail->mNext = aList.mHead; 1.914 + } 1.915 + else { 1.916 + NS_ASSERTION(!mHead, "Bogus"); 1.917 + mHead = aList.mHead; 1.918 + } 1.919 + mTail = aList.Tail(); 1.920 + aList.mHead = nullptr; 1.921 +} 1.922 + 1.923 +void 1.924 +nsFloatCacheFreeList::Remove(nsFloatCache* aElement) 1.925 +{ 1.926 + nsFloatCache* prev = nsFloatCacheList::RemoveAndReturnPrev(aElement); 1.927 + if (mTail == aElement) { 1.928 + mTail = prev; 1.929 + } 1.930 +} 1.931 + 1.932 +void 1.933 +nsFloatCacheFreeList::DeleteAll() 1.934 +{ 1.935 + nsFloatCacheList::DeleteAll(); 1.936 + mTail = nullptr; 1.937 +} 1.938 + 1.939 +nsFloatCache* 1.940 +nsFloatCacheFreeList::Alloc(nsIFrame* aFloat) 1.941 +{ 1.942 + NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW, 1.943 + "This is a float cache, why isn't the frame out-of-flow?"); 1.944 + nsFloatCache* fc = mHead; 1.945 + if (mHead) { 1.946 + if (mHead == mTail) { 1.947 + mHead = mTail = nullptr; 1.948 + } 1.949 + else { 1.950 + mHead = fc->mNext; 1.951 + } 1.952 + fc->mNext = nullptr; 1.953 + } 1.954 + else { 1.955 + fc = new nsFloatCache(); 1.956 + } 1.957 + fc->mFloat = aFloat; 1.958 + return fc; 1.959 +} 1.960 + 1.961 +void 1.962 +nsFloatCacheFreeList::Append(nsFloatCache* aFloat) 1.963 +{ 1.964 + NS_ASSERTION(!aFloat->mNext, "Bogus!"); 1.965 + aFloat->mNext = nullptr; 1.966 + if (mTail) { 1.967 + NS_ASSERTION(!mTail->mNext, "Bogus!"); 1.968 + mTail->mNext = aFloat; 1.969 + mTail = aFloat; 1.970 + } 1.971 + else { 1.972 + NS_ASSERTION(!mHead, "Bogus!"); 1.973 + mHead = mTail = aFloat; 1.974 + } 1.975 +} 1.976 + 1.977 +//---------------------------------------------------------------------- 1.978 + 1.979 +nsFloatCache::nsFloatCache() 1.980 + : mFloat(nullptr), 1.981 + mNext(nullptr) 1.982 +{ 1.983 + MOZ_COUNT_CTOR(nsFloatCache); 1.984 +} 1.985 + 1.986 +#ifdef NS_BUILD_REFCNT_LOGGING 1.987 +nsFloatCache::~nsFloatCache() 1.988 +{ 1.989 + MOZ_COUNT_DTOR(nsFloatCache); 1.990 +} 1.991 +#endif