/src/mozilla-central/layout/generic/nsLineBox.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | /* representation of one line within a block frame, a CSS line box */ |
8 | | |
9 | | #include "nsLineBox.h" |
10 | | |
11 | | #include "mozilla/ArenaObjectID.h" |
12 | | #include "mozilla/Assertions.h" |
13 | | #include "mozilla/Likely.h" |
14 | | #include "mozilla/Sprintf.h" |
15 | | #include "mozilla/WritingModes.h" |
16 | | #include "nsBidiPresUtils.h" |
17 | | #include "nsFrame.h" |
18 | | #include "nsIFrameInlines.h" |
19 | | #include "nsPresArena.h" |
20 | | #include "nsPrintfCString.h" |
21 | | #include "nsWindowSizes.h" |
22 | | |
23 | | #ifdef DEBUG |
24 | | static int32_t ctorCount; |
25 | | int32_t nsLineBox::GetCtorCount() { return ctorCount; } |
26 | | #endif |
27 | | |
28 | | #ifndef _MSC_VER |
29 | | // static nsLineBox constant; initialized in the header file. |
30 | | const uint32_t nsLineBox::kMinChildCountForHashtable; |
31 | | #endif |
32 | | |
33 | | using namespace mozilla; |
34 | | |
35 | | nsLineBox::nsLineBox(nsIFrame* aFrame, int32_t aCount, bool aIsBlock) |
36 | | : mFirstChild(aFrame) |
37 | | , mWritingMode() |
38 | | , mContainerSize(-1, -1) |
39 | | , mBounds(WritingMode()) // mBounds will be initialized with the correct |
40 | | // writing mode when it is set |
41 | | , mFrames() |
42 | | , mAscent() |
43 | | , mAllFlags(0) |
44 | | , mData(nullptr) |
45 | 0 | { |
46 | 0 | // Assert that the union elements chosen for initialisation are at |
47 | 0 | // least as large as all other elements in their respective unions, so |
48 | 0 | // as to ensure that no parts are missed. |
49 | 0 | static_assert(sizeof(mFrames) >= sizeof(mChildCount), "nsLineBox init #1"); |
50 | 0 | static_assert(sizeof(mAllFlags) >= sizeof(mFlags), "nsLineBox init #2"); |
51 | 0 | static_assert(sizeof(mData) >= sizeof(mBlockData), "nsLineBox init #3"); |
52 | 0 | static_assert(sizeof(mData) >= sizeof(mInlineData), "nsLineBox init #4"); |
53 | 0 |
|
54 | 0 | MOZ_COUNT_CTOR(nsLineBox); |
55 | | #ifdef DEBUG |
56 | | ++ctorCount; |
57 | | NS_ASSERTION(!aIsBlock || aCount == 1, "Blocks must have exactly one child"); |
58 | | nsIFrame* f = aFrame; |
59 | | for (int32_t n = aCount; n > 0; f = f->GetNextSibling(), --n) { |
60 | | NS_ASSERTION(aIsBlock == f->IsBlockOutside(), |
61 | | "wrong kind of child frame"); |
62 | | } |
63 | | #endif |
64 | | static_assert(static_cast<int>(StyleClear::Max) <= 15, |
65 | 0 | "FlagBits needs more bits to store the full range of " |
66 | 0 | "break type ('clear') values"); |
67 | 0 | mChildCount = aCount; |
68 | 0 | MarkDirty(); |
69 | 0 | mFlags.mBlock = aIsBlock; |
70 | 0 | } |
71 | | |
72 | | nsLineBox::~nsLineBox() |
73 | 0 | { |
74 | 0 | MOZ_COUNT_DTOR(nsLineBox); |
75 | 0 | if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) { |
76 | 0 | delete mFrames; |
77 | 0 | } |
78 | 0 | Cleanup(); |
79 | 0 | } |
80 | | |
81 | | nsLineBox* |
82 | | NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame, bool aIsBlock) |
83 | 0 | { |
84 | 0 | return new (aPresShell) nsLineBox(aFrame, 1, aIsBlock); |
85 | 0 | } |
86 | | |
87 | | nsLineBox* |
88 | | NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine, |
89 | | nsIFrame* aFrame, int32_t aCount) |
90 | 0 | { |
91 | 0 | nsLineBox* newLine = new (aPresShell) nsLineBox(aFrame, aCount, false); |
92 | 0 | newLine->NoteFramesMovedFrom(aFromLine); |
93 | 0 | newLine->mContainerSize = aFromLine->mContainerSize; |
94 | 0 | return newLine; |
95 | 0 | } |
96 | | |
97 | | void |
98 | | nsLineBox::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const |
99 | 0 | { |
100 | 0 | if (mFlags.mHasHashedFrames) { |
101 | 0 | aSizes.mLayoutFramePropertiesSize += |
102 | 0 | mFrames->ShallowSizeOfIncludingThis(aSizes.mState.mMallocSizeOf); |
103 | 0 | } |
104 | 0 | } |
105 | | |
106 | | void |
107 | | nsLineBox::StealHashTableFrom(nsLineBox* aFromLine, uint32_t aFromLineNewCount) |
108 | 0 | { |
109 | 0 | MOZ_ASSERT(!mFlags.mHasHashedFrames); |
110 | 0 | MOZ_ASSERT(GetChildCount() >= int32_t(aFromLineNewCount)); |
111 | 0 | mFrames = aFromLine->mFrames; |
112 | 0 | mFlags.mHasHashedFrames = 1; |
113 | 0 | aFromLine->mFlags.mHasHashedFrames = 0; |
114 | 0 | aFromLine->mChildCount = aFromLineNewCount; |
115 | 0 | // remove aFromLine's frames that aren't on this line |
116 | 0 | nsIFrame* f = aFromLine->mFirstChild; |
117 | 0 | for (uint32_t i = 0; i < aFromLineNewCount; f = f->GetNextSibling(), ++i) { |
118 | 0 | mFrames->RemoveEntry(f); |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | | void |
123 | | nsLineBox::NoteFramesMovedFrom(nsLineBox* aFromLine) |
124 | 0 | { |
125 | 0 | uint32_t fromCount = aFromLine->GetChildCount(); |
126 | 0 | uint32_t toCount = GetChildCount(); |
127 | 0 | MOZ_ASSERT(toCount <= fromCount, "moved more frames than aFromLine has"); |
128 | 0 | uint32_t fromNewCount = fromCount - toCount; |
129 | 0 | if (MOZ_LIKELY(!aFromLine->mFlags.mHasHashedFrames)) { |
130 | 0 | aFromLine->mChildCount = fromNewCount; |
131 | 0 | MOZ_ASSERT(toCount < kMinChildCountForHashtable); |
132 | 0 | } else if (fromNewCount < kMinChildCountForHashtable) { |
133 | 0 | // aFromLine has a hash table but will not have it after moving the frames |
134 | 0 | // so this line can steal the hash table if it needs it. |
135 | 0 | if (toCount >= kMinChildCountForHashtable) { |
136 | 0 | StealHashTableFrom(aFromLine, fromNewCount); |
137 | 0 | } else { |
138 | 0 | delete aFromLine->mFrames; |
139 | 0 | aFromLine->mFlags.mHasHashedFrames = 0; |
140 | 0 | aFromLine->mChildCount = fromNewCount; |
141 | 0 | } |
142 | 0 | } else { |
143 | 0 | // aFromLine still needs a hash table. |
144 | 0 | if (toCount < kMinChildCountForHashtable) { |
145 | 0 | // remove the moved frames from it |
146 | 0 | nsIFrame* f = mFirstChild; |
147 | 0 | for (uint32_t i = 0; i < toCount; f = f->GetNextSibling(), ++i) { |
148 | 0 | aFromLine->mFrames->RemoveEntry(f); |
149 | 0 | } |
150 | 0 | } else if (toCount <= fromNewCount) { |
151 | 0 | // This line needs a hash table, allocate a hash table for it since that |
152 | 0 | // means fewer hash ops. |
153 | 0 | nsIFrame* f = mFirstChild; |
154 | 0 | for (uint32_t i = 0; i < toCount; f = f->GetNextSibling(), ++i) { |
155 | 0 | aFromLine->mFrames->RemoveEntry(f); // toCount RemoveEntry |
156 | 0 | } |
157 | 0 | SwitchToHashtable(); // toCount PutEntry |
158 | 0 | } else { |
159 | 0 | // This line needs a hash table, but it's fewer hash ops to steal |
160 | 0 | // aFromLine's hash table and allocate a new hash table for that line. |
161 | 0 | StealHashTableFrom(aFromLine, fromNewCount); // fromNewCount RemoveEntry |
162 | 0 | aFromLine->SwitchToHashtable(); // fromNewCount PutEntry |
163 | 0 | } |
164 | 0 | } |
165 | 0 | } |
166 | | |
167 | | void* |
168 | | nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell) |
169 | 0 | { |
170 | 0 | return aPresShell->AllocateByObjectID(eArenaObjectID_nsLineBox, sz); |
171 | 0 | } |
172 | | |
173 | | void |
174 | | nsLineBox::Destroy(nsIPresShell* aPresShell) |
175 | 0 | { |
176 | 0 | this->nsLineBox::~nsLineBox(); |
177 | 0 | aPresShell->FreeByObjectID(eArenaObjectID_nsLineBox, this); |
178 | 0 | } |
179 | | |
180 | | void |
181 | | nsLineBox::Cleanup() |
182 | 0 | { |
183 | 0 | if (mData) { |
184 | 0 | if (IsBlock()) { |
185 | 0 | delete mBlockData; |
186 | 0 | } |
187 | 0 | else { |
188 | 0 | delete mInlineData; |
189 | 0 | } |
190 | 0 | mData = nullptr; |
191 | 0 | } |
192 | 0 | } |
193 | | |
194 | | #ifdef DEBUG_FRAME_DUMP |
195 | | static void |
196 | | ListFloats(FILE* out, const char* aPrefix, const nsFloatCacheList& aFloats) |
197 | | { |
198 | | nsFloatCache* fc = aFloats.Head(); |
199 | | while (fc) { |
200 | | nsCString str(aPrefix); |
201 | | nsIFrame* frame = fc->mFloat; |
202 | | str += nsPrintfCString("floatframe@%p ", static_cast<void*>(frame)); |
203 | | if (frame) { |
204 | | nsAutoString frameName; |
205 | | frame->GetFrameName(frameName); |
206 | | str += NS_ConvertUTF16toUTF8(frameName).get(); |
207 | | } |
208 | | else { |
209 | | str += "\n###!!! NULL out-of-flow frame"; |
210 | | } |
211 | | fprintf_stderr(out, "%s\n", str.get()); |
212 | | fc = fc->Next(); |
213 | | } |
214 | | } |
215 | | |
216 | | /* static */ const char* |
217 | | nsLineBox::BreakTypeToString(StyleClear aBreakType) |
218 | | { |
219 | | switch (aBreakType) { |
220 | | case StyleClear::None: return "nobr"; |
221 | | case StyleClear::Left: return "leftbr"; |
222 | | case StyleClear::Right: return "rightbr"; |
223 | | case StyleClear::Both: return "leftbr+rightbr"; |
224 | | case StyleClear::Line: return "linebr"; |
225 | | case StyleClear::Max: return "leftbr+rightbr+linebr"; |
226 | | } |
227 | | return "unknown"; |
228 | | } |
229 | | |
230 | | char* |
231 | | nsLineBox::StateToString(char* aBuf, int32_t aBufSize) const |
232 | | { |
233 | | snprintf(aBuf, aBufSize, "%s,%s,%s,%s,%s,before:%s,after:%s[0x%x]", |
234 | | IsBlock() ? "block" : "inline", |
235 | | IsDirty() ? "dirty" : "clean", |
236 | | IsPreviousMarginDirty() ? "prevmargindirty" : "prevmarginclean", |
237 | | IsImpactedByFloat() ? "impacted" : "not impacted", |
238 | | IsLineWrapped() ? "wrapped" : "not wrapped", |
239 | | BreakTypeToString(GetBreakTypeBefore()), |
240 | | BreakTypeToString(GetBreakTypeAfter()), |
241 | | mAllFlags); |
242 | | return aBuf; |
243 | | } |
244 | | |
245 | | void |
246 | | nsLineBox::List(FILE* out, int32_t aIndent, uint32_t aFlags) const |
247 | | { |
248 | | nsCString str; |
249 | | while (aIndent-- > 0) { |
250 | | str += " "; |
251 | | } |
252 | | List(out, str.get(), aFlags); |
253 | | } |
254 | | |
255 | | void |
256 | | nsLineBox::List(FILE* out, const char* aPrefix, uint32_t aFlags) const |
257 | | { |
258 | | nsCString str(aPrefix); |
259 | | char cbuf[100]; |
260 | | str += nsPrintfCString("line %p: count=%d state=%s ", |
261 | | static_cast<const void*>(this), GetChildCount(), |
262 | | StateToString(cbuf, sizeof(cbuf))); |
263 | | if (IsBlock() && !GetCarriedOutBEndMargin().IsZero()) { |
264 | | str += nsPrintfCString("bm=%d ", GetCarriedOutBEndMargin().get()); |
265 | | } |
266 | | nsRect bounds = GetPhysicalBounds(); |
267 | | str += nsPrintfCString("{%d,%d,%d,%d} ", |
268 | | bounds.x, bounds.y, bounds.width, bounds.height); |
269 | | if (mWritingMode.IsVertical() || !mWritingMode.IsBidiLTR()) { |
270 | | str += nsPrintfCString("{%s: %d,%d,%d,%d; cs=%d,%d} ", |
271 | | mWritingMode.DebugString(), |
272 | | IStart(), BStart(), ISize(), BSize(), |
273 | | mContainerSize.width, mContainerSize.height); |
274 | | } |
275 | | if (mData && |
276 | | (!mData->mOverflowAreas.VisualOverflow().IsEqualEdges(bounds) || |
277 | | !mData->mOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds))) { |
278 | | str += nsPrintfCString("vis-overflow=%d,%d,%d,%d scr-overflow=%d,%d,%d,%d ", |
279 | | mData->mOverflowAreas.VisualOverflow().x, |
280 | | mData->mOverflowAreas.VisualOverflow().y, |
281 | | mData->mOverflowAreas.VisualOverflow().width, |
282 | | mData->mOverflowAreas.VisualOverflow().height, |
283 | | mData->mOverflowAreas.ScrollableOverflow().x, |
284 | | mData->mOverflowAreas.ScrollableOverflow().y, |
285 | | mData->mOverflowAreas.ScrollableOverflow().width, |
286 | | mData->mOverflowAreas.ScrollableOverflow().height); |
287 | | } |
288 | | fprintf_stderr(out, "%s<\n", str.get()); |
289 | | |
290 | | nsIFrame* frame = mFirstChild; |
291 | | int32_t n = GetChildCount(); |
292 | | nsCString pfx(aPrefix); |
293 | | pfx += " "; |
294 | | while (--n >= 0) { |
295 | | frame->List(out, pfx.get(), aFlags); |
296 | | frame = frame->GetNextSibling(); |
297 | | } |
298 | | |
299 | | if (HasFloats()) { |
300 | | fprintf_stderr(out, "%s> floats <\n", aPrefix); |
301 | | ListFloats(out, pfx.get(), mInlineData->mFloats); |
302 | | } |
303 | | fprintf_stderr(out, "%s>\n", aPrefix); |
304 | | } |
305 | | |
306 | | nsIFrame* |
307 | | nsLineBox::LastChild() const |
308 | | { |
309 | | nsIFrame* frame = mFirstChild; |
310 | | int32_t n = GetChildCount() - 1; |
311 | | while (--n >= 0) { |
312 | | frame = frame->GetNextSibling(); |
313 | | } |
314 | | return frame; |
315 | | } |
316 | | #endif |
317 | | |
318 | | int32_t |
319 | | nsLineBox::IndexOf(nsIFrame* aFrame) const |
320 | 0 | { |
321 | 0 | int32_t i, n = GetChildCount(); |
322 | 0 | nsIFrame* frame = mFirstChild; |
323 | 0 | for (i = 0; i < n; i++) { |
324 | 0 | if (frame == aFrame) { |
325 | 0 | return i; |
326 | 0 | } |
327 | 0 | frame = frame->GetNextSibling(); |
328 | 0 | } |
329 | 0 | return -1; |
330 | 0 | } |
331 | | |
332 | | bool |
333 | | nsLineBox::IsEmpty() const |
334 | 0 | { |
335 | 0 | if (IsBlock()) |
336 | 0 | return mFirstChild->IsEmpty(); |
337 | 0 | |
338 | 0 | int32_t n; |
339 | 0 | nsIFrame *kid; |
340 | 0 | for (n = GetChildCount(), kid = mFirstChild; |
341 | 0 | n > 0; |
342 | 0 | --n, kid = kid->GetNextSibling()) |
343 | 0 | { |
344 | 0 | if (!kid->IsEmpty()) |
345 | 0 | return false; |
346 | 0 | } |
347 | 0 | if (HasBullet()) { |
348 | 0 | return false; |
349 | 0 | } |
350 | 0 | return true; |
351 | 0 | } |
352 | | |
353 | | bool |
354 | | nsLineBox::CachedIsEmpty() |
355 | 0 | { |
356 | 0 | if (mFlags.mDirty) { |
357 | 0 | return IsEmpty(); |
358 | 0 | } |
359 | 0 | |
360 | 0 | if (mFlags.mEmptyCacheValid) { |
361 | 0 | return mFlags.mEmptyCacheState; |
362 | 0 | } |
363 | 0 | |
364 | 0 | bool result; |
365 | 0 | if (IsBlock()) { |
366 | 0 | result = mFirstChild->CachedIsEmpty(); |
367 | 0 | } else { |
368 | 0 | int32_t n; |
369 | 0 | nsIFrame *kid; |
370 | 0 | result = true; |
371 | 0 | for (n = GetChildCount(), kid = mFirstChild; |
372 | 0 | n > 0; |
373 | 0 | --n, kid = kid->GetNextSibling()) |
374 | 0 | { |
375 | 0 | if (!kid->CachedIsEmpty()) { |
376 | 0 | result = false; |
377 | 0 | break; |
378 | 0 | } |
379 | 0 | } |
380 | 0 | if (HasBullet()) { |
381 | 0 | result = false; |
382 | 0 | } |
383 | 0 | } |
384 | 0 |
|
385 | 0 | mFlags.mEmptyCacheValid = true; |
386 | 0 | mFlags.mEmptyCacheState = result; |
387 | 0 | return result; |
388 | 0 | } |
389 | | |
390 | | void |
391 | | nsLineBox::DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines, |
392 | | nsIFrame* aDestructRoot, nsFrameList* aFrames, |
393 | | PostDestroyData& aPostDestroyData) |
394 | 0 | { |
395 | 0 | nsIPresShell* shell = aPresContext->PresShell(); |
396 | 0 |
|
397 | 0 | // Keep our line list and frame list up to date as we |
398 | 0 | // remove frames, in case something wants to traverse the |
399 | 0 | // frame tree while we're destroying. |
400 | 0 | while (!aLines.empty()) { |
401 | 0 | nsLineBox* line = aLines.front(); |
402 | 0 | if (MOZ_UNLIKELY(line->mFlags.mHasHashedFrames)) { |
403 | 0 | line->SwitchToCounter(); // Avoid expensive has table removals. |
404 | 0 | } |
405 | 0 | while (line->GetChildCount() > 0) { |
406 | 0 | nsIFrame* child = aFrames->RemoveFirstChild(); |
407 | 0 | MOZ_DIAGNOSTIC_ASSERT(child->PresContext() == aPresContext); |
408 | 0 | MOZ_DIAGNOSTIC_ASSERT(child == line->mFirstChild, "Lines out of sync"); |
409 | 0 | line->mFirstChild = aFrames->FirstChild(); |
410 | 0 | line->NoteFrameRemoved(child); |
411 | 0 | child->DestroyFrom(aDestructRoot, aPostDestroyData); |
412 | 0 | } |
413 | 0 | MOZ_DIAGNOSTIC_ASSERT(line == aLines.front(), |
414 | 0 | "destroying child frames messed up our lines!"); |
415 | 0 | aLines.pop_front(); |
416 | 0 | line->Destroy(shell); |
417 | 0 | } |
418 | 0 | } |
419 | | |
420 | | bool |
421 | | nsLineBox::RFindLineContaining(nsIFrame* aFrame, |
422 | | const nsLineList::iterator& aBegin, |
423 | | nsLineList::iterator& aEnd, |
424 | | nsIFrame* aLastFrameBeforeEnd, |
425 | | int32_t* aFrameIndexInLine) |
426 | 0 | { |
427 | 0 | MOZ_ASSERT(aFrame, "null ptr"); |
428 | 0 |
|
429 | 0 | nsIFrame* curFrame = aLastFrameBeforeEnd; |
430 | 0 | while (aBegin != aEnd) { |
431 | 0 | --aEnd; |
432 | 0 | NS_ASSERTION(aEnd->LastChild() == curFrame, "Unexpected curFrame"); |
433 | 0 | if (MOZ_UNLIKELY(aEnd->mFlags.mHasHashedFrames) && |
434 | 0 | !aEnd->Contains(aFrame)) { |
435 | 0 | if (aEnd->mFirstChild) { |
436 | 0 | curFrame = aEnd->mFirstChild->GetPrevSibling(); |
437 | 0 | } |
438 | 0 | continue; |
439 | 0 | } |
440 | 0 | // i is the index of curFrame in aEnd |
441 | 0 | int32_t i = aEnd->GetChildCount() - 1; |
442 | 0 | while (i >= 0) { |
443 | 0 | if (curFrame == aFrame) { |
444 | 0 | *aFrameIndexInLine = i; |
445 | 0 | return true; |
446 | 0 | } |
447 | 0 | --i; |
448 | 0 | curFrame = curFrame->GetPrevSibling(); |
449 | 0 | } |
450 | 0 | MOZ_ASSERT(!aEnd->mFlags.mHasHashedFrames, "Contains lied to us!"); |
451 | 0 | } |
452 | 0 | *aFrameIndexInLine = -1; |
453 | 0 | return false; |
454 | 0 | } |
455 | | |
456 | | nsCollapsingMargin |
457 | | nsLineBox::GetCarriedOutBEndMargin() const |
458 | 0 | { |
459 | 0 | NS_ASSERTION(IsBlock(), |
460 | 0 | "GetCarriedOutBEndMargin called on non-block line."); |
461 | 0 | return (IsBlock() && mBlockData) |
462 | 0 | ? mBlockData->mCarriedOutBEndMargin |
463 | 0 | : nsCollapsingMargin(); |
464 | 0 | } |
465 | | |
466 | | bool |
467 | | nsLineBox::SetCarriedOutBEndMargin(nsCollapsingMargin aValue) |
468 | 0 | { |
469 | 0 | bool changed = false; |
470 | 0 | if (IsBlock()) { |
471 | 0 | if (!aValue.IsZero()) { |
472 | 0 | if (!mBlockData) { |
473 | 0 | mBlockData = new ExtraBlockData(GetPhysicalBounds()); |
474 | 0 | } |
475 | 0 | changed = aValue != mBlockData->mCarriedOutBEndMargin; |
476 | 0 | mBlockData->mCarriedOutBEndMargin = aValue; |
477 | 0 | } |
478 | 0 | else if (mBlockData) { |
479 | 0 | changed = aValue != mBlockData->mCarriedOutBEndMargin; |
480 | 0 | mBlockData->mCarriedOutBEndMargin = aValue; |
481 | 0 | MaybeFreeData(); |
482 | 0 | } |
483 | 0 | } |
484 | 0 | return changed; |
485 | 0 | } |
486 | | |
487 | | void |
488 | | nsLineBox::MaybeFreeData() |
489 | 0 | { |
490 | 0 | nsRect bounds = GetPhysicalBounds(); |
491 | 0 | if (mData && mData->mOverflowAreas == nsOverflowAreas(bounds, bounds)) { |
492 | 0 | if (IsInline()) { |
493 | 0 | if (mInlineData->mFloats.IsEmpty()) { |
494 | 0 | delete mInlineData; |
495 | 0 | mInlineData = nullptr; |
496 | 0 | } |
497 | 0 | } |
498 | 0 | else if (mBlockData->mCarriedOutBEndMargin.IsZero()) { |
499 | 0 | delete mBlockData; |
500 | 0 | mBlockData = nullptr; |
501 | 0 | } |
502 | 0 | } |
503 | 0 | } |
504 | | |
505 | | // XXX get rid of this??? |
506 | | nsFloatCache* |
507 | | nsLineBox::GetFirstFloat() |
508 | 0 | { |
509 | 0 | MOZ_ASSERT(IsInline(), "block line can't have floats"); |
510 | 0 | return mInlineData ? mInlineData->mFloats.Head() : nullptr; |
511 | 0 | } |
512 | | |
513 | | // XXX this might be too eager to free memory |
514 | | void |
515 | | nsLineBox::FreeFloats(nsFloatCacheFreeList& aFreeList) |
516 | 0 | { |
517 | 0 | MOZ_ASSERT(IsInline(), "block line can't have floats"); |
518 | 0 | if (IsInline() && mInlineData) { |
519 | 0 | if (mInlineData->mFloats.NotEmpty()) { |
520 | 0 | aFreeList.Append(mInlineData->mFloats); |
521 | 0 | } |
522 | 0 | MaybeFreeData(); |
523 | 0 | } |
524 | 0 | } |
525 | | |
526 | | void |
527 | | nsLineBox::AppendFloats(nsFloatCacheFreeList& aFreeList) |
528 | 0 | { |
529 | 0 | MOZ_ASSERT(IsInline(), "block line can't have floats"); |
530 | 0 | if (IsInline()) { |
531 | 0 | if (aFreeList.NotEmpty()) { |
532 | 0 | if (!mInlineData) { |
533 | 0 | mInlineData = new ExtraInlineData(GetPhysicalBounds()); |
534 | 0 | } |
535 | 0 | mInlineData->mFloats.Append(aFreeList); |
536 | 0 | } |
537 | 0 | } |
538 | 0 | } |
539 | | |
540 | | bool |
541 | | nsLineBox::RemoveFloat(nsIFrame* aFrame) |
542 | 0 | { |
543 | 0 | MOZ_ASSERT(IsInline(), "block line can't have floats"); |
544 | 0 | if (IsInline() && mInlineData) { |
545 | 0 | nsFloatCache* fc = mInlineData->mFloats.Find(aFrame); |
546 | 0 | if (fc) { |
547 | 0 | // Note: the placeholder is part of the line's child list |
548 | 0 | // and will be removed later. |
549 | 0 | mInlineData->mFloats.Remove(fc); |
550 | 0 | delete fc; |
551 | 0 | MaybeFreeData(); |
552 | 0 | return true; |
553 | 0 | } |
554 | 0 | } |
555 | 0 | return false; |
556 | 0 | } |
557 | | |
558 | | void |
559 | | nsLineBox::SetFloatEdges(nscoord aStart, nscoord aEnd) |
560 | 0 | { |
561 | 0 | MOZ_ASSERT(IsInline(), "block line can't have float edges"); |
562 | 0 | if (!mInlineData) { |
563 | 0 | mInlineData = new ExtraInlineData(GetPhysicalBounds()); |
564 | 0 | } |
565 | 0 | mInlineData->mFloatEdgeIStart = aStart; |
566 | 0 | mInlineData->mFloatEdgeIEnd = aEnd; |
567 | 0 | } |
568 | | |
569 | | void |
570 | | nsLineBox::ClearFloatEdges() |
571 | 0 | { |
572 | 0 | MOZ_ASSERT(IsInline(), "block line can't have float edges"); |
573 | 0 | if (mInlineData) { |
574 | 0 | mInlineData->mFloatEdgeIStart = nscoord_MIN; |
575 | 0 | mInlineData->mFloatEdgeIEnd = nscoord_MIN; |
576 | 0 | } |
577 | 0 | } |
578 | | |
579 | | void |
580 | | nsLineBox::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas) |
581 | 0 | { |
582 | 0 | NS_FOR_FRAME_OVERFLOW_TYPES(otype) { |
583 | 0 | NS_ASSERTION(aOverflowAreas.Overflow(otype).width >= 0, |
584 | 0 | "illegal width for combined area"); |
585 | 0 | NS_ASSERTION(aOverflowAreas.Overflow(otype).height >= 0, |
586 | 0 | "illegal height for combined area"); |
587 | 0 | } |
588 | 0 | nsRect bounds = GetPhysicalBounds(); |
589 | 0 | if (!aOverflowAreas.VisualOverflow().IsEqualInterior(bounds) || |
590 | 0 | !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) { |
591 | 0 | if (!mData) { |
592 | 0 | if (IsInline()) { |
593 | 0 | mInlineData = new ExtraInlineData(bounds); |
594 | 0 | } |
595 | 0 | else { |
596 | 0 | mBlockData = new ExtraBlockData(bounds); |
597 | 0 | } |
598 | 0 | } |
599 | 0 | mData->mOverflowAreas = aOverflowAreas; |
600 | 0 | } |
601 | 0 | else if (mData) { |
602 | 0 | // Store away new value so that MaybeFreeData compares against |
603 | 0 | // the right value. |
604 | 0 | mData->mOverflowAreas = aOverflowAreas; |
605 | 0 | MaybeFreeData(); |
606 | 0 | } |
607 | 0 | } |
608 | | |
609 | | //---------------------------------------------------------------------- |
610 | | |
611 | | |
612 | | static nsLineBox* gDummyLines[1]; |
613 | | |
614 | | nsLineIterator::nsLineIterator() |
615 | 0 | { |
616 | 0 | mLines = gDummyLines; |
617 | 0 | mNumLines = 0; |
618 | 0 | mIndex = 0; |
619 | 0 | mRightToLeft = false; |
620 | 0 | } |
621 | | |
622 | | nsLineIterator::~nsLineIterator() |
623 | 0 | { |
624 | 0 | if (mLines != gDummyLines) { |
625 | 0 | delete [] mLines; |
626 | 0 | } |
627 | 0 | } |
628 | | |
629 | | /* virtual */ void |
630 | | nsLineIterator::DisposeLineIterator() |
631 | 0 | { |
632 | 0 | delete this; |
633 | 0 | } |
634 | | |
635 | | nsresult |
636 | | nsLineIterator::Init(nsLineList& aLines, bool aRightToLeft) |
637 | 0 | { |
638 | 0 | mRightToLeft = aRightToLeft; |
639 | 0 |
|
640 | 0 | // Count the lines |
641 | 0 | int32_t numLines = aLines.size(); |
642 | 0 | if (0 == numLines) { |
643 | 0 | // Use gDummyLines so that we don't need null pointer checks in |
644 | 0 | // the accessor methods |
645 | 0 | mLines = gDummyLines; |
646 | 0 | return NS_OK; |
647 | 0 | } |
648 | 0 | |
649 | 0 | // Make a linear array of the lines |
650 | 0 | mLines = new nsLineBox*[numLines]; |
651 | 0 | if (!mLines) { |
652 | 0 | // Use gDummyLines so that we don't need null pointer checks in |
653 | 0 | // the accessor methods |
654 | 0 | mLines = gDummyLines; |
655 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
656 | 0 | } |
657 | 0 | nsLineBox** lp = mLines; |
658 | 0 | for (nsLineList::iterator line = aLines.begin(), line_end = aLines.end() ; |
659 | 0 | line != line_end; |
660 | 0 | ++line) |
661 | 0 | { |
662 | 0 | *lp++ = line; |
663 | 0 | } |
664 | 0 | mNumLines = numLines; |
665 | 0 | return NS_OK; |
666 | 0 | } |
667 | | |
668 | | int32_t |
669 | | nsLineIterator::GetNumLines() |
670 | 0 | { |
671 | 0 | return mNumLines; |
672 | 0 | } |
673 | | |
674 | | bool |
675 | | nsLineIterator::GetDirection() |
676 | 0 | { |
677 | 0 | return mRightToLeft; |
678 | 0 | } |
679 | | |
680 | | NS_IMETHODIMP |
681 | | nsLineIterator::GetLine(int32_t aLineNumber, |
682 | | nsIFrame** aFirstFrameOnLine, |
683 | | int32_t* aNumFramesOnLine, |
684 | | nsRect& aLineBounds) |
685 | 0 | { |
686 | 0 | NS_ENSURE_ARG_POINTER(aFirstFrameOnLine); |
687 | 0 | NS_ENSURE_ARG_POINTER(aNumFramesOnLine); |
688 | 0 |
|
689 | 0 | if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) { |
690 | 0 | *aFirstFrameOnLine = nullptr; |
691 | 0 | *aNumFramesOnLine = 0; |
692 | 0 | aLineBounds.SetRect(0, 0, 0, 0); |
693 | 0 | return NS_OK; |
694 | 0 | } |
695 | 0 | nsLineBox* line = mLines[aLineNumber]; |
696 | 0 | *aFirstFrameOnLine = line->mFirstChild; |
697 | 0 | *aNumFramesOnLine = line->GetChildCount(); |
698 | 0 | aLineBounds = line->GetPhysicalBounds(); |
699 | 0 |
|
700 | 0 | return NS_OK; |
701 | 0 | } |
702 | | |
703 | | int32_t |
704 | | nsLineIterator::FindLineContaining(nsIFrame* aFrame, int32_t aStartLine) |
705 | 0 | { |
706 | 0 | MOZ_ASSERT(aStartLine <= mNumLines, "Bogus line numbers"); |
707 | 0 | int32_t lineNumber = aStartLine; |
708 | 0 | while (lineNumber != mNumLines) { |
709 | 0 | nsLineBox* line = mLines[lineNumber]; |
710 | 0 | if (line->Contains(aFrame)) { |
711 | 0 | return lineNumber; |
712 | 0 | } |
713 | 0 | ++lineNumber; |
714 | 0 | } |
715 | 0 | return -1; |
716 | 0 | } |
717 | | |
718 | | NS_IMETHODIMP |
719 | | nsLineIterator::CheckLineOrder(int32_t aLine, |
720 | | bool *aIsReordered, |
721 | | nsIFrame **aFirstVisual, |
722 | | nsIFrame **aLastVisual) |
723 | 0 | { |
724 | 0 | NS_ASSERTION (aLine >= 0 && aLine < mNumLines, "aLine out of range!"); |
725 | 0 | nsLineBox* line = mLines[aLine]; |
726 | 0 |
|
727 | 0 | if (!line->mFirstChild) { // empty line |
728 | 0 | *aIsReordered = false; |
729 | 0 | *aFirstVisual = nullptr; |
730 | 0 | *aLastVisual = nullptr; |
731 | 0 | return NS_OK; |
732 | 0 | } |
733 | 0 | |
734 | 0 | nsIFrame* leftmostFrame; |
735 | 0 | nsIFrame* rightmostFrame; |
736 | 0 | *aIsReordered = nsBidiPresUtils::CheckLineOrder(line->mFirstChild, line->GetChildCount(), &leftmostFrame, &rightmostFrame); |
737 | 0 |
|
738 | 0 | // map leftmost/rightmost to first/last according to paragraph direction |
739 | 0 | *aFirstVisual = mRightToLeft ? rightmostFrame : leftmostFrame; |
740 | 0 | *aLastVisual = mRightToLeft ? leftmostFrame : rightmostFrame; |
741 | 0 |
|
742 | 0 | return NS_OK; |
743 | 0 | } |
744 | | |
745 | | NS_IMETHODIMP |
746 | | nsLineIterator::FindFrameAt(int32_t aLineNumber, |
747 | | nsPoint aPos, |
748 | | nsIFrame** aFrameFound, |
749 | | bool* aPosIsBeforeFirstFrame, |
750 | | bool* aPosIsAfterLastFrame) |
751 | 0 | { |
752 | 0 | MOZ_ASSERT(aFrameFound && aPosIsBeforeFirstFrame && aPosIsAfterLastFrame, |
753 | 0 | "null OUT ptr"); |
754 | 0 |
|
755 | 0 | if (!aFrameFound || !aPosIsBeforeFirstFrame || !aPosIsAfterLastFrame) { |
756 | 0 | return NS_ERROR_NULL_POINTER; |
757 | 0 | } |
758 | 0 | if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) { |
759 | 0 | return NS_ERROR_INVALID_ARG; |
760 | 0 | } |
761 | 0 | |
762 | 0 | nsLineBox* line = mLines[aLineNumber]; |
763 | 0 | if (!line) { |
764 | 0 | *aFrameFound = nullptr; |
765 | 0 | *aPosIsBeforeFirstFrame = true; |
766 | 0 | *aPosIsAfterLastFrame = false; |
767 | 0 | return NS_OK; |
768 | 0 | } |
769 | 0 | |
770 | 0 | if (line->ISize() == 0 && line->BSize() == 0) |
771 | 0 | return NS_ERROR_FAILURE; |
772 | 0 | |
773 | 0 | nsIFrame* frame = line->mFirstChild; |
774 | 0 | nsIFrame* closestFromStart = nullptr; |
775 | 0 | nsIFrame* closestFromEnd = nullptr; |
776 | 0 |
|
777 | 0 | WritingMode wm = line->mWritingMode; |
778 | 0 | nsSize containerSize = line->mContainerSize; |
779 | 0 |
|
780 | 0 | LogicalPoint pos(wm, aPos, containerSize); |
781 | 0 |
|
782 | 0 | int32_t n = line->GetChildCount(); |
783 | 0 | while (n--) { |
784 | 0 | LogicalRect rect = frame->GetLogicalRect(wm, containerSize); |
785 | 0 | if (rect.ISize(wm) > 0) { |
786 | 0 | // If pos.I() is inside this frame - this is it |
787 | 0 | if (rect.IStart(wm) <= pos.I(wm) && rect.IEnd(wm) > pos.I(wm)) { |
788 | 0 | closestFromStart = closestFromEnd = frame; |
789 | 0 | break; |
790 | 0 | } |
791 | 0 | if (rect.IStart(wm) < pos.I(wm)) { |
792 | 0 | if (!closestFromStart || |
793 | 0 | rect.IEnd(wm) > closestFromStart-> |
794 | 0 | GetLogicalRect(wm, containerSize).IEnd(wm)) |
795 | 0 | closestFromStart = frame; |
796 | 0 | } |
797 | 0 | else { |
798 | 0 | if (!closestFromEnd || |
799 | 0 | rect.IStart(wm) < closestFromEnd-> |
800 | 0 | GetLogicalRect(wm, containerSize).IStart(wm)) |
801 | 0 | closestFromEnd = frame; |
802 | 0 | } |
803 | 0 | } |
804 | 0 | frame = frame->GetNextSibling(); |
805 | 0 | } |
806 | 0 | if (!closestFromStart && !closestFromEnd) { |
807 | 0 | // All frames were zero-width. Just take the first one. |
808 | 0 | closestFromStart = closestFromEnd = line->mFirstChild; |
809 | 0 | } |
810 | 0 | *aPosIsBeforeFirstFrame = mRightToLeft ? !closestFromEnd : !closestFromStart; |
811 | 0 | *aPosIsAfterLastFrame = mRightToLeft ? !closestFromStart : !closestFromEnd; |
812 | 0 | if (closestFromStart == closestFromEnd) { |
813 | 0 | *aFrameFound = closestFromStart; |
814 | 0 | } |
815 | 0 | else if (!closestFromStart) { |
816 | 0 | *aFrameFound = closestFromEnd; |
817 | 0 | } |
818 | 0 | else if (!closestFromEnd) { |
819 | 0 | *aFrameFound = closestFromStart; |
820 | 0 | } |
821 | 0 | else { // we're between two frames |
822 | 0 | nscoord delta = |
823 | 0 | closestFromEnd->GetLogicalRect(wm, containerSize).IStart(wm) - |
824 | 0 | closestFromStart->GetLogicalRect(wm, containerSize).IEnd(wm); |
825 | 0 | if (pos.I(wm) < closestFromStart-> |
826 | 0 | GetLogicalRect(wm, containerSize).IEnd(wm) + delta/2) { |
827 | 0 | *aFrameFound = closestFromStart; |
828 | 0 | } else { |
829 | 0 | *aFrameFound = closestFromEnd; |
830 | 0 | } |
831 | 0 | } |
832 | 0 | return NS_OK; |
833 | 0 | } |
834 | | |
835 | | NS_IMETHODIMP |
836 | | nsLineIterator::GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber) |
837 | 0 | { |
838 | 0 | aFrame = aFrame->GetNextSibling(); |
839 | 0 | return NS_OK; |
840 | 0 | } |
841 | | |
842 | | //---------------------------------------------------------------------- |
843 | | |
844 | | #ifdef NS_BUILD_REFCNT_LOGGING |
845 | | nsFloatCacheList::nsFloatCacheList() : |
846 | | mHead(nullptr) |
847 | | { |
848 | | MOZ_COUNT_CTOR(nsFloatCacheList); |
849 | | } |
850 | | #endif |
851 | | |
852 | | nsFloatCacheList::~nsFloatCacheList() |
853 | 0 | { |
854 | 0 | DeleteAll(); |
855 | 0 | MOZ_COUNT_DTOR(nsFloatCacheList); |
856 | 0 | } |
857 | | |
858 | | void |
859 | | nsFloatCacheList::DeleteAll() |
860 | 0 | { |
861 | 0 | nsFloatCache* c = mHead; |
862 | 0 | while (c) { |
863 | 0 | nsFloatCache* next = c->Next(); |
864 | 0 | delete c; |
865 | 0 | c = next; |
866 | 0 | } |
867 | 0 | mHead = nullptr; |
868 | 0 | } |
869 | | |
870 | | nsFloatCache* |
871 | | nsFloatCacheList::Tail() const |
872 | 0 | { |
873 | 0 | nsFloatCache* fc = mHead; |
874 | 0 | while (fc) { |
875 | 0 | if (!fc->mNext) { |
876 | 0 | break; |
877 | 0 | } |
878 | 0 | fc = fc->mNext; |
879 | 0 | } |
880 | 0 | return fc; |
881 | 0 | } |
882 | | |
883 | | void |
884 | | nsFloatCacheList::Append(nsFloatCacheFreeList& aList) |
885 | 0 | { |
886 | 0 | MOZ_ASSERT(aList.NotEmpty(), "Appending empty list will fail"); |
887 | 0 |
|
888 | 0 | nsFloatCache* tail = Tail(); |
889 | 0 | if (tail) { |
890 | 0 | NS_ASSERTION(!tail->mNext, "Bogus!"); |
891 | 0 | tail->mNext = aList.mHead; |
892 | 0 | } |
893 | 0 | else { |
894 | 0 | NS_ASSERTION(!mHead, "Bogus!"); |
895 | 0 | mHead = aList.mHead; |
896 | 0 | } |
897 | 0 | aList.mHead = nullptr; |
898 | 0 | aList.mTail = nullptr; |
899 | 0 | } |
900 | | |
901 | | nsFloatCache* |
902 | | nsFloatCacheList::Find(nsIFrame* aOutOfFlowFrame) |
903 | 0 | { |
904 | 0 | nsFloatCache* fc = mHead; |
905 | 0 | while (fc) { |
906 | 0 | if (fc->mFloat == aOutOfFlowFrame) { |
907 | 0 | break; |
908 | 0 | } |
909 | 0 | fc = fc->Next(); |
910 | 0 | } |
911 | 0 | return fc; |
912 | 0 | } |
913 | | |
914 | | nsFloatCache* |
915 | | nsFloatCacheList::RemoveAndReturnPrev(nsFloatCache* aElement) |
916 | 0 | { |
917 | 0 | nsFloatCache* fc = mHead; |
918 | 0 | nsFloatCache* prev = nullptr; |
919 | 0 | while (fc) { |
920 | 0 | if (fc == aElement) { |
921 | 0 | if (prev) { |
922 | 0 | prev->mNext = fc->mNext; |
923 | 0 | } else { |
924 | 0 | mHead = fc->mNext; |
925 | 0 | } |
926 | 0 | return prev; |
927 | 0 | } |
928 | 0 | prev = fc; |
929 | 0 | fc = fc->mNext; |
930 | 0 | } |
931 | 0 | return nullptr; |
932 | 0 | } |
933 | | |
934 | | //---------------------------------------------------------------------- |
935 | | |
936 | | #ifdef NS_BUILD_REFCNT_LOGGING |
937 | | nsFloatCacheFreeList::nsFloatCacheFreeList() : |
938 | | mTail(nullptr) |
939 | | { |
940 | | MOZ_COUNT_CTOR(nsFloatCacheFreeList); |
941 | | } |
942 | | |
943 | | nsFloatCacheFreeList::~nsFloatCacheFreeList() |
944 | | { |
945 | | MOZ_COUNT_DTOR(nsFloatCacheFreeList); |
946 | | } |
947 | | #endif |
948 | | |
949 | | void |
950 | | nsFloatCacheFreeList::Append(nsFloatCacheList& aList) |
951 | 0 | { |
952 | 0 | MOZ_ASSERT(aList.NotEmpty(), "Appending empty list will fail"); |
953 | 0 |
|
954 | 0 | if (mTail) { |
955 | 0 | NS_ASSERTION(!mTail->mNext, "Bogus"); |
956 | 0 | mTail->mNext = aList.mHead; |
957 | 0 | } |
958 | 0 | else { |
959 | 0 | NS_ASSERTION(!mHead, "Bogus"); |
960 | 0 | mHead = aList.mHead; |
961 | 0 | } |
962 | 0 | mTail = aList.Tail(); |
963 | 0 | aList.mHead = nullptr; |
964 | 0 | } |
965 | | |
966 | | void |
967 | | nsFloatCacheFreeList::Remove(nsFloatCache* aElement) |
968 | 0 | { |
969 | 0 | nsFloatCache* prev = nsFloatCacheList::RemoveAndReturnPrev(aElement); |
970 | 0 | if (mTail == aElement) { |
971 | 0 | mTail = prev; |
972 | 0 | } |
973 | 0 | } |
974 | | |
975 | | void |
976 | | nsFloatCacheFreeList::DeleteAll() |
977 | 0 | { |
978 | 0 | nsFloatCacheList::DeleteAll(); |
979 | 0 | mTail = nullptr; |
980 | 0 | } |
981 | | |
982 | | nsFloatCache* |
983 | | nsFloatCacheFreeList::Alloc(nsIFrame* aFloat) |
984 | 0 | { |
985 | 0 | MOZ_ASSERT(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW, |
986 | 0 | "This is a float cache, why isn't the frame out-of-flow?"); |
987 | 0 |
|
988 | 0 | nsFloatCache* fc = mHead; |
989 | 0 | if (mHead) { |
990 | 0 | if (mHead == mTail) { |
991 | 0 | mHead = mTail = nullptr; |
992 | 0 | } |
993 | 0 | else { |
994 | 0 | mHead = fc->mNext; |
995 | 0 | } |
996 | 0 | fc->mNext = nullptr; |
997 | 0 | } |
998 | 0 | else { |
999 | 0 | fc = new nsFloatCache(); |
1000 | 0 | } |
1001 | 0 | fc->mFloat = aFloat; |
1002 | 0 | return fc; |
1003 | 0 | } |
1004 | | |
1005 | | void |
1006 | | nsFloatCacheFreeList::Append(nsFloatCache* aFloat) |
1007 | 0 | { |
1008 | 0 | NS_ASSERTION(!aFloat->mNext, "Bogus!"); |
1009 | 0 | aFloat->mNext = nullptr; |
1010 | 0 | if (mTail) { |
1011 | 0 | NS_ASSERTION(!mTail->mNext, "Bogus!"); |
1012 | 0 | mTail->mNext = aFloat; |
1013 | 0 | mTail = aFloat; |
1014 | 0 | } |
1015 | 0 | else { |
1016 | 0 | NS_ASSERTION(!mHead, "Bogus!"); |
1017 | 0 | mHead = mTail = aFloat; |
1018 | 0 | } |
1019 | 0 | } |
1020 | | |
1021 | | //---------------------------------------------------------------------- |
1022 | | |
1023 | | nsFloatCache::nsFloatCache() |
1024 | | : mFloat(nullptr), |
1025 | | mNext(nullptr) |
1026 | 0 | { |
1027 | 0 | MOZ_COUNT_CTOR(nsFloatCache); |
1028 | 0 | } |
1029 | | |
1030 | | #ifdef NS_BUILD_REFCNT_LOGGING |
1031 | | nsFloatCache::~nsFloatCache() |
1032 | | { |
1033 | | MOZ_COUNT_DTOR(nsFloatCache); |
1034 | | } |
1035 | | #endif |