/src/mozilla-central/layout/generic/nsFrameList.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 | | #include "nsFrameList.h" |
8 | | |
9 | | #include "mozilla/ArenaObjectID.h" |
10 | | #include "nsBidiPresUtils.h" |
11 | | #include "nsContainerFrame.h" |
12 | | #include "nsGkAtoms.h" |
13 | | #include "nsILineIterator.h" |
14 | | #include "nsIPresShell.h" |
15 | | #include "nsLayoutUtils.h" |
16 | | #include "nsPresContext.h" |
17 | | |
18 | | using namespace mozilla; |
19 | | |
20 | | namespace mozilla { |
21 | | namespace layout { |
22 | | namespace detail { |
23 | | const AlignedFrameListBytes gEmptyFrameListBytes = { 0 }; |
24 | | } // namespace detail |
25 | | } // namespace layout |
26 | | } // namespace mozilla |
27 | | |
28 | | void* |
29 | | nsFrameList::operator new(size_t sz, nsIPresShell* aPresShell) |
30 | 0 | { |
31 | 0 | return aPresShell->AllocateByObjectID(eArenaObjectID_nsFrameList, sz); |
32 | 0 | } |
33 | | |
34 | | void |
35 | | nsFrameList::Delete(nsIPresShell* aPresShell) |
36 | 0 | { |
37 | 0 | MOZ_ASSERT(this != &EmptyList(), "Shouldn't Delete() this list"); |
38 | 0 | NS_ASSERTION(IsEmpty(), "Shouldn't Delete() a non-empty list"); |
39 | 0 |
|
40 | 0 | aPresShell->FreeByObjectID(eArenaObjectID_nsFrameList, this); |
41 | 0 | } |
42 | | |
43 | | void |
44 | | nsFrameList::DestroyFrames() |
45 | 0 | { |
46 | 0 | while (nsIFrame* frame = RemoveFirstChild()) { |
47 | 0 | frame->Destroy(); |
48 | 0 | } |
49 | 0 | mLastChild = nullptr; |
50 | 0 | } |
51 | | |
52 | | void |
53 | | nsFrameList::DestroyFramesFrom(nsIFrame* aDestructRoot, |
54 | | layout::PostFrameDestroyData& aPostDestroyData) |
55 | 0 | { |
56 | 0 | MOZ_ASSERT(aDestructRoot, "Missing destruct root"); |
57 | 0 |
|
58 | 0 | while (nsIFrame* frame = RemoveFirstChild()) { |
59 | 0 | frame->DestroyFrom(aDestructRoot, aPostDestroyData); |
60 | 0 | } |
61 | 0 | mLastChild = nullptr; |
62 | 0 | } |
63 | | |
64 | | void |
65 | | nsFrameList::SetFrames(nsIFrame* aFrameList) |
66 | 0 | { |
67 | 0 | MOZ_ASSERT(!mFirstChild, "Losing frames"); |
68 | 0 |
|
69 | 0 | mFirstChild = aFrameList; |
70 | 0 | mLastChild = nsLayoutUtils::GetLastSibling(mFirstChild); |
71 | 0 | } |
72 | | |
73 | | void |
74 | | nsFrameList::RemoveFrame(nsIFrame* aFrame) |
75 | 0 | { |
76 | 0 | MOZ_ASSERT(aFrame, "null ptr"); |
77 | | #ifdef DEBUG_FRAME_LIST |
78 | | // ContainsFrame is O(N) |
79 | | MOZ_ASSERT(ContainsFrame(aFrame), "wrong list"); |
80 | | #endif |
81 | |
|
82 | 0 | nsIFrame* nextFrame = aFrame->GetNextSibling(); |
83 | 0 | if (aFrame == mFirstChild) { |
84 | 0 | mFirstChild = nextFrame; |
85 | 0 | aFrame->SetNextSibling(nullptr); |
86 | 0 | if (!nextFrame) { |
87 | 0 | mLastChild = nullptr; |
88 | 0 | } |
89 | 0 | } |
90 | 0 | else { |
91 | 0 | nsIFrame* prevSibling = aFrame->GetPrevSibling(); |
92 | 0 | NS_ASSERTION(prevSibling && prevSibling->GetNextSibling() == aFrame, |
93 | 0 | "Broken frame linkage"); |
94 | 0 | prevSibling->SetNextSibling(nextFrame); |
95 | 0 | aFrame->SetNextSibling(nullptr); |
96 | 0 | if (!nextFrame) { |
97 | 0 | mLastChild = prevSibling; |
98 | 0 | } |
99 | 0 | } |
100 | 0 | } |
101 | | |
102 | | nsFrameList |
103 | | nsFrameList::RemoveFramesAfter(nsIFrame* aAfterFrame) |
104 | 0 | { |
105 | 0 | if (!aAfterFrame) { |
106 | 0 | nsFrameList result; |
107 | 0 | result.InsertFrames(nullptr, nullptr, *this); |
108 | 0 | return result; |
109 | 0 | } |
110 | 0 | |
111 | 0 | MOZ_ASSERT(NotEmpty(), "illegal operation on empty list"); |
112 | | #ifdef DEBUG_FRAME_LIST |
113 | | MOZ_ASSERT(ContainsFrame(aAfterFrame), "wrong list"); |
114 | | #endif |
115 | |
|
116 | 0 | nsIFrame* tail = aAfterFrame->GetNextSibling(); |
117 | 0 | // if (!tail) return EmptyList(); -- worth optimizing this case? |
118 | 0 | nsIFrame* oldLastChild = mLastChild; |
119 | 0 | mLastChild = aAfterFrame; |
120 | 0 | aAfterFrame->SetNextSibling(nullptr); |
121 | 0 | return nsFrameList(tail, tail ? oldLastChild : nullptr); |
122 | 0 | } |
123 | | |
124 | | nsIFrame* |
125 | | nsFrameList::RemoveFirstChild() |
126 | 0 | { |
127 | 0 | if (mFirstChild) { |
128 | 0 | nsIFrame* firstChild = mFirstChild; |
129 | 0 | RemoveFrame(firstChild); |
130 | 0 | return firstChild; |
131 | 0 | } |
132 | 0 | return nullptr; |
133 | 0 | } |
134 | | |
135 | | void |
136 | | nsFrameList::DestroyFrame(nsIFrame* aFrame) |
137 | 0 | { |
138 | 0 | MOZ_ASSERT(aFrame, "null ptr"); |
139 | 0 | RemoveFrame(aFrame); |
140 | 0 | aFrame->Destroy(); |
141 | 0 | } |
142 | | |
143 | | nsFrameList::Slice |
144 | | nsFrameList::InsertFrames(nsContainerFrame* aParent, nsIFrame* aPrevSibling, |
145 | | nsFrameList& aFrameList) |
146 | 0 | { |
147 | 0 | MOZ_ASSERT(aFrameList.NotEmpty(), "Unexpected empty list"); |
148 | 0 |
|
149 | 0 | if (aParent) { |
150 | 0 | aFrameList.ApplySetParent(aParent); |
151 | 0 | } |
152 | 0 |
|
153 | 0 | NS_ASSERTION(IsEmpty() || |
154 | 0 | FirstChild()->GetParent() == aFrameList.FirstChild()->GetParent(), |
155 | 0 | "frame to add has different parent"); |
156 | 0 | NS_ASSERTION(!aPrevSibling || |
157 | 0 | aPrevSibling->GetParent() == aFrameList.FirstChild()->GetParent(), |
158 | 0 | "prev sibling has different parent"); |
159 | | #ifdef DEBUG_FRAME_LIST |
160 | | // ContainsFrame is O(N) |
161 | | NS_ASSERTION(!aPrevSibling || ContainsFrame(aPrevSibling), |
162 | | "prev sibling is not on this list"); |
163 | | #endif |
164 | |
|
165 | 0 | nsIFrame* firstNewFrame = aFrameList.FirstChild(); |
166 | 0 | nsIFrame* nextSibling; |
167 | 0 | if (aPrevSibling) { |
168 | 0 | nextSibling = aPrevSibling->GetNextSibling(); |
169 | 0 | aPrevSibling->SetNextSibling(firstNewFrame); |
170 | 0 | } |
171 | 0 | else { |
172 | 0 | nextSibling = mFirstChild; |
173 | 0 | mFirstChild = firstNewFrame; |
174 | 0 | } |
175 | 0 |
|
176 | 0 | nsIFrame* lastNewFrame = aFrameList.LastChild(); |
177 | 0 | lastNewFrame->SetNextSibling(nextSibling); |
178 | 0 | if (!nextSibling) { |
179 | 0 | mLastChild = lastNewFrame; |
180 | 0 | } |
181 | 0 |
|
182 | 0 | VerifyList(); |
183 | 0 |
|
184 | 0 | aFrameList.Clear(); |
185 | 0 | return Slice(*this, firstNewFrame, nextSibling); |
186 | 0 | } |
187 | | |
188 | | nsFrameList |
189 | | nsFrameList::ExtractHead(FrameLinkEnumerator& aLink) |
190 | 0 | { |
191 | 0 | MOZ_ASSERT(&aLink.List() == this, "Unexpected list"); |
192 | 0 | MOZ_ASSERT(!aLink.PrevFrame() || |
193 | 0 | aLink.PrevFrame()->GetNextSibling() == aLink.NextFrame(), |
194 | 0 | "Unexpected PrevFrame()"); |
195 | 0 | MOZ_ASSERT(aLink.PrevFrame() || aLink.NextFrame() == FirstChild(), |
196 | 0 | "Unexpected NextFrame()"); |
197 | 0 | MOZ_ASSERT(!aLink.PrevFrame() || aLink.NextFrame() != FirstChild(), |
198 | 0 | "Unexpected NextFrame()"); |
199 | 0 | MOZ_ASSERT(aLink.mEnd == nullptr, |
200 | 0 | "Unexpected mEnd for frame link enumerator"); |
201 | 0 |
|
202 | 0 | nsIFrame* prev = aLink.PrevFrame(); |
203 | 0 | nsIFrame* newFirstFrame = nullptr; |
204 | 0 | if (prev) { |
205 | 0 | // Truncate the list after |prev| and hand the first part to our new list. |
206 | 0 | prev->SetNextSibling(nullptr); |
207 | 0 | newFirstFrame = mFirstChild; |
208 | 0 | mFirstChild = aLink.NextFrame(); |
209 | 0 | if (!mFirstChild) { // we handed over the whole list |
210 | 0 | mLastChild = nullptr; |
211 | 0 | } |
212 | 0 |
|
213 | 0 | // Now make sure aLink doesn't point to a frame we no longer have. |
214 | 0 | aLink.mPrev = nullptr; |
215 | 0 | } |
216 | 0 | // else aLink is pointing to before our first frame. Nothing to do. |
217 | 0 |
|
218 | 0 | return nsFrameList(newFirstFrame, prev); |
219 | 0 | } |
220 | | |
221 | | nsFrameList |
222 | | nsFrameList::ExtractTail(FrameLinkEnumerator& aLink) |
223 | 0 | { |
224 | 0 | MOZ_ASSERT(&aLink.List() == this, "Unexpected list"); |
225 | 0 | MOZ_ASSERT(!aLink.PrevFrame() || |
226 | 0 | aLink.PrevFrame()->GetNextSibling() == aLink.NextFrame(), |
227 | 0 | "Unexpected PrevFrame()"); |
228 | 0 | MOZ_ASSERT(aLink.PrevFrame() || aLink.NextFrame() == FirstChild(), |
229 | 0 | "Unexpected NextFrame()"); |
230 | 0 | MOZ_ASSERT(!aLink.PrevFrame() || aLink.NextFrame() != FirstChild(), |
231 | 0 | "Unexpected NextFrame()"); |
232 | 0 | MOZ_ASSERT(aLink.mEnd == nullptr, |
233 | 0 | "Unexpected mEnd for frame link enumerator"); |
234 | 0 |
|
235 | 0 | nsIFrame* prev = aLink.PrevFrame(); |
236 | 0 | nsIFrame* newFirstFrame; |
237 | 0 | nsIFrame* newLastFrame; |
238 | 0 | if (prev) { |
239 | 0 | // Truncate the list after |prev| and hand the second part to our new list |
240 | 0 | prev->SetNextSibling(nullptr); |
241 | 0 | newFirstFrame = aLink.NextFrame(); |
242 | 0 | newLastFrame = newFirstFrame ? mLastChild : nullptr; |
243 | 0 | mLastChild = prev; |
244 | 0 | } else { |
245 | 0 | // Hand the whole list over to our new list |
246 | 0 | newFirstFrame = mFirstChild; |
247 | 0 | newLastFrame = mLastChild; |
248 | 0 | Clear(); |
249 | 0 | } |
250 | 0 |
|
251 | 0 | // Now make sure aLink doesn't point to a frame we no longer have. |
252 | 0 | aLink.mFrame = nullptr; |
253 | 0 |
|
254 | 0 | MOZ_ASSERT(aLink.AtEnd(), "What's going on here?"); |
255 | 0 |
|
256 | 0 | return nsFrameList(newFirstFrame, newLastFrame); |
257 | 0 | } |
258 | | |
259 | | nsIFrame* |
260 | | nsFrameList::FrameAt(int32_t aIndex) const |
261 | 0 | { |
262 | 0 | MOZ_ASSERT(aIndex >= 0, "invalid arg"); |
263 | 0 | if (aIndex < 0) return nullptr; |
264 | 0 | nsIFrame* frame = mFirstChild; |
265 | 0 | while ((aIndex-- > 0) && frame) { |
266 | 0 | frame = frame->GetNextSibling(); |
267 | 0 | } |
268 | 0 | return frame; |
269 | 0 | } |
270 | | |
271 | | int32_t |
272 | | nsFrameList::IndexOf(nsIFrame* aFrame) const |
273 | 0 | { |
274 | 0 | int32_t count = 0; |
275 | 0 | for (nsIFrame* f = mFirstChild; f; f = f->GetNextSibling()) { |
276 | 0 | if (f == aFrame) |
277 | 0 | return count; |
278 | 0 | ++count; |
279 | 0 | } |
280 | 0 | return -1; |
281 | 0 | } |
282 | | |
283 | | bool |
284 | | nsFrameList::ContainsFrame(const nsIFrame* aFrame) const |
285 | 0 | { |
286 | 0 | MOZ_ASSERT(aFrame, "null ptr"); |
287 | 0 |
|
288 | 0 | nsIFrame* frame = mFirstChild; |
289 | 0 | while (frame) { |
290 | 0 | if (frame == aFrame) { |
291 | 0 | return true; |
292 | 0 | } |
293 | 0 | frame = frame->GetNextSibling(); |
294 | 0 | } |
295 | 0 | return false; |
296 | 0 | } |
297 | | |
298 | | int32_t |
299 | | nsFrameList::GetLength() const |
300 | 0 | { |
301 | 0 | int32_t count = 0; |
302 | 0 | nsIFrame* frame = mFirstChild; |
303 | 0 | while (frame) { |
304 | 0 | count++; |
305 | 0 | frame = frame->GetNextSibling(); |
306 | 0 | } |
307 | 0 | return count; |
308 | 0 | } |
309 | | |
310 | | void |
311 | | nsFrameList::ApplySetParent(nsContainerFrame* aParent) const |
312 | 0 | { |
313 | 0 | NS_ASSERTION(aParent, "null ptr"); |
314 | 0 |
|
315 | 0 | for (nsIFrame* f = FirstChild(); f; f = f->GetNextSibling()) { |
316 | 0 | f->SetParent(aParent); |
317 | 0 | } |
318 | 0 | } |
319 | | |
320 | | /* static */ void |
321 | | nsFrameList::UnhookFrameFromSiblings(nsIFrame* aFrame) |
322 | 0 | { |
323 | 0 | MOZ_ASSERT(aFrame->GetPrevSibling() && aFrame->GetNextSibling()); |
324 | 0 | nsIFrame* const nextSibling = aFrame->GetNextSibling(); |
325 | 0 | nsIFrame* const prevSibling = aFrame->GetPrevSibling(); |
326 | 0 | aFrame->SetNextSibling(nullptr); |
327 | 0 | prevSibling->SetNextSibling(nextSibling); |
328 | 0 | MOZ_ASSERT(!aFrame->GetPrevSibling() && !aFrame->GetNextSibling()); |
329 | 0 | } |
330 | | |
331 | | #ifdef DEBUG_FRAME_DUMP |
332 | | void |
333 | | nsFrameList::List(FILE* out) const |
334 | | { |
335 | | fprintf_stderr(out, "<\n"); |
336 | | for (nsIFrame* frame = mFirstChild; frame; |
337 | | frame = frame->GetNextSibling()) { |
338 | | frame->List(out, " "); |
339 | | } |
340 | | fprintf_stderr(out, ">\n"); |
341 | | } |
342 | | #endif |
343 | | |
344 | | nsIFrame* |
345 | | nsFrameList::GetPrevVisualFor(nsIFrame* aFrame) const |
346 | 0 | { |
347 | 0 | if (!mFirstChild) |
348 | 0 | return nullptr; |
349 | 0 | |
350 | 0 | nsIFrame* parent = mFirstChild->GetParent(); |
351 | 0 | if (!parent) |
352 | 0 | return aFrame ? aFrame->GetPrevSibling() : LastChild(); |
353 | 0 | |
354 | 0 | nsBidiDirection paraDir = nsBidiPresUtils::ParagraphDirection(mFirstChild); |
355 | 0 |
|
356 | 0 | nsAutoLineIterator iter = parent->GetLineIterator(); |
357 | 0 | if (!iter) { |
358 | 0 | // Parent is not a block Frame |
359 | 0 | if (parent->IsLineFrame()) { |
360 | 0 | // Line frames are not bidi-splittable, so need to consider bidi reordering |
361 | 0 | if (paraDir == NSBIDI_LTR) { |
362 | 0 | return nsBidiPresUtils::GetFrameToLeftOf(aFrame, mFirstChild, -1); |
363 | 0 | } else { // RTL |
364 | 0 | return nsBidiPresUtils::GetFrameToRightOf(aFrame, mFirstChild, -1); |
365 | 0 | } |
366 | 0 | } else { |
367 | 0 | // Just get the next or prev sibling, depending on block and frame direction. |
368 | 0 | if (nsBidiPresUtils::IsFrameInParagraphDirection(mFirstChild)) { |
369 | 0 | return aFrame ? aFrame->GetPrevSibling() : LastChild(); |
370 | 0 | } else { |
371 | 0 | return aFrame ? aFrame->GetNextSibling() : mFirstChild; |
372 | 0 | } |
373 | 0 | } |
374 | 0 | } |
375 | 0 |
|
376 | 0 | // Parent is a block frame, so use the LineIterator to find the previous visual |
377 | 0 | // sibling on this line, or the last one on the previous line. |
378 | 0 |
|
379 | 0 | int32_t thisLine; |
380 | 0 | if (aFrame) { |
381 | 0 | thisLine = iter->FindLineContaining(aFrame); |
382 | 0 | if (thisLine < 0) |
383 | 0 | return nullptr; |
384 | 0 | } else { |
385 | 0 | thisLine = iter->GetNumLines(); |
386 | 0 | } |
387 | 0 |
|
388 | 0 | nsIFrame* frame = nullptr; |
389 | 0 | nsIFrame* firstFrameOnLine; |
390 | 0 | int32_t numFramesOnLine; |
391 | 0 | nsRect lineBounds; |
392 | 0 |
|
393 | 0 | if (aFrame) { |
394 | 0 | iter->GetLine(thisLine, &firstFrameOnLine, &numFramesOnLine, lineBounds); |
395 | 0 |
|
396 | 0 | if (paraDir == NSBIDI_LTR) { |
397 | 0 | frame = nsBidiPresUtils::GetFrameToLeftOf(aFrame, firstFrameOnLine, numFramesOnLine); |
398 | 0 | } else { // RTL |
399 | 0 | frame = nsBidiPresUtils::GetFrameToRightOf(aFrame, firstFrameOnLine, numFramesOnLine); |
400 | 0 | } |
401 | 0 | } |
402 | 0 |
|
403 | 0 | if (!frame && thisLine > 0) { |
404 | 0 | // Get the last frame of the previous line |
405 | 0 | iter->GetLine(thisLine - 1, &firstFrameOnLine, &numFramesOnLine, lineBounds); |
406 | 0 |
|
407 | 0 | if (paraDir == NSBIDI_LTR) { |
408 | 0 | frame = nsBidiPresUtils::GetFrameToLeftOf(nullptr, firstFrameOnLine, numFramesOnLine); |
409 | 0 | } else { // RTL |
410 | 0 | frame = nsBidiPresUtils::GetFrameToRightOf(nullptr, firstFrameOnLine, numFramesOnLine); |
411 | 0 | } |
412 | 0 | } |
413 | 0 | return frame; |
414 | 0 | } |
415 | | |
416 | | nsIFrame* |
417 | | nsFrameList::GetNextVisualFor(nsIFrame* aFrame) const |
418 | 0 | { |
419 | 0 | if (!mFirstChild) |
420 | 0 | return nullptr; |
421 | 0 | |
422 | 0 | nsIFrame* parent = mFirstChild->GetParent(); |
423 | 0 | if (!parent) |
424 | 0 | return aFrame ? aFrame->GetPrevSibling() : mFirstChild; |
425 | 0 | |
426 | 0 | nsBidiDirection paraDir = nsBidiPresUtils::ParagraphDirection(mFirstChild); |
427 | 0 |
|
428 | 0 | nsAutoLineIterator iter = parent->GetLineIterator(); |
429 | 0 | if (!iter) { |
430 | 0 | // Parent is not a block Frame |
431 | 0 | if (parent->IsLineFrame()) { |
432 | 0 | // Line frames are not bidi-splittable, so need to consider bidi reordering |
433 | 0 | if (paraDir == NSBIDI_LTR) { |
434 | 0 | return nsBidiPresUtils::GetFrameToRightOf(aFrame, mFirstChild, -1); |
435 | 0 | } else { // RTL |
436 | 0 | return nsBidiPresUtils::GetFrameToLeftOf(aFrame, mFirstChild, -1); |
437 | 0 | } |
438 | 0 | } else { |
439 | 0 | // Just get the next or prev sibling, depending on block and frame direction. |
440 | 0 | if (nsBidiPresUtils::IsFrameInParagraphDirection(mFirstChild)) { |
441 | 0 | return aFrame ? aFrame->GetNextSibling() : mFirstChild; |
442 | 0 | } else { |
443 | 0 | return aFrame ? aFrame->GetPrevSibling() : LastChild(); |
444 | 0 | } |
445 | 0 | } |
446 | 0 | } |
447 | 0 |
|
448 | 0 | // Parent is a block frame, so use the LineIterator to find the next visual |
449 | 0 | // sibling on this line, or the first one on the next line. |
450 | 0 |
|
451 | 0 | int32_t thisLine; |
452 | 0 | if (aFrame) { |
453 | 0 | thisLine = iter->FindLineContaining(aFrame); |
454 | 0 | if (thisLine < 0) |
455 | 0 | return nullptr; |
456 | 0 | } else { |
457 | 0 | thisLine = -1; |
458 | 0 | } |
459 | 0 |
|
460 | 0 | nsIFrame* frame = nullptr; |
461 | 0 | nsIFrame* firstFrameOnLine; |
462 | 0 | int32_t numFramesOnLine; |
463 | 0 | nsRect lineBounds; |
464 | 0 |
|
465 | 0 | if (aFrame) { |
466 | 0 | iter->GetLine(thisLine, &firstFrameOnLine, &numFramesOnLine, lineBounds); |
467 | 0 |
|
468 | 0 | if (paraDir == NSBIDI_LTR) { |
469 | 0 | frame = nsBidiPresUtils::GetFrameToRightOf(aFrame, firstFrameOnLine, numFramesOnLine); |
470 | 0 | } else { // RTL |
471 | 0 | frame = nsBidiPresUtils::GetFrameToLeftOf(aFrame, firstFrameOnLine, numFramesOnLine); |
472 | 0 | } |
473 | 0 | } |
474 | 0 |
|
475 | 0 | int32_t numLines = iter->GetNumLines(); |
476 | 0 | if (!frame && thisLine < numLines - 1) { |
477 | 0 | // Get the first frame of the next line |
478 | 0 | iter->GetLine(thisLine + 1, &firstFrameOnLine, &numFramesOnLine, lineBounds); |
479 | 0 |
|
480 | 0 | if (paraDir == NSBIDI_LTR) { |
481 | 0 | frame = nsBidiPresUtils::GetFrameToRightOf(nullptr, firstFrameOnLine, numFramesOnLine); |
482 | 0 | } else { // RTL |
483 | 0 | frame = nsBidiPresUtils::GetFrameToLeftOf(nullptr, firstFrameOnLine, numFramesOnLine); |
484 | 0 | } |
485 | 0 | } |
486 | 0 | return frame; |
487 | 0 | } |
488 | | |
489 | | #ifdef DEBUG_FRAME_LIST |
490 | | void |
491 | | nsFrameList::VerifyList() const |
492 | | { |
493 | | NS_ASSERTION((mFirstChild == nullptr) == (mLastChild == nullptr), |
494 | | "bad list state"); |
495 | | |
496 | | if (IsEmpty()) { |
497 | | return; |
498 | | } |
499 | | |
500 | | // Simple algorithm to find a loop in a linked list -- advance pointers |
501 | | // through it at speeds of 1 and 2, and if they ever get to be equal bail |
502 | | NS_ASSERTION(!mFirstChild->GetPrevSibling(), "bad prev sibling pointer"); |
503 | | nsIFrame *first = mFirstChild, *second = mFirstChild; |
504 | | for (;;) { |
505 | | first = first->GetNextSibling(); |
506 | | second = second->GetNextSibling(); |
507 | | if (!second) { |
508 | | break; |
509 | | } |
510 | | NS_ASSERTION(second->GetPrevSibling()->GetNextSibling() == second, |
511 | | "bad prev sibling pointer"); |
512 | | second = second->GetNextSibling(); |
513 | | if (first == second) { |
514 | | // Loop detected! Since second advances faster, they can't both be null; |
515 | | // we would have broken out of the loop long ago. |
516 | | NS_ERROR("loop in frame list. This will probably hang soon."); |
517 | | return; |
518 | | } |
519 | | if (!second) { |
520 | | break; |
521 | | } |
522 | | NS_ASSERTION(second->GetPrevSibling()->GetNextSibling() == second, |
523 | | "bad prev sibling pointer"); |
524 | | } |
525 | | |
526 | | NS_ASSERTION(mLastChild == nsLayoutUtils::GetLastSibling(mFirstChild), |
527 | | "bogus mLastChild"); |
528 | | // XXX we should also assert that all GetParent() are either null or |
529 | | // the same non-null value, but nsCSSFrameConstructor::nsFrameItems |
530 | | // prevents that, e.g. table captions. |
531 | | } |
532 | | #endif |
533 | | |
534 | | namespace mozilla { |
535 | | namespace layout { |
536 | | |
537 | | AutoFrameListPtr::~AutoFrameListPtr() |
538 | 0 | { |
539 | 0 | if (mFrameList) { |
540 | 0 | mFrameList->Delete(mPresContext->PresShell()); |
541 | 0 | } |
542 | 0 | } |
543 | | |
544 | | } // namespace layout |
545 | | } // namespace mozilla |