Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /* base class #1 for rendering objects that have child lists */
7 :
8 : #include "nsContainerFrame.h"
9 :
10 : #include "mozilla/dom/HTMLDetailsElement.h"
11 : #include "mozilla/dom/HTMLSummaryElement.h"
12 : #include "nsAbsoluteContainingBlock.h"
13 : #include "nsAttrValue.h"
14 : #include "nsAttrValueInlines.h"
15 : #include "nsIDocument.h"
16 : #include "nsPresContext.h"
17 : #include "nsStyleContext.h"
18 : #include "nsRect.h"
19 : #include "nsPoint.h"
20 : #include "nsStyleConsts.h"
21 : #include "nsView.h"
22 : #include "nsIPresShell.h"
23 : #include "nsCOMPtr.h"
24 : #include "nsGkAtoms.h"
25 : #include "nsViewManager.h"
26 : #include "nsIWidget.h"
27 : #include "nsCSSRendering.h"
28 : #include "nsError.h"
29 : #include "nsDisplayList.h"
30 : #include "nsIBaseWindow.h"
31 : #include "nsBoxLayoutState.h"
32 : #include "nsCSSFrameConstructor.h"
33 : #include "nsBlockFrame.h"
34 : #include "nsBulletFrame.h"
35 : #include "nsPlaceholderFrame.h"
36 : #include "mozilla/AutoRestore.h"
37 : #include "nsIFrameInlines.h"
38 : #include "nsPrintfCString.h"
39 : #include <algorithm>
40 :
41 : using namespace mozilla;
42 : using namespace mozilla::dom;
43 : using namespace mozilla::layout;
44 :
45 76 : nsContainerFrame::~nsContainerFrame()
46 : {
47 76 : }
48 :
49 7329 : NS_QUERYFRAME_HEAD(nsContainerFrame)
50 344 : NS_QUERYFRAME_ENTRY(nsContainerFrame)
51 6985 : NS_QUERYFRAME_TAIL_INHERITING(nsSplittableFrame)
52 :
53 : void
54 448 : nsContainerFrame::Init(nsIContent* aContent,
55 : nsContainerFrame* aParent,
56 : nsIFrame* aPrevInFlow)
57 : {
58 448 : nsSplittableFrame::Init(aContent, aParent, aPrevInFlow);
59 448 : if (aPrevInFlow) {
60 : // Make sure we copy bits from our prev-in-flow that will affect
61 : // us. A continuation for a container frame needs to know if it
62 : // has a child with a view so that we'll properly reposition it.
63 0 : if (aPrevInFlow->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)
64 0 : AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
65 : }
66 448 : }
67 :
68 : void
69 414 : nsContainerFrame::SetInitialChildList(ChildListID aListID,
70 : nsFrameList& aChildList)
71 : {
72 : #ifdef DEBUG
73 414 : nsFrame::VerifyDirtyBitSet(aChildList);
74 : #endif
75 414 : if (aListID == kPrincipalList) {
76 414 : MOZ_ASSERT(mFrames.IsEmpty(),
77 : "unexpected second call to SetInitialChildList");
78 414 : mFrames.SetFrames(aChildList);
79 0 : } else if (aListID == kBackdropList) {
80 0 : MOZ_ASSERT(StyleDisplay()->mTopLayer != NS_STYLE_TOP_LAYER_NONE,
81 : "Only top layer frames should have backdrop");
82 0 : MOZ_ASSERT(GetStateBits() & NS_FRAME_OUT_OF_FLOW,
83 : "Top layer frames should be out-of-flow");
84 0 : MOZ_ASSERT(!GetProperty(BackdropProperty()),
85 : "We shouldn't have setup backdrop frame list before");
86 : #ifdef DEBUG
87 : {
88 0 : nsIFrame* placeholder = aChildList.FirstChild();
89 0 : MOZ_ASSERT(aChildList.OnlyChild(), "Should have only one backdrop");
90 0 : MOZ_ASSERT(placeholder->IsPlaceholderFrame(),
91 : "The frame to be stored should be a placeholder");
92 0 : MOZ_ASSERT(static_cast<nsPlaceholderFrame*>(placeholder)->
93 : GetOutOfFlowFrame()->IsBackdropFrame(),
94 : "The placeholder should points to a backdrop frame");
95 : }
96 : #endif
97 : nsFrameList* list =
98 0 : new (PresContext()->PresShell()) nsFrameList(aChildList);
99 0 : SetProperty(BackdropProperty(), list);
100 : } else {
101 0 : MOZ_ASSERT_UNREACHABLE("Unexpected child list");
102 : }
103 414 : }
104 :
105 : void
106 23 : nsContainerFrame::AppendFrames(ChildListID aListID,
107 : nsFrameList& aFrameList)
108 : {
109 23 : MOZ_ASSERT(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
110 : "unexpected child list");
111 :
112 23 : if (MOZ_UNLIKELY(aFrameList.IsEmpty())) {
113 23 : return;
114 : }
115 :
116 0 : DrainSelfOverflowList(); // ensure the last frame is in mFrames
117 0 : mFrames.AppendFrames(this, aFrameList);
118 :
119 0 : if (aListID != kNoReflowPrincipalList) {
120 0 : PresContext()->PresShell()->
121 0 : FrameNeedsReflow(this, nsIPresShell::eTreeChange,
122 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
123 : }
124 : }
125 :
126 : void
127 0 : nsContainerFrame::InsertFrames(ChildListID aListID,
128 : nsIFrame* aPrevFrame,
129 : nsFrameList& aFrameList)
130 : {
131 0 : MOZ_ASSERT(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
132 : "unexpected child list");
133 0 : NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
134 : "inserting after sibling frame with different parent");
135 :
136 0 : if (MOZ_UNLIKELY(aFrameList.IsEmpty())) {
137 0 : return;
138 : }
139 :
140 0 : DrainSelfOverflowList(); // ensure aPrevFrame is in mFrames
141 0 : mFrames.InsertFrames(this, aPrevFrame, aFrameList);
142 :
143 0 : if (aListID != kNoReflowPrincipalList) {
144 0 : PresContext()->PresShell()->
145 0 : FrameNeedsReflow(this, nsIPresShell::eTreeChange,
146 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
147 : }
148 : }
149 :
150 : void
151 0 : nsContainerFrame::RemoveFrame(ChildListID aListID,
152 : nsIFrame* aOldFrame)
153 : {
154 0 : MOZ_ASSERT(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
155 : "unexpected child list");
156 :
157 : // Loop and destroy aOldFrame and all of its continuations.
158 : // Request a reflow on the parent frames involved unless we were explicitly
159 : // told not to (kNoReflowPrincipalList).
160 0 : bool generateReflowCommand = true;
161 0 : if (kNoReflowPrincipalList == aListID) {
162 0 : generateReflowCommand = false;
163 : }
164 0 : nsIPresShell* shell = PresContext()->PresShell();
165 0 : nsContainerFrame* lastParent = nullptr;
166 0 : while (aOldFrame) {
167 0 : nsIFrame* oldFrameNextContinuation = aOldFrame->GetNextContinuation();
168 0 : nsContainerFrame* parent = aOldFrame->GetParent();
169 : // Please note that 'parent' may not actually be where 'aOldFrame' lives.
170 : // We really MUST use StealFrame() and nothing else here.
171 : // @see nsInlineFrame::StealFrame for details.
172 0 : parent->StealFrame(aOldFrame);
173 0 : aOldFrame->Destroy();
174 0 : aOldFrame = oldFrameNextContinuation;
175 0 : if (parent != lastParent && generateReflowCommand) {
176 : shell->FrameNeedsReflow(parent, nsIPresShell::eTreeChange,
177 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
178 0 : lastParent = parent;
179 : }
180 : }
181 0 : }
182 :
183 : void
184 92 : nsContainerFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot)
185 : {
186 92 : if (IsAbsoluteContainer()) {
187 2 : GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot);
188 2 : MarkAsNotAbsoluteContainingBlock();
189 : }
190 92 : }
191 :
192 : void
193 0 : nsContainerFrame::SafelyDestroyFrameListProp(nsIFrame* aDestructRoot,
194 : nsIPresShell* aPresShell,
195 : FrameListPropertyDescriptor aProp)
196 : {
197 : // Note that the last frame can be removed through another route and thus
198 : // delete the property -- that's why we fetch the property again before
199 : // removing each frame rather than fetching it once and iterating the list.
200 0 : while (nsFrameList* frameList = GetProperty(aProp)) {
201 0 : nsIFrame* frame = frameList->RemoveFirstChild();
202 0 : if (MOZ_LIKELY(frame)) {
203 0 : frame->DestroyFrom(aDestructRoot);
204 : } else {
205 0 : RemoveProperty(aProp);
206 0 : frameList->Delete(aPresShell);
207 0 : return;
208 : }
209 0 : }
210 : }
211 :
212 : void
213 76 : nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot)
214 : {
215 : // Prevent event dispatch during destruction.
216 76 : if (HasView()) {
217 9 : GetView()->SetFrame(nullptr);
218 : }
219 :
220 76 : DestroyAbsoluteFrames(aDestructRoot);
221 :
222 : // Destroy frames on the principal child list.
223 76 : mFrames.DestroyFramesFrom(aDestructRoot);
224 :
225 : // If we have any IB split siblings, clear their references to us.
226 76 : if (HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) {
227 : // Delete previous sibling's reference to me.
228 0 : nsIFrame* prevSib = GetProperty(nsIFrame::IBSplitPrevSibling());
229 0 : if (prevSib) {
230 0 : NS_WARNING_ASSERTION(
231 : this == prevSib->GetProperty(nsIFrame::IBSplitSibling()),
232 : "IB sibling chain is inconsistent");
233 0 : prevSib->DeleteProperty(nsIFrame::IBSplitSibling());
234 : }
235 :
236 : // Delete next sibling's reference to me.
237 0 : nsIFrame* nextSib = GetProperty(nsIFrame::IBSplitSibling());
238 0 : if (nextSib) {
239 0 : NS_WARNING_ASSERTION(
240 : this == nextSib->GetProperty(nsIFrame::IBSplitPrevSibling()),
241 : "IB sibling chain is inconsistent");
242 0 : nextSib->DeleteProperty(nsIFrame::IBSplitPrevSibling());
243 : }
244 :
245 : #ifdef DEBUG
246 : // This is just so we can assert it's not set in nsFrame::DestroyFrom.
247 0 : RemoveStateBits(NS_FRAME_PART_OF_IBSPLIT);
248 : #endif
249 : }
250 :
251 76 : if (MOZ_UNLIKELY(!mProperties.IsEmpty())) {
252 : using T = mozilla::FrameProperties::UntypedDescriptor;
253 22 : bool hasO = false, hasOC = false, hasEOC = false, hasBackdrop = false;
254 46 : mProperties.ForEach([&] (const T& aProp, void*) {
255 24 : if (aProp == OverflowProperty()) {
256 0 : hasO = true;
257 24 : } else if (aProp == OverflowContainersProperty()) {
258 0 : hasOC = true;
259 24 : } else if (aProp == ExcessOverflowContainersProperty()) {
260 0 : hasEOC = true;
261 24 : } else if (aProp == BackdropProperty()) {
262 0 : hasBackdrop = true;
263 : }
264 24 : return true;
265 44 : });
266 :
267 : // Destroy frames on the auxiliary frame lists and delete the lists.
268 22 : nsPresContext* pc = PresContext();
269 22 : nsIPresShell* shell = pc->PresShell();
270 22 : if (hasO) {
271 0 : SafelyDestroyFrameListProp(aDestructRoot, shell, OverflowProperty());
272 : }
273 :
274 22 : MOZ_ASSERT(IsFrameOfType(eCanContainOverflowContainers) ||
275 : !(hasOC || hasEOC),
276 : "this type of frame shouldn't have overflow containers");
277 22 : if (hasOC) {
278 0 : SafelyDestroyFrameListProp(aDestructRoot, shell,
279 0 : OverflowContainersProperty());
280 : }
281 22 : if (hasEOC) {
282 0 : SafelyDestroyFrameListProp(aDestructRoot, shell,
283 0 : ExcessOverflowContainersProperty());
284 : }
285 :
286 22 : MOZ_ASSERT(!GetProperty(BackdropProperty()) ||
287 : StyleDisplay()->mTopLayer != NS_STYLE_TOP_LAYER_NONE,
288 : "only top layer frame may have backdrop");
289 22 : if (hasBackdrop) {
290 0 : SafelyDestroyFrameListProp(aDestructRoot, shell, BackdropProperty());
291 : }
292 : }
293 :
294 76 : nsSplittableFrame::DestroyFrom(aDestructRoot);
295 76 : }
296 :
297 : /////////////////////////////////////////////////////////////////////////////
298 : // Child frame enumeration
299 :
300 : const nsFrameList&
301 6161 : nsContainerFrame::GetChildList(ChildListID aListID) const
302 : {
303 : // We only know about the principal child list, the overflow lists,
304 : // and the backdrop list.
305 6161 : switch (aListID) {
306 : case kPrincipalList:
307 6135 : return mFrames;
308 : case kOverflowList: {
309 0 : nsFrameList* list = GetOverflowFrames();
310 0 : return list ? *list : nsFrameList::EmptyList();
311 : }
312 : case kOverflowContainersList: {
313 0 : nsFrameList* list = GetPropTableFrames(OverflowContainersProperty());
314 0 : return list ? *list : nsFrameList::EmptyList();
315 : }
316 : case kExcessOverflowContainersList: {
317 : nsFrameList* list =
318 0 : GetPropTableFrames(ExcessOverflowContainersProperty());
319 0 : return list ? *list : nsFrameList::EmptyList();
320 : }
321 : case kBackdropList: {
322 0 : nsFrameList* list = GetPropTableFrames(BackdropProperty());
323 0 : return list ? *list : nsFrameList::EmptyList();
324 : }
325 : default:
326 26 : return nsSplittableFrame::GetChildList(aListID);
327 : }
328 : }
329 :
330 : void
331 4822 : nsContainerFrame::GetChildLists(nsTArray<ChildList>* aLists) const
332 : {
333 4822 : mFrames.AppendIfNonempty(aLists, kPrincipalList);
334 :
335 : using T = mozilla::FrameProperties::UntypedDescriptor;
336 7152 : mProperties.ForEach([this, aLists] (const T& aProp, void* aValue) {
337 : typedef const nsFrameList* L;
338 2330 : if (aProp == OverflowProperty()) {
339 0 : L(aValue)->AppendIfNonempty(aLists, kOverflowList);
340 2330 : } else if (aProp == OverflowContainersProperty()) {
341 0 : MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers),
342 : "found unexpected OverflowContainersProperty");
343 0 : Unused << this; // silence clang -Wunused-lambda-capture in opt builds
344 0 : L(aValue)->AppendIfNonempty(aLists, kOverflowContainersList);
345 2330 : } else if (aProp == ExcessOverflowContainersProperty()) {
346 0 : MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers),
347 : "found unexpected ExcessOverflowContainersProperty");
348 0 : Unused << this; // silence clang -Wunused-lambda-capture in opt builds
349 0 : L(aValue)->AppendIfNonempty(aLists, kExcessOverflowContainersList);
350 2330 : } else if (aProp == BackdropProperty()) {
351 0 : L(aValue)->AppendIfNonempty(aLists, kBackdropList);
352 : }
353 2330 : return true;
354 9644 : });
355 :
356 4822 : nsSplittableFrame::GetChildLists(aLists);
357 4822 : }
358 :
359 : /////////////////////////////////////////////////////////////////////////////
360 : // Painting/Events
361 :
362 : void
363 0 : nsContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
364 : const nsRect& aDirtyRect,
365 : const nsDisplayListSet& aLists)
366 : {
367 0 : DisplayBorderBackgroundOutline(aBuilder, aLists);
368 :
369 0 : BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
370 0 : }
371 :
372 : void
373 63 : nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder* aBuilder,
374 : const nsRect& aDirtyRect,
375 : const nsDisplayListSet& aLists,
376 : uint32_t aFlags)
377 : {
378 63 : nsIFrame* kid = mFrames.FirstChild();
379 : // Put each child's background directly onto the content list
380 63 : nsDisplayListSet set(aLists, aLists.Content());
381 : // The children should be in content order
382 233 : while (kid) {
383 85 : BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, aFlags);
384 85 : kid = kid->GetNextSibling();
385 : }
386 63 : }
387 :
388 : /* virtual */ void
389 429 : nsContainerFrame::ChildIsDirty(nsIFrame* aChild)
390 : {
391 429 : NS_ASSERTION(NS_SUBTREE_DIRTY(aChild), "child isn't actually dirty");
392 :
393 429 : AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
394 429 : }
395 :
396 : nsIFrame::FrameSearchResult
397 0 : nsContainerFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
398 : {
399 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
400 : // Don't allow the caret to stay in an empty (leaf) container frame.
401 0 : return CONTINUE_EMPTY;
402 : }
403 :
404 : nsIFrame::FrameSearchResult
405 0 : nsContainerFrame::PeekOffsetCharacter(
406 : bool aForward, int32_t* aOffset,
407 : PeekOffsetCharacterOptions aOptions)
408 : {
409 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
410 : // Don't allow the caret to stay in an empty (leaf) container frame.
411 0 : return CONTINUE_EMPTY;
412 : }
413 :
414 : /////////////////////////////////////////////////////////////////////////////
415 : // Helper member functions
416 :
417 : /**
418 : * Position the view associated with |aKidFrame|, if there is one. A
419 : * container frame should call this method after positioning a frame,
420 : * but before |Reflow|.
421 : */
422 : void
423 2140 : nsContainerFrame::PositionFrameView(nsIFrame* aKidFrame)
424 : {
425 2140 : nsIFrame* parentFrame = aKidFrame->GetParent();
426 2140 : if (!aKidFrame->HasView() || !parentFrame)
427 4212 : return;
428 :
429 34 : nsView* view = aKidFrame->GetView();
430 34 : nsViewManager* vm = view->GetViewManager();
431 34 : nsPoint pt;
432 34 : nsView* ancestorView = parentFrame->GetClosestView(&pt);
433 :
434 34 : if (ancestorView != view->GetParent()) {
435 0 : NS_ASSERTION(ancestorView == view->GetParent()->GetParent(),
436 : "Allowed only one anonymous view between frames");
437 : // parentFrame is responsible for positioning aKidFrame's view
438 : // explicitly
439 0 : return;
440 : }
441 :
442 34 : pt += aKidFrame->GetPosition();
443 34 : vm->MoveViewTo(view, pt.x, pt.y);
444 : }
445 :
446 : nsresult
447 0 : nsContainerFrame::ReparentFrameView(nsIFrame* aChildFrame,
448 : nsIFrame* aOldParentFrame,
449 : nsIFrame* aNewParentFrame)
450 : {
451 0 : NS_PRECONDITION(aChildFrame, "null child frame pointer");
452 0 : NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
453 0 : NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
454 0 : NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
455 :
456 : // See if either the old parent frame or the new parent frame have a view
457 0 : while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
458 : // Walk up both the old parent frame and the new parent frame nodes
459 : // stopping when we either find a common parent or views for one
460 : // or both of the frames.
461 : //
462 : // This works well in the common case where we push/pull and the old parent
463 : // frame and the new parent frame are part of the same flow. They will
464 : // typically be the same distance (height wise) from the
465 0 : aOldParentFrame = aOldParentFrame->GetParent();
466 0 : aNewParentFrame = aNewParentFrame->GetParent();
467 :
468 : // We should never walk all the way to the root frame without finding
469 : // a view
470 0 : NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
471 :
472 : // See if we reached a common ancestor
473 0 : if (aOldParentFrame == aNewParentFrame) {
474 0 : break;
475 : }
476 : }
477 :
478 : // See if we found a common parent frame
479 0 : if (aOldParentFrame == aNewParentFrame) {
480 : // We found a common parent and there are no views between the old parent
481 : // and the common parent or the new parent frame and the common parent.
482 : // Because neither the old parent frame nor the new parent frame have views,
483 : // then any child views don't need reparenting
484 0 : return NS_OK;
485 : }
486 :
487 : // We found views for one or both of the ancestor frames before we
488 : // found a common ancestor.
489 0 : nsView* oldParentView = aOldParentFrame->GetClosestView();
490 0 : nsView* newParentView = aNewParentFrame->GetClosestView();
491 :
492 : // See if the old parent frame and the new parent frame are in the
493 : // same view sub-hierarchy. If they are then we don't have to do
494 : // anything
495 0 : if (oldParentView != newParentView) {
496 : // They're not so we need to reparent any child views
497 0 : aChildFrame->ReparentFrameViewTo(oldParentView->GetViewManager(),
498 : newParentView,
499 0 : oldParentView);
500 : }
501 :
502 0 : return NS_OK;
503 : }
504 :
505 : nsresult
506 0 : nsContainerFrame::ReparentFrameViewList(const nsFrameList& aChildFrameList,
507 : nsIFrame* aOldParentFrame,
508 : nsIFrame* aNewParentFrame)
509 : {
510 0 : NS_PRECONDITION(aChildFrameList.NotEmpty(), "empty child frame list");
511 0 : NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
512 0 : NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
513 0 : NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
514 :
515 : // See if either the old parent frame or the new parent frame have a view
516 0 : while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
517 : // Walk up both the old parent frame and the new parent frame nodes
518 : // stopping when we either find a common parent or views for one
519 : // or both of the frames.
520 : //
521 : // This works well in the common case where we push/pull and the old parent
522 : // frame and the new parent frame are part of the same flow. They will
523 : // typically be the same distance (height wise) from the
524 0 : aOldParentFrame = aOldParentFrame->GetParent();
525 0 : aNewParentFrame = aNewParentFrame->GetParent();
526 :
527 : // We should never walk all the way to the root frame without finding
528 : // a view
529 0 : NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
530 :
531 : // See if we reached a common ancestor
532 0 : if (aOldParentFrame == aNewParentFrame) {
533 0 : break;
534 : }
535 : }
536 :
537 :
538 : // See if we found a common parent frame
539 0 : if (aOldParentFrame == aNewParentFrame) {
540 : // We found a common parent and there are no views between the old parent
541 : // and the common parent or the new parent frame and the common parent.
542 : // Because neither the old parent frame nor the new parent frame have views,
543 : // then any child views don't need reparenting
544 0 : return NS_OK;
545 : }
546 :
547 : // We found views for one or both of the ancestor frames before we
548 : // found a common ancestor.
549 0 : nsView* oldParentView = aOldParentFrame->GetClosestView();
550 0 : nsView* newParentView = aNewParentFrame->GetClosestView();
551 :
552 : // See if the old parent frame and the new parent frame are in the
553 : // same view sub-hierarchy. If they are then we don't have to do
554 : // anything
555 0 : if (oldParentView != newParentView) {
556 0 : nsViewManager* viewManager = oldParentView->GetViewManager();
557 :
558 : // They're not so we need to reparent any child views
559 0 : for (nsFrameList::Enumerator e(aChildFrameList); !e.AtEnd(); e.Next()) {
560 0 : e.get()->ReparentFrameViewTo(viewManager, newParentView, oldParentView);
561 : }
562 : }
563 :
564 0 : return NS_OK;
565 : }
566 :
567 : static nsIWidget*
568 50 : GetPresContextContainerWidget(nsPresContext* aPresContext)
569 : {
570 100 : nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
571 100 : nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
572 50 : if (!baseWindow)
573 0 : return nullptr;
574 :
575 100 : nsCOMPtr<nsIWidget> mainWidget;
576 50 : baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
577 50 : return mainWidget;
578 : }
579 :
580 : static bool
581 50 : IsTopLevelWidget(nsIWidget* aWidget)
582 : {
583 50 : nsWindowType windowType = aWidget->WindowType();
584 6 : return windowType == eWindowType_toplevel ||
585 6 : windowType == eWindowType_dialog ||
586 56 : windowType == eWindowType_popup ||
587 50 : windowType == eWindowType_sheet;
588 : }
589 :
590 : void
591 114 : nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
592 : nsIFrame* aFrame,
593 : nsView* aView,
594 : gfxContext* aRC,
595 : uint32_t aFlags)
596 : {
597 : #ifdef MOZ_XUL
598 114 : if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget())
599 158 : return;
600 :
601 70 : nsCOMPtr<nsIWidget> windowWidget = GetPresContextContainerWidget(aPresContext);
602 50 : if (!windowWidget || !IsTopLevelWidget(windowWidget))
603 6 : return;
604 :
605 44 : nsViewManager* vm = aView->GetViewManager();
606 44 : nsView* rootView = vm->GetRootView();
607 :
608 44 : if (aView != rootView)
609 0 : return;
610 :
611 44 : Element* rootElement = aPresContext->Document()->GetRootElement();
612 44 : if (!rootElement || !rootElement->IsXULElement()) {
613 : // Scrollframes use native widgets which don't work well with
614 : // translucent windows, at least in Windows XP. So if the document
615 : // has a root scrollrame it's useless to try to make it transparent,
616 : // we'll just get something broken.
617 : // nsCSSFrameConstructor::ConstructRootFrame constructs root
618 : // scrollframes whenever the root element is not a XUL element, so
619 : // we test for that here. We can't just call
620 : // presShell->GetRootScrollFrame() since that might not have
621 : // been constructed yet.
622 : // We can change this to allow translucent toplevel HTML documents
623 : // (e.g. to do something like Dashboard widgets), once we
624 : // have broad support for translucent scrolled documents, but be
625 : // careful because apparently some Firefox extensions expect
626 : // openDialog("something.html") to produce an opaque window
627 : // even if the HTML doesn't have a background-color set.
628 0 : return;
629 : }
630 :
631 44 : nsIFrame *rootFrame = aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
632 44 : if (!rootFrame)
633 1 : return;
634 :
635 43 : if (aFlags & SET_ASYNC) {
636 23 : aView->SetNeedsWindowPropertiesSync();
637 23 : return;
638 : }
639 :
640 40 : RefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
641 40 : AutoWeakFrame weak(rootFrame);
642 :
643 20 : nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(aFrame, rootFrame);
644 20 : int32_t shadow = rootFrame->StyleUIReset()->mWindowShadow;
645 40 : nsCOMPtr<nsIWidget> viewWidget = aView->GetWidget();
646 20 : viewWidget->SetTransparencyMode(mode);
647 20 : windowWidget->SetWindowShadowStyle(shadow);
648 :
649 20 : if (!aRC)
650 0 : return;
651 :
652 20 : if (!weak.IsAlive()) {
653 0 : return;
654 : }
655 :
656 40 : nsBoxLayoutState aState(aPresContext, aRC);
657 20 : nsSize minSize = rootFrame->GetXULMinSize(aState);
658 20 : nsSize maxSize = rootFrame->GetXULMaxSize(aState);
659 :
660 20 : SetSizeConstraints(aPresContext, windowWidget, minSize, maxSize);
661 : #endif
662 : }
663 :
664 20 : void nsContainerFrame::SetSizeConstraints(nsPresContext* aPresContext,
665 : nsIWidget* aWidget,
666 : const nsSize& aMinSize,
667 : const nsSize& aMaxSize)
668 : {
669 20 : LayoutDeviceIntSize devMinSize(aPresContext->AppUnitsToDevPixels(aMinSize.width),
670 40 : aPresContext->AppUnitsToDevPixels(aMinSize.height));
671 20 : LayoutDeviceIntSize devMaxSize(aMaxSize.width == NS_INTRINSICSIZE ? NS_MAXSIZE :
672 0 : aPresContext->AppUnitsToDevPixels(aMaxSize.width),
673 20 : aMaxSize.height == NS_INTRINSICSIZE ? NS_MAXSIZE :
674 40 : aPresContext->AppUnitsToDevPixels(aMaxSize.height));
675 :
676 : // MinSize has a priority over MaxSize
677 20 : if (devMinSize.width > devMaxSize.width)
678 0 : devMaxSize.width = devMinSize.width;
679 20 : if (devMinSize.height > devMaxSize.height)
680 0 : devMaxSize.height = devMinSize.height;
681 :
682 20 : widget::SizeConstraints constraints(devMinSize, devMaxSize);
683 :
684 : // The sizes are in inner window sizes, so convert them into outer window sizes.
685 : // Use a size of (200, 200) as only the difference between the inner and outer
686 : // size is needed.
687 : LayoutDeviceIntSize windowSize =
688 20 : aWidget->ClientToWindowSize(LayoutDeviceIntSize(200, 200));
689 20 : if (constraints.mMinSize.width)
690 20 : constraints.mMinSize.width += windowSize.width - 200;
691 20 : if (constraints.mMinSize.height)
692 20 : constraints.mMinSize.height += windowSize.height - 200;
693 20 : if (constraints.mMaxSize.width != NS_MAXSIZE)
694 0 : constraints.mMaxSize.width += windowSize.width - 200;
695 20 : if (constraints.mMaxSize.height != NS_MAXSIZE)
696 0 : constraints.mMaxSize.height += windowSize.height - 200;
697 :
698 20 : aWidget->SetSizeConstraints(constraints);
699 20 : }
700 :
701 : void
702 205 : nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
703 : nsIFrame* aFrame,
704 : nsView* aView,
705 : const nsRect& aVisualOverflowArea,
706 : uint32_t aFlags)
707 : {
708 205 : if (!aView) {
709 129 : return;
710 : }
711 :
712 : // Make sure the view is sized and positioned correctly
713 76 : if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
714 72 : PositionFrameView(aFrame);
715 : }
716 :
717 76 : if (0 == (aFlags & NS_FRAME_NO_SIZE_VIEW)) {
718 76 : nsViewManager* vm = aView->GetViewManager();
719 :
720 76 : vm->ResizeView(aView, aVisualOverflowArea, true);
721 : }
722 : }
723 :
724 0 : static nscoord GetCoord(const nsStyleCoord& aCoord, nscoord aIfNotCoord)
725 : {
726 0 : if (aCoord.ConvertsToLength()) {
727 0 : return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
728 : }
729 0 : return aIfNotCoord;
730 : }
731 :
732 : void
733 0 : nsContainerFrame::DoInlineIntrinsicISize(gfxContext *aRenderingContext,
734 : InlineIntrinsicISizeData *aData,
735 : nsLayoutUtils::IntrinsicISizeType aType)
736 : {
737 0 : if (GetPrevInFlow())
738 0 : return; // Already added.
739 :
740 0 : NS_PRECONDITION(aType == nsLayoutUtils::MIN_ISIZE ||
741 : aType == nsLayoutUtils::PREF_ISIZE, "bad type");
742 :
743 0 : WritingMode wm = GetWritingMode();
744 : mozilla::Side startSide =
745 0 : wm.PhysicalSideForInlineAxis(eLogicalEdgeStart);
746 : mozilla::Side endSide =
747 0 : wm.PhysicalSideForInlineAxis(eLogicalEdgeEnd);
748 :
749 0 : const nsStylePadding *stylePadding = StylePadding();
750 0 : const nsStyleBorder *styleBorder = StyleBorder();
751 0 : const nsStyleMargin *styleMargin = StyleMargin();
752 :
753 : // This goes at the beginning no matter how things are broken and how
754 : // messy the bidi situations are, since per CSS2.1 section 8.6
755 : // (implemented in bug 328168), the startSide border is always on the
756 : // first line.
757 : // This frame is a first-in-flow, but it might have a previous bidi
758 : // continuation, in which case that continuation should handle the startSide
759 : // border.
760 : // For box-decoration-break:clone we setup clonePBM = startPBM + endPBM and
761 : // add that to each line. For box-decoration-break:slice clonePBM is zero.
762 0 : nscoord clonePBM = 0; // PBM = PaddingBorderMargin
763 : const bool sliceBreak =
764 0 : styleBorder->mBoxDecorationBreak == StyleBoxDecorationBreak::Slice;
765 0 : if (!GetPrevContinuation()) {
766 : nscoord startPBM =
767 : // clamp negative calc() to 0
768 0 : std::max(GetCoord(stylePadding->mPadding.Get(startSide), 0), 0) +
769 0 : styleBorder->GetComputedBorderWidth(startSide) +
770 0 : GetCoord(styleMargin->mMargin.Get(startSide), 0);
771 0 : if (MOZ_LIKELY(sliceBreak)) {
772 0 : aData->mCurrentLine += startPBM;
773 : } else {
774 0 : clonePBM = startPBM;
775 : }
776 : }
777 :
778 : nscoord endPBM =
779 : // clamp negative calc() to 0
780 0 : std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
781 0 : styleBorder->GetComputedBorderWidth(endSide) +
782 0 : GetCoord(styleMargin->mMargin.Get(endSide), 0);
783 0 : if (MOZ_UNLIKELY(!sliceBreak)) {
784 0 : clonePBM += endPBM;
785 : }
786 :
787 0 : const nsLineList_iterator* savedLine = aData->mLine;
788 0 : nsIFrame* const savedLineContainer = aData->LineContainer();
789 :
790 : nsContainerFrame *lastInFlow;
791 0 : for (nsContainerFrame *nif = this; nif;
792 0 : nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) {
793 0 : if (aData->mCurrentLine == 0) {
794 0 : aData->mCurrentLine = clonePBM;
795 : }
796 0 : for (nsIFrame* kid : nif->mFrames) {
797 0 : if (aType == nsLayoutUtils::MIN_ISIZE)
798 : kid->AddInlineMinISize(aRenderingContext,
799 0 : static_cast<InlineMinISizeData*>(aData));
800 : else
801 : kid->AddInlinePrefISize(aRenderingContext,
802 0 : static_cast<InlinePrefISizeData*>(aData));
803 : }
804 :
805 : // After we advance to our next-in-flow, the stored line and line container
806 : // may no longer be correct. Just forget them.
807 0 : aData->mLine = nullptr;
808 0 : aData->SetLineContainer(nullptr);
809 :
810 0 : lastInFlow = nif;
811 : }
812 :
813 0 : aData->mLine = savedLine;
814 0 : aData->SetLineContainer(savedLineContainer);
815 :
816 : // This goes at the end no matter how things are broken and how
817 : // messy the bidi situations are, since per CSS2.1 section 8.6
818 : // (implemented in bug 328168), the endSide border is always on the
819 : // last line.
820 : // We reached the last-in-flow, but it might have a next bidi
821 : // continuation, in which case that continuation should handle
822 : // the endSide border.
823 0 : if (MOZ_LIKELY(!lastInFlow->GetNextContinuation() && sliceBreak)) {
824 0 : aData->mCurrentLine += endPBM;
825 : }
826 : }
827 :
828 : /* virtual */
829 : LogicalSize
830 341 : nsContainerFrame::ComputeAutoSize(gfxContext* aRenderingContext,
831 : WritingMode aWM,
832 : const LogicalSize& aCBSize,
833 : nscoord aAvailableISize,
834 : const LogicalSize& aMargin,
835 : const LogicalSize& aBorder,
836 : const LogicalSize& aPadding,
837 : ComputeSizeFlags aFlags)
838 : {
839 341 : LogicalSize result(aWM, 0xdeadbeef, NS_UNCONSTRAINEDSIZE);
840 682 : nscoord availBased = aAvailableISize - aMargin.ISize(aWM) -
841 682 : aBorder.ISize(aWM) - aPadding.ISize(aWM);
842 : // replaced elements always shrink-wrap
843 341 : if ((aFlags & ComputeSizeFlags::eShrinkWrap) || IsFrameOfType(eReplaced)) {
844 : // don't bother setting it if the result won't be used
845 123 : if (StylePosition()->ISize(aWM).GetUnit() == eStyleUnit_Auto) {
846 119 : result.ISize(aWM) = ShrinkWidthToFit(aRenderingContext, availBased, aFlags);
847 : }
848 : } else {
849 218 : result.ISize(aWM) = availBased;
850 : }
851 :
852 341 : if (IsTableCaption()) {
853 : // If we're a container for font size inflation, then shrink
854 : // wrapping inside of us should not apply font size inflation.
855 0 : AutoMaybeDisableFontInflation an(this);
856 :
857 0 : WritingMode tableWM = GetParent()->GetWritingMode();
858 0 : uint8_t captionSide = StyleTableBorder()->mCaptionSide;
859 :
860 0 : if (aWM.IsOrthogonalTo(tableWM)) {
861 0 : if (captionSide == NS_STYLE_CAPTION_SIDE_TOP ||
862 0 : captionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE ||
863 0 : captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM ||
864 : captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE) {
865 : // For an orthogonal caption on a block-dir side of the table,
866 : // shrink-wrap to min-isize.
867 0 : result.ISize(aWM) = GetMinISize(aRenderingContext);
868 : } else {
869 : // An orthogonal caption on an inline-dir side of the table
870 : // is constrained to the containing block.
871 0 : nscoord pref = GetPrefISize(aRenderingContext);
872 0 : if (pref > aCBSize.ISize(aWM)) {
873 0 : pref = aCBSize.ISize(aWM);
874 : }
875 0 : if (pref < result.ISize(aWM)) {
876 0 : result.ISize(aWM) = pref;
877 : }
878 : }
879 : } else {
880 0 : if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
881 : captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) {
882 0 : result.ISize(aWM) = GetMinISize(aRenderingContext);
883 0 : } else if (captionSide == NS_STYLE_CAPTION_SIDE_TOP ||
884 : captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) {
885 : // The outer frame constrains our available isize to the isize of
886 : // the table. Grow if our min-isize is bigger than that, but not
887 : // larger than the containing block isize. (It would really be nice
888 : // to transmit that information another way, so we could grow up to
889 : // the table's available isize, but that's harder.)
890 0 : nscoord min = GetMinISize(aRenderingContext);
891 0 : if (min > aCBSize.ISize(aWM)) {
892 0 : min = aCBSize.ISize(aWM);
893 : }
894 0 : if (min > result.ISize(aWM)) {
895 0 : result.ISize(aWM) = min;
896 : }
897 : }
898 : }
899 : }
900 341 : return result;
901 : }
902 :
903 : void
904 172 : nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
905 : nsPresContext* aPresContext,
906 : ReflowOutput& aDesiredSize,
907 : const ReflowInput& aReflowInput,
908 : const WritingMode& aWM,
909 : const LogicalPoint& aPos,
910 : const nsSize& aContainerSize,
911 : uint32_t aFlags,
912 : nsReflowStatus& aStatus,
913 : nsOverflowContinuationTracker* aTracker)
914 : {
915 172 : NS_PRECONDITION(aReflowInput.mFrame == aKidFrame, "bad reflow state");
916 172 : if (aWM.IsVerticalRL() || (!aWM.IsVertical() && !aWM.IsBidiLTR())) {
917 0 : NS_ASSERTION(aContainerSize.width != NS_UNCONSTRAINEDSIZE,
918 : "ReflowChild with unconstrained container width!");
919 : }
920 172 : MOZ_ASSERT(aDesiredSize.VisualOverflow() == nsRect(0,0,0,0) &&
921 : aDesiredSize.ScrollableOverflow() == nsRect(0,0,0,0),
922 : "please reset the overflow areas before calling ReflowChild");
923 :
924 : // Position the child frame and its view if requested.
925 172 : if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
926 45 : aKidFrame->SetPosition(aWM, aPos, aContainerSize);
927 : }
928 :
929 172 : if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
930 45 : PositionFrameView(aKidFrame);
931 45 : PositionChildViews(aKidFrame);
932 : }
933 :
934 : // Reflow the child frame
935 172 : aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
936 :
937 : // If the child frame is complete, delete any next-in-flows,
938 : // but only if the NO_DELETE_NEXT_IN_FLOW flag isn't set.
939 516 : if (!aStatus.IsInlineBreakBefore() &&
940 344 : aStatus.IsFullyComplete() &&
941 172 : !(aFlags & NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD)) {
942 172 : nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
943 172 : if (kidNextInFlow) {
944 : // Remove all of the childs next-in-flows. Make sure that we ask
945 : // the right parent to do the removal (it's possible that the
946 : // parent is not this because we are executing pullup code)
947 0 : nsOverflowContinuationTracker::AutoFinish fini(aTracker, aKidFrame);
948 0 : kidNextInFlow->GetParent()->DeleteNextInFlowChild(kidNextInFlow, true);
949 : }
950 : }
951 172 : }
952 :
953 : //XXX temporary: hold on to a copy of the old physical version of
954 : // ReflowChild so that we can convert callers incrementally.
955 : void
956 105 : nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
957 : nsPresContext* aPresContext,
958 : ReflowOutput& aDesiredSize,
959 : const ReflowInput& aReflowInput,
960 : nscoord aX,
961 : nscoord aY,
962 : uint32_t aFlags,
963 : nsReflowStatus& aStatus,
964 : nsOverflowContinuationTracker* aTracker)
965 : {
966 105 : NS_PRECONDITION(aReflowInput.mFrame == aKidFrame, "bad reflow state");
967 :
968 : // Position the child frame and its view if requested.
969 105 : if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
970 101 : aKidFrame->SetPosition(nsPoint(aX, aY));
971 : }
972 :
973 105 : if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
974 101 : PositionFrameView(aKidFrame);
975 101 : PositionChildViews(aKidFrame);
976 : }
977 :
978 : // Reflow the child frame
979 105 : aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
980 :
981 : // If the child frame is complete, delete any next-in-flows,
982 : // but only if the NO_DELETE_NEXT_IN_FLOW flag isn't set.
983 210 : if (aStatus.IsFullyComplete() &&
984 105 : !(aFlags & NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD)) {
985 105 : nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
986 105 : if (kidNextInFlow) {
987 : // Remove all of the childs next-in-flows. Make sure that we ask
988 : // the right parent to do the removal (it's possible that the
989 : // parent is not this because we are executing pullup code)
990 0 : nsOverflowContinuationTracker::AutoFinish fini(aTracker, aKidFrame);
991 0 : kidNextInFlow->GetParent()->DeleteNextInFlowChild(kidNextInFlow, true);
992 : }
993 : }
994 105 : }
995 :
996 :
997 : /**
998 : * Position the views of |aFrame|'s descendants. A container frame
999 : * should call this method if it moves a frame after |Reflow|.
1000 : */
1001 : void
1002 2831 : nsContainerFrame::PositionChildViews(nsIFrame* aFrame)
1003 : {
1004 2831 : if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
1005 1718 : return;
1006 : }
1007 :
1008 : // Recursively walk aFrame's child frames.
1009 : // Process the additional child lists, but skip the popup list as the
1010 : // view for popups is managed by the parent. Currently only nsMenuFrame
1011 : // and nsPopupSetFrame have a popupList and during layout will adjust the
1012 : // view manually to position the popup.
1013 2226 : ChildListIterator lists(aFrame);
1014 3991 : for (; !lists.IsDone(); lists.Next()) {
1015 1439 : if (lists.CurrentID() == kPopupList) {
1016 348 : continue;
1017 : }
1018 1091 : nsFrameList::Enumerator childFrames(lists.CurrentList());
1019 5367 : for (; !childFrames.AtEnd(); childFrames.Next()) {
1020 : // Position the frame's view (if it has one) otherwise recursively
1021 : // process its children
1022 2138 : nsIFrame* childFrame = childFrames.get();
1023 2138 : if (childFrame->HasView()) {
1024 25 : PositionFrameView(childFrame);
1025 : } else {
1026 2113 : PositionChildViews(childFrame);
1027 : }
1028 : }
1029 : }
1030 : }
1031 :
1032 : /**
1033 : * The second half of frame reflow. Does the following:
1034 : * - sets the frame's bounds
1035 : * - sizes and positions (if requested) the frame's view. If the frame's final
1036 : * position differs from the current position and the frame itself does not
1037 : * have a view, then any child frames with views are positioned so they stay
1038 : * in sync
1039 : * - sets the view's visibility, opacity, content transparency, and clip
1040 : * - invoked the DidReflow() function
1041 : *
1042 : * Flags:
1043 : * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
1044 : * case. Also implies NS_FRAME_NO_MOVE_VIEW
1045 : * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
1046 : * don't want to automatically sync the frame and view
1047 : * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
1048 : */
1049 : void
1050 182 : nsContainerFrame::FinishReflowChild(nsIFrame* aKidFrame,
1051 : nsPresContext* aPresContext,
1052 : const ReflowOutput& aDesiredSize,
1053 : const ReflowInput* aReflowInput,
1054 : const WritingMode& aWM,
1055 : const LogicalPoint& aPos,
1056 : const nsSize& aContainerSize,
1057 : uint32_t aFlags)
1058 : {
1059 182 : if (aWM.IsVerticalRL() || (!aWM.IsVertical() && !aWM.IsBidiLTR())) {
1060 0 : NS_ASSERTION(aContainerSize.width != NS_UNCONSTRAINEDSIZE,
1061 : "FinishReflowChild with unconstrained container width!");
1062 : }
1063 :
1064 182 : nsPoint curOrigin = aKidFrame->GetPosition();
1065 182 : WritingMode outerWM = aDesiredSize.GetWritingMode();
1066 364 : LogicalSize convertedSize = aDesiredSize.Size(outerWM).ConvertTo(aWM,
1067 182 : outerWM);
1068 :
1069 182 : if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
1070 110 : aKidFrame->SetRect(aWM, LogicalRect(aWM, aPos, convertedSize),
1071 55 : aContainerSize);
1072 : } else {
1073 127 : aKidFrame->SetSize(aWM, convertedSize);
1074 : }
1075 :
1076 182 : if (aKidFrame->HasView()) {
1077 0 : nsView* view = aKidFrame->GetView();
1078 : // Make sure the frame's view is properly sized and positioned and has
1079 : // things like opacity correct
1080 0 : SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
1081 0 : aDesiredSize.VisualOverflow(), aFlags);
1082 : }
1083 :
1084 182 : nsPoint newOrigin = aKidFrame->GetPosition();
1085 182 : if (!(aFlags & NS_FRAME_NO_MOVE_VIEW) && curOrigin != newOrigin) {
1086 2 : if (!aKidFrame->HasView()) {
1087 : // If the frame has moved, then we need to make sure any child views are
1088 : // correctly positioned
1089 2 : PositionChildViews(aKidFrame);
1090 : }
1091 : }
1092 :
1093 182 : aKidFrame->DidReflow(aPresContext, aReflowInput, nsDidReflowStatus::FINISHED);
1094 182 : }
1095 :
1096 : //XXX temporary: hold on to a copy of the old physical version of
1097 : // FinishReflowChild so that we can convert callers incrementally.
1098 : void
1099 231 : nsContainerFrame::FinishReflowChild(nsIFrame* aKidFrame,
1100 : nsPresContext* aPresContext,
1101 : const ReflowOutput& aDesiredSize,
1102 : const ReflowInput* aReflowInput,
1103 : nscoord aX,
1104 : nscoord aY,
1105 : uint32_t aFlags)
1106 : {
1107 231 : nsPoint curOrigin = aKidFrame->GetPosition();
1108 :
1109 231 : if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
1110 101 : aKidFrame->SetRect(nsRect(aX, aY, aDesiredSize.Width(), aDesiredSize.Height()));
1111 : } else {
1112 130 : aKidFrame->SetSize(nsSize(aDesiredSize.Width(), aDesiredSize.Height()));
1113 : }
1114 :
1115 231 : if (aKidFrame->HasView()) {
1116 4 : nsView* view = aKidFrame->GetView();
1117 : // Make sure the frame's view is properly sized and positioned and has
1118 : // things like opacity correct
1119 4 : SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
1120 4 : aDesiredSize.VisualOverflow(), aFlags);
1121 : }
1122 :
1123 332 : if (!(aFlags & NS_FRAME_NO_MOVE_VIEW) &&
1124 202 : (curOrigin.x != aX || curOrigin.y != aY)) {
1125 0 : if (!aKidFrame->HasView()) {
1126 : // If the frame has moved, then we need to make sure any child views are
1127 : // correctly positioned
1128 0 : PositionChildViews(aKidFrame);
1129 : }
1130 : }
1131 :
1132 231 : aKidFrame->DidReflow(aPresContext, aReflowInput, nsDidReflowStatus::FINISHED);
1133 231 : }
1134 :
1135 : void
1136 0 : nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPresContext,
1137 : const ReflowInput& aReflowInput,
1138 : nsOverflowAreas& aOverflowRects,
1139 : uint32_t aFlags,
1140 : nsReflowStatus& aStatus,
1141 : ChildFrameMerger aMergeFunc)
1142 : {
1143 0 : NS_PRECONDITION(aPresContext, "null pointer");
1144 :
1145 0 : nsFrameList* overflowContainers = DrainExcessOverflowContainersList(aMergeFunc);
1146 0 : if (!overflowContainers) {
1147 0 : return; // nothing to reflow
1148 : }
1149 :
1150 0 : nsOverflowContinuationTracker tracker(this, false, false);
1151 0 : bool shouldReflowAllKids = aReflowInput.ShouldReflowAllKids();
1152 :
1153 0 : for (nsIFrame* frame : *overflowContainers) {
1154 0 : if (frame->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
1155 : // frame's prevInFlow has moved, skip reflowing this frame;
1156 : // it will get reflowed once it's been placed
1157 0 : continue;
1158 : }
1159 : // If the available vertical height has changed, we need to reflow
1160 : // even if the frame isn't dirty.
1161 0 : if (shouldReflowAllKids || NS_SUBTREE_DIRTY(frame)) {
1162 : // Get prev-in-flow
1163 0 : nsIFrame* prevInFlow = frame->GetPrevInFlow();
1164 0 : NS_ASSERTION(prevInFlow,
1165 : "overflow container frame must have a prev-in-flow");
1166 0 : NS_ASSERTION(frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
1167 : "overflow container frame must have overflow container bit set");
1168 0 : WritingMode wm = frame->GetWritingMode();
1169 0 : nsSize containerSize = aReflowInput.AvailableSize(wm).GetPhysicalSize(wm);
1170 0 : LogicalRect prevRect = prevInFlow->GetLogicalRect(wm, containerSize);
1171 :
1172 : // Initialize reflow params
1173 0 : LogicalSize availSpace(wm, prevRect.ISize(wm),
1174 0 : aReflowInput.AvailableSize(wm).BSize(wm));
1175 0 : ReflowOutput desiredSize(aReflowInput);
1176 : ReflowInput frameState(aPresContext, aReflowInput,
1177 0 : frame, availSpace);
1178 0 : nsReflowStatus frameStatus;
1179 :
1180 : // Reflow
1181 0 : LogicalPoint pos(wm, prevRect.IStart(wm), 0);
1182 : ReflowChild(frame, aPresContext, desiredSize, frameState,
1183 0 : wm, pos, containerSize, aFlags, frameStatus, &tracker);
1184 : //XXXfr Do we need to override any shrinkwrap effects here?
1185 : // e.g. desiredSize.Width() = prevRect.width;
1186 : FinishReflowChild(frame, aPresContext, desiredSize, &frameState,
1187 0 : wm, pos, containerSize, aFlags);
1188 :
1189 : // Handle continuations
1190 0 : if (!frameStatus.IsFullyComplete()) {
1191 0 : if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
1192 : // Abspos frames can't cause their parent to be incomplete,
1193 : // only overflow incomplete.
1194 0 : frameStatus.SetOverflowIncomplete();
1195 : }
1196 : else {
1197 0 : NS_ASSERTION(frameStatus.IsComplete(),
1198 : "overflow container frames can't be incomplete, only overflow-incomplete");
1199 : }
1200 :
1201 : // Acquire a next-in-flow, creating it if necessary
1202 0 : nsIFrame* nif = frame->GetNextInFlow();
1203 0 : if (!nif) {
1204 0 : NS_ASSERTION(frameStatus.NextInFlowNeedsReflow(),
1205 : "Someone forgot a NextInFlowNeedsReflow flag");
1206 : nif = aPresContext->PresShell()->FrameConstructor()->
1207 0 : CreateContinuingFrame(aPresContext, frame, this);
1208 : }
1209 0 : else if (!(nif->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1210 : // used to be a normal next-in-flow; steal it from the child list
1211 0 : nsresult rv = nif->GetParent()->StealFrame(nif);
1212 0 : if (NS_FAILED(rv)) {
1213 0 : return;
1214 : }
1215 : }
1216 :
1217 0 : tracker.Insert(nif, frameStatus);
1218 : }
1219 0 : aStatus.MergeCompletionStatusFrom(frameStatus);
1220 : // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
1221 : // but we have some unsplittable frames that, when taller than
1222 : // availableHeight will push zero-height content into a next-in-flow.
1223 : }
1224 : else {
1225 0 : tracker.Skip(frame, aStatus);
1226 0 : if (aReflowInput.mFloatManager) {
1227 0 : nsBlockFrame::RecoverFloatsFor(frame, *aReflowInput.mFloatManager,
1228 : aReflowInput.GetWritingMode(),
1229 0 : aReflowInput.ComputedPhysicalSize());
1230 : }
1231 : }
1232 0 : ConsiderChildOverflow(aOverflowRects, frame);
1233 : }
1234 : }
1235 :
1236 : void
1237 0 : nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
1238 : const nsRect& aDirtyRect,
1239 : const nsDisplayListSet& aLists)
1240 : {
1241 0 : nsFrameList* overflowconts = GetPropTableFrames(OverflowContainersProperty());
1242 0 : if (overflowconts) {
1243 0 : for (nsIFrame* frame : *overflowconts) {
1244 0 : BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists);
1245 : }
1246 : }
1247 0 : }
1248 :
1249 : static bool
1250 0 : TryRemoveFrame(nsIFrame* aFrame,
1251 : nsContainerFrame::FrameListPropertyDescriptor aProp,
1252 : nsIFrame* aChildToRemove)
1253 : {
1254 0 : nsFrameList* list = aFrame->GetProperty(aProp);
1255 0 : if (list && list->StartRemoveFrame(aChildToRemove)) {
1256 : // aChildToRemove *may* have been removed from this list.
1257 0 : if (list->IsEmpty()) {
1258 0 : aFrame->RemoveProperty(aProp);
1259 0 : list->Delete(aFrame->PresContext()->PresShell());
1260 : }
1261 0 : return true;
1262 : }
1263 0 : return false;
1264 : }
1265 :
1266 : bool
1267 0 : nsContainerFrame::MaybeStealOverflowContainerFrame(nsIFrame* aChild)
1268 : {
1269 0 : bool removed = false;
1270 0 : if (MOZ_UNLIKELY(aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1271 : // Try removing from the overflow container list.
1272 0 : removed = ::TryRemoveFrame(this, OverflowContainersProperty(),
1273 0 : aChild);
1274 0 : if (!removed) {
1275 : // It might be in the excess overflow container list.
1276 0 : removed = ::TryRemoveFrame(this,
1277 : ExcessOverflowContainersProperty(),
1278 0 : aChild);
1279 : }
1280 : }
1281 0 : return removed;
1282 : }
1283 :
1284 : nsresult
1285 0 : nsContainerFrame::StealFrame(nsIFrame* aChild)
1286 : {
1287 : #ifdef DEBUG
1288 0 : if (!mFrames.ContainsFrame(aChild)) {
1289 0 : nsFrameList* list = GetOverflowFrames();
1290 0 : if (!list || !list->ContainsFrame(aChild)) {
1291 0 : list = GetProperty(OverflowContainersProperty());
1292 0 : if (!list || !list->ContainsFrame(aChild)) {
1293 0 : list = GetProperty(ExcessOverflowContainersProperty());
1294 0 : MOZ_ASSERT(list && list->ContainsFrame(aChild), "aChild isn't our child"
1295 : " or on a frame list not supported by StealFrame");
1296 : }
1297 : }
1298 : }
1299 : #endif
1300 :
1301 0 : bool removed = MaybeStealOverflowContainerFrame(aChild);
1302 0 : if (!removed) {
1303 : // NOTE nsColumnSetFrame and nsCanvasFrame have their overflow containers
1304 : // on the normal lists so we might get here also if the frame bit
1305 : // NS_FRAME_IS_OVERFLOW_CONTAINER is set.
1306 0 : removed = mFrames.StartRemoveFrame(aChild);
1307 0 : if (!removed) {
1308 : // We didn't find the child in our principal child list.
1309 : // Maybe it's on the overflow list?
1310 0 : nsFrameList* frameList = GetOverflowFrames();
1311 0 : if (frameList) {
1312 0 : removed = frameList->ContinueRemoveFrame(aChild);
1313 0 : if (frameList->IsEmpty()) {
1314 0 : DestroyOverflowList();
1315 : }
1316 : }
1317 : }
1318 : }
1319 :
1320 0 : NS_POSTCONDITION(removed, "StealFrame: can't find aChild");
1321 0 : return removed ? NS_OK : NS_ERROR_UNEXPECTED;
1322 : }
1323 :
1324 : nsFrameList
1325 0 : nsContainerFrame::StealFramesAfter(nsIFrame* aChild)
1326 : {
1327 0 : NS_ASSERTION(!aChild ||
1328 : !(aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER),
1329 : "StealFramesAfter doesn't handle overflow containers");
1330 0 : NS_ASSERTION(!IsBlockFrame(), "unexpected call");
1331 :
1332 0 : if (!aChild) {
1333 0 : nsFrameList copy(mFrames);
1334 0 : mFrames.Clear();
1335 0 : return copy;
1336 : }
1337 :
1338 0 : for (nsFrameList::FrameLinkEnumerator iter(mFrames); !iter.AtEnd();
1339 0 : iter.Next()) {
1340 0 : if (iter.PrevFrame() == aChild) {
1341 0 : return mFrames.ExtractTail(iter);
1342 : }
1343 : }
1344 :
1345 : // We didn't find the child in the principal child list.
1346 : // Maybe it's on the overflow list?
1347 0 : nsFrameList* overflowFrames = GetOverflowFrames();
1348 0 : if (overflowFrames) {
1349 0 : for (nsFrameList::FrameLinkEnumerator iter(*overflowFrames); !iter.AtEnd();
1350 0 : iter.Next()) {
1351 0 : if (iter.PrevFrame() == aChild) {
1352 0 : return overflowFrames->ExtractTail(iter);
1353 : }
1354 : }
1355 : }
1356 :
1357 0 : NS_ERROR("StealFramesAfter: can't find aChild");
1358 0 : return nsFrameList::EmptyList();
1359 : }
1360 :
1361 : /*
1362 : * Create a next-in-flow for aFrame. Will return the newly created
1363 : * frame <b>if and only if</b> a new frame is created; otherwise
1364 : * nullptr is returned.
1365 : */
1366 : nsIFrame*
1367 0 : nsContainerFrame::CreateNextInFlow(nsIFrame* aFrame)
1368 : {
1369 0 : NS_PRECONDITION(!IsBlockFrame(),
1370 : "you should have called nsBlockFrame::CreateContinuationFor instead");
1371 0 : NS_PRECONDITION(mFrames.ContainsFrame(aFrame), "expected an in-flow child frame");
1372 :
1373 0 : nsPresContext* pc = PresContext();
1374 0 : nsIFrame* nextInFlow = aFrame->GetNextInFlow();
1375 0 : if (nullptr == nextInFlow) {
1376 : // Create a continuation frame for the child frame and insert it
1377 : // into our child list.
1378 : nextInFlow = pc->PresShell()->FrameConstructor()->
1379 0 : CreateContinuingFrame(pc, aFrame, this);
1380 0 : mFrames.InsertFrame(nullptr, aFrame, nextInFlow);
1381 :
1382 0 : NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES,
1383 : ("nsContainerFrame::CreateNextInFlow: frame=%p nextInFlow=%p",
1384 : aFrame, nextInFlow));
1385 :
1386 0 : return nextInFlow;
1387 : }
1388 0 : return nullptr;
1389 : }
1390 :
1391 : /**
1392 : * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
1393 : * pointers
1394 : */
1395 : void
1396 0 : nsContainerFrame::DeleteNextInFlowChild(nsIFrame* aNextInFlow,
1397 : bool aDeletingEmptyFrames)
1398 : {
1399 : #ifdef DEBUG
1400 0 : nsIFrame* prevInFlow = aNextInFlow->GetPrevInFlow();
1401 : #endif
1402 0 : NS_PRECONDITION(prevInFlow, "bad prev-in-flow");
1403 :
1404 : // If the next-in-flow has a next-in-flow then delete it, too (and
1405 : // delete it first).
1406 : // Do this in a loop so we don't overflow the stack for frames
1407 : // with very many next-in-flows
1408 0 : nsIFrame* nextNextInFlow = aNextInFlow->GetNextInFlow();
1409 0 : if (nextNextInFlow) {
1410 0 : AutoTArray<nsIFrame*, 8> frames;
1411 0 : for (nsIFrame* f = nextNextInFlow; f; f = f->GetNextInFlow()) {
1412 0 : frames.AppendElement(f);
1413 : }
1414 0 : for (int32_t i = frames.Length() - 1; i >= 0; --i) {
1415 0 : nsIFrame* delFrame = frames.ElementAt(i);
1416 0 : delFrame->GetParent()->
1417 0 : DeleteNextInFlowChild(delFrame, aDeletingEmptyFrames);
1418 : }
1419 : }
1420 :
1421 : // Take the next-in-flow out of the parent's child list
1422 0 : DebugOnly<nsresult> rv = StealFrame(aNextInFlow);
1423 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
1424 :
1425 : #ifdef DEBUG
1426 0 : if (aDeletingEmptyFrames) {
1427 0 : nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow);
1428 : }
1429 : #endif
1430 :
1431 : // Delete the next-in-flow frame and its descendants. This will also
1432 : // remove it from its next-in-flow/prev-in-flow chain.
1433 0 : aNextInFlow->Destroy();
1434 :
1435 0 : NS_POSTCONDITION(!prevInFlow->GetNextInFlow(), "non null next-in-flow");
1436 0 : }
1437 :
1438 : /**
1439 : * Set the frames on the overflow list
1440 : */
1441 : void
1442 0 : nsContainerFrame::SetOverflowFrames(const nsFrameList& aOverflowFrames)
1443 : {
1444 0 : NS_PRECONDITION(aOverflowFrames.NotEmpty(), "Shouldn't be called");
1445 :
1446 0 : nsPresContext* pc = PresContext();
1447 0 : nsFrameList* newList = new (pc->PresShell()) nsFrameList(aOverflowFrames);
1448 :
1449 0 : SetProperty(OverflowProperty(), newList);
1450 0 : }
1451 :
1452 : nsFrameList*
1453 185 : nsContainerFrame::GetPropTableFrames(
1454 : FrameListPropertyDescriptor aProperty) const
1455 : {
1456 185 : return GetProperty(aProperty);
1457 : }
1458 :
1459 : nsFrameList*
1460 0 : nsContainerFrame::RemovePropTableFrames(FrameListPropertyDescriptor aProperty)
1461 : {
1462 0 : return RemoveProperty(aProperty);
1463 : }
1464 :
1465 : void
1466 0 : nsContainerFrame::SetPropTableFrames(nsFrameList* aFrameList,
1467 : FrameListPropertyDescriptor aProperty)
1468 : {
1469 0 : NS_PRECONDITION(aProperty && aFrameList, "null ptr");
1470 0 : NS_PRECONDITION(
1471 : (aProperty != nsContainerFrame::OverflowContainersProperty() &&
1472 : aProperty != nsContainerFrame::ExcessOverflowContainersProperty()) ||
1473 : IsFrameOfType(nsIFrame::eCanContainOverflowContainers),
1474 : "this type of frame can't have overflow containers");
1475 0 : MOZ_ASSERT(!GetPropTableFrames(aProperty));
1476 0 : SetProperty(aProperty, aFrameList);
1477 0 : }
1478 :
1479 : /**
1480 : * Push aFromChild and its next siblings to the next-in-flow. Change the
1481 : * geometric parent of each frame that's pushed. If there is no next-in-flow
1482 : * the frames are placed on the overflow list (and the geometric parent is
1483 : * left unchanged).
1484 : *
1485 : * Updates the next-in-flow's child count. Does <b>not</b> update the
1486 : * pusher's child count.
1487 : *
1488 : * @param aFromChild the first child frame to push. It is disconnected from
1489 : * aPrevSibling
1490 : * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's
1491 : * an error to push a parent's first child frame
1492 : */
1493 : void
1494 0 : nsContainerFrame::PushChildren(nsIFrame* aFromChild,
1495 : nsIFrame* aPrevSibling)
1496 : {
1497 0 : NS_PRECONDITION(aFromChild, "null pointer");
1498 0 : NS_PRECONDITION(aPrevSibling, "pushing first child");
1499 0 : NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
1500 :
1501 : // Disconnect aFromChild from its previous sibling
1502 0 : nsFrameList tail = mFrames.RemoveFramesAfter(aPrevSibling);
1503 :
1504 : nsContainerFrame* nextInFlow =
1505 0 : static_cast<nsContainerFrame*>(GetNextInFlow());
1506 0 : if (nextInFlow) {
1507 : // XXX This is not a very good thing to do. If it gets removed
1508 : // then remove the copy of this routine that doesn't do this from
1509 : // nsInlineFrame.
1510 : // When pushing and pulling frames we need to check for whether any
1511 : // views need to be reparented.
1512 0 : for (nsIFrame* f = aFromChild; f; f = f->GetNextSibling()) {
1513 0 : nsContainerFrame::ReparentFrameView(f, this, nextInFlow);
1514 : }
1515 0 : nextInFlow->mFrames.InsertFrames(nextInFlow, nullptr, tail);
1516 : }
1517 : else {
1518 : // Add the frames to our overflow list
1519 0 : SetOverflowFrames(tail);
1520 : }
1521 0 : }
1522 :
1523 : /**
1524 : * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
1525 : * the receiver's overflow list) to the child list.
1526 : *
1527 : * Updates this frame's child count and content mapping.
1528 : *
1529 : * @return true if any frames were moved and false otherwise
1530 : */
1531 : bool
1532 0 : nsContainerFrame::MoveOverflowToChildList()
1533 : {
1534 0 : bool result = false;
1535 :
1536 : // Check for an overflow list with our prev-in-flow
1537 0 : nsContainerFrame* prevInFlow = (nsContainerFrame*)GetPrevInFlow();
1538 0 : if (nullptr != prevInFlow) {
1539 : AutoFrameListPtr prevOverflowFrames(PresContext(),
1540 0 : prevInFlow->StealOverflowFrames());
1541 0 : if (prevOverflowFrames) {
1542 : // Tables are special; they can have repeated header/footer
1543 : // frames on mFrames at this point.
1544 0 : NS_ASSERTION(mFrames.IsEmpty() || IsTableFrame(), "bad overflow list");
1545 : // When pushing and pulling frames we need to check for whether any
1546 : // views need to be reparented.
1547 0 : nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames,
1548 0 : prevInFlow, this);
1549 0 : mFrames.AppendFrames(this, *prevOverflowFrames);
1550 0 : result = true;
1551 : }
1552 : }
1553 :
1554 : // It's also possible that we have an overflow list for ourselves.
1555 0 : return DrainSelfOverflowList() || result;
1556 : }
1557 :
1558 : bool
1559 32 : nsContainerFrame::DrainSelfOverflowList()
1560 : {
1561 64 : AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
1562 32 : if (overflowFrames) {
1563 0 : mFrames.AppendFrames(nullptr, *overflowFrames);
1564 0 : return true;
1565 : }
1566 32 : return false;
1567 : }
1568 :
1569 : nsFrameList*
1570 0 : nsContainerFrame::DrainExcessOverflowContainersList(ChildFrameMerger aMergeFunc)
1571 : {
1572 : nsFrameList* overflowContainers =
1573 0 : GetPropTableFrames(OverflowContainersProperty());
1574 :
1575 0 : NS_ASSERTION(!(overflowContainers && GetPrevInFlow()
1576 : && static_cast<nsContainerFrame*>(GetPrevInFlow())
1577 : ->GetPropTableFrames(ExcessOverflowContainersProperty())),
1578 : "conflicting overflow containers lists");
1579 :
1580 0 : if (!overflowContainers) {
1581 : // Drain excess from previnflow
1582 0 : nsContainerFrame* prev = (nsContainerFrame*) GetPrevInFlow();
1583 0 : if (prev) {
1584 : nsFrameList* excessFrames =
1585 0 : prev->RemovePropTableFrames(ExcessOverflowContainersProperty());
1586 0 : if (excessFrames) {
1587 0 : excessFrames->ApplySetParent(this);
1588 0 : nsContainerFrame::ReparentFrameViewList(*excessFrames, prev, this);
1589 0 : overflowContainers = excessFrames;
1590 0 : SetPropTableFrames(overflowContainers, OverflowContainersProperty());
1591 : }
1592 : }
1593 : }
1594 :
1595 : // Our own excess overflow containers from a previous reflow can still be
1596 : // present if our next-in-flow hasn't been reflown yet. Move any children
1597 : // from it that don't have a continuation in this frame to the
1598 : // OverflowContainers list.
1599 : nsFrameList* selfExcessOCFrames =
1600 0 : RemovePropTableFrames(ExcessOverflowContainersProperty());
1601 0 : if (selfExcessOCFrames) {
1602 0 : nsFrameList toMove;
1603 0 : auto child = selfExcessOCFrames->FirstChild();
1604 0 : while (child) {
1605 0 : auto next = child->GetNextSibling();
1606 0 : MOZ_ASSERT(child->GetPrevInFlow(),
1607 : "ExcessOverflowContainers frames must be continuations");
1608 0 : if (child->GetPrevInFlow()->GetParent() != this) {
1609 0 : selfExcessOCFrames->RemoveFrame(child);
1610 0 : toMove.AppendFrame(nullptr, child);
1611 : }
1612 0 : child = next;
1613 : }
1614 0 : if (toMove.IsEmpty()) {
1615 0 : SetPropTableFrames(selfExcessOCFrames, ExcessOverflowContainersProperty());
1616 0 : } else if (overflowContainers) {
1617 0 : aMergeFunc(*overflowContainers, toMove, this);
1618 0 : if (selfExcessOCFrames->IsEmpty()) {
1619 0 : selfExcessOCFrames->Delete(PresContext()->PresShell());
1620 : } else {
1621 0 : SetPropTableFrames(selfExcessOCFrames, ExcessOverflowContainersProperty());
1622 : }
1623 : } else {
1624 0 : if (selfExcessOCFrames->IsEmpty()) {
1625 0 : *selfExcessOCFrames = toMove;
1626 0 : overflowContainers = selfExcessOCFrames;
1627 : } else {
1628 0 : SetPropTableFrames(selfExcessOCFrames, ExcessOverflowContainersProperty());
1629 0 : auto shell = PresContext()->PresShell();
1630 0 : overflowContainers = new (shell) nsFrameList(toMove);
1631 : }
1632 0 : SetPropTableFrames(overflowContainers, OverflowContainersProperty());
1633 : }
1634 : }
1635 :
1636 0 : return overflowContainers;
1637 : }
1638 :
1639 : nsIFrame*
1640 0 : nsContainerFrame::GetNextInFlowChild(ContinuationTraversingState& aState,
1641 : bool* aIsInOverflow)
1642 : {
1643 0 : nsContainerFrame*& nextInFlow = aState.mNextInFlow;
1644 0 : while (nextInFlow) {
1645 : // See if there is any frame in the container
1646 0 : nsIFrame* frame = nextInFlow->mFrames.FirstChild();
1647 0 : if (frame) {
1648 0 : if (aIsInOverflow) {
1649 0 : *aIsInOverflow = false;
1650 : }
1651 0 : return frame;
1652 : }
1653 : // No frames in the principal list, try its overflow list
1654 0 : nsFrameList* overflowFrames = nextInFlow->GetOverflowFrames();
1655 0 : if (overflowFrames) {
1656 0 : if (aIsInOverflow) {
1657 0 : *aIsInOverflow = true;
1658 : }
1659 0 : return overflowFrames->FirstChild();
1660 : }
1661 0 : nextInFlow = static_cast<nsContainerFrame*>(nextInFlow->GetNextInFlow());
1662 : }
1663 0 : return nullptr;
1664 : }
1665 :
1666 : nsIFrame*
1667 0 : nsContainerFrame::PullNextInFlowChild(ContinuationTraversingState& aState)
1668 : {
1669 : bool isInOverflow;
1670 0 : nsIFrame* frame = GetNextInFlowChild(aState, &isInOverflow);
1671 0 : if (frame) {
1672 0 : nsContainerFrame* nextInFlow = aState.mNextInFlow;
1673 0 : if (isInOverflow) {
1674 0 : nsFrameList* overflowFrames = nextInFlow->GetOverflowFrames();
1675 0 : overflowFrames->RemoveFirstChild();
1676 0 : if (overflowFrames->IsEmpty()) {
1677 0 : nextInFlow->DestroyOverflowList();
1678 : }
1679 : } else {
1680 0 : nextInFlow->mFrames.RemoveFirstChild();
1681 : }
1682 :
1683 : // Move the frame to the principal frame list of this container
1684 0 : mFrames.AppendFrame(this, frame);
1685 : // AppendFrame has reparented the frame, we need
1686 : // to reparent the frame view then.
1687 0 : nsContainerFrame::ReparentFrameView(frame, nextInFlow, this);
1688 : }
1689 0 : return frame;
1690 : }
1691 :
1692 : bool
1693 0 : nsContainerFrame::ResolvedOrientationIsVertical()
1694 : {
1695 0 : StyleOrient orient = StyleDisplay()->mOrient;
1696 0 : switch (orient) {
1697 : case StyleOrient::Horizontal:
1698 0 : return false;
1699 : case StyleOrient::Vertical:
1700 0 : return true;
1701 : case StyleOrient::Inline:
1702 0 : return GetWritingMode().IsVertical();
1703 : case StyleOrient::Block:
1704 0 : return !GetWritingMode().IsVertical();
1705 : }
1706 0 : NS_NOTREACHED("unexpected -moz-orient value");
1707 0 : return false;
1708 : }
1709 :
1710 : // static
1711 : bool
1712 229 : nsContainerFrame::FrameStartsCounterScope(nsIFrame* aFrame)
1713 : {
1714 229 : nsIContent* content = aFrame->GetContent();
1715 229 : if (!content || !content->IsHTMLElement())
1716 159 : return false;
1717 :
1718 70 : nsIAtom* localName = content->NodeInfo()->NameAtom();
1719 140 : return localName == nsGkAtoms::ol ||
1720 140 : localName == nsGkAtoms::ul ||
1721 210 : localName == nsGkAtoms::dir ||
1722 140 : localName == nsGkAtoms::menu;
1723 : }
1724 :
1725 : bool
1726 229 : nsContainerFrame::RenumberList()
1727 : {
1728 229 : if (!FrameStartsCounterScope(this)) {
1729 : // If this frame doesn't start a counter scope then we don't need
1730 : // to renumber child list items.
1731 229 : return false;
1732 : }
1733 :
1734 0 : MOZ_ASSERT(mContent->IsHTMLElement(),
1735 : "FrameStartsCounterScope should only return true for HTML elements");
1736 :
1737 : // Setup initial list ordinal value
1738 : // XXX Map html's start property to counter-reset style
1739 0 : int32_t ordinal = 1;
1740 : int32_t increment;
1741 0 : if (mContent->IsHTMLElement(nsGkAtoms::ol) &&
1742 0 : mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::reversed)) {
1743 0 : increment = -1;
1744 : } else {
1745 0 : increment = 1;
1746 : }
1747 :
1748 0 : nsGenericHTMLElement* hc = nsGenericHTMLElement::FromContent(mContent);
1749 : // Must be non-null, since FrameStartsCounterScope only returns true
1750 : // for HTML elements.
1751 0 : MOZ_ASSERT(hc, "How is mContent not HTML?");
1752 0 : const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::start);
1753 0 : nsContainerFrame* fif = static_cast<nsContainerFrame*>(FirstInFlow());
1754 0 : if (attr && attr->Type() == nsAttrValue::eInteger) {
1755 0 : ordinal = attr->GetIntegerValue();
1756 0 : } else if (increment < 0) {
1757 : // <ol reversed> case, or some other case with a negative increment: count
1758 : // up the child list
1759 0 : ordinal = 0;
1760 0 : fif->RenumberChildFrames(&ordinal, 0, -increment, true);
1761 : }
1762 :
1763 0 : return fif->RenumberChildFrames(&ordinal, 0, increment, false);
1764 : }
1765 :
1766 : // add in a sanity check for absurdly deep frame trees. See bug 42138
1767 : // can't just use IsFrameTreeTooDeep() because that method has side effects we don't want
1768 : #define MAX_DEPTH_FOR_LIST_RENUMBERING 200 // 200 open displayable tags is pretty unrealistic
1769 :
1770 : bool
1771 0 : nsContainerFrame::RenumberFrameAndDescendants(int32_t* aOrdinal,
1772 : int32_t aDepth,
1773 : int32_t aIncrement,
1774 : bool aForCounting)
1775 : {
1776 0 : NS_PRECONDITION(aOrdinal, "null params are immoral!");
1777 :
1778 : // add in a sanity check for absurdly deep frame trees. See bug 42138
1779 0 : if (MAX_DEPTH_FOR_LIST_RENUMBERING < aDepth) {
1780 0 : return false;
1781 : }
1782 0 : const nsStyleDisplay* display = StyleDisplay();
1783 :
1784 : // drill down through any wrappers to the real frame
1785 0 : nsIFrame* kid = GetContentInsertionFrame();
1786 0 : if (!kid) {
1787 0 : return false;
1788 : }
1789 :
1790 : // Do not renumber list for summary elements.
1791 : HTMLSummaryElement* summary =
1792 0 : HTMLSummaryElement::FromContent(kid->GetContent());
1793 0 : if (summary && summary->IsMainSummary()) {
1794 0 : return false;
1795 : }
1796 :
1797 0 : bool kidRenumberedABullet = false;
1798 :
1799 : // If the frame is a list-item and the frame implements our
1800 : // block frame API then get its bullet and set the list item
1801 : // ordinal.
1802 0 : if (mozilla::StyleDisplay::ListItem == display->mDisplay) {
1803 : // Make certain that the frame is a block frame in case
1804 : // something foreign has crept in.
1805 0 : nsBlockFrame* listItem = nsLayoutUtils::GetAsBlock(kid);
1806 0 : if (listItem) {
1807 0 : nsBulletFrame* bullet = listItem->GetBullet();
1808 0 : if (bullet) {
1809 0 : if (!aForCounting) {
1810 : bool changed;
1811 0 : *aOrdinal = bullet->SetListItemOrdinal(*aOrdinal, &changed, aIncrement);
1812 0 : if (changed) {
1813 0 : kidRenumberedABullet = true;
1814 :
1815 : // The ordinal changed - mark the bullet frame, and any
1816 : // intermediate frames between it and the block (are there
1817 : // ever any?), dirty.
1818 : // The calling code will make the necessary FrameNeedsReflow
1819 : // call for the list ancestor.
1820 0 : bullet->AddStateBits(NS_FRAME_IS_DIRTY);
1821 0 : nsIFrame *f = bullet;
1822 0 : do {
1823 0 : nsIFrame *parent = f->GetParent();
1824 0 : parent->ChildIsDirty(f);
1825 0 : f = parent;
1826 0 : } while (f != listItem);
1827 : }
1828 : } else {
1829 : // We're only counting the number of children,
1830 : // not restyling them. Don't take |value|
1831 : // into account when incrementing the ordinal
1832 : // or dirty the bullet.
1833 0 : *aOrdinal += aIncrement;
1834 : }
1835 : }
1836 :
1837 : // XXX temporary? if the list-item has child list-items they
1838 : // should be numbered too; especially since the list-item is
1839 : // itself (ASSUMED!) not to be a counter-resetter.
1840 0 : bool meToo = listItem->RenumberChildFrames(aOrdinal, aDepth + 1,
1841 0 : aIncrement, aForCounting);
1842 0 : if (meToo) {
1843 0 : kidRenumberedABullet = true;
1844 : }
1845 : }
1846 0 : } else if (display->mDisplay == mozilla::StyleDisplay::Block ||
1847 0 : display->mDisplay == mozilla::StyleDisplay::Flex ||
1848 0 : display->mDisplay == mozilla::StyleDisplay::Grid) {
1849 0 : if (FrameStartsCounterScope(kid)) {
1850 : // Don't bother recursing into a frame that is a new counter scope.
1851 : // Any list-items in there will be handled by it.
1852 : } else {
1853 0 : nsContainerFrame* container = do_QueryFrame(kid);
1854 0 : if (container) {
1855 : kidRenumberedABullet =
1856 0 : container->RenumberChildFrames(aOrdinal, aDepth + 1,
1857 0 : aIncrement, aForCounting);
1858 : }
1859 : }
1860 : }
1861 0 : return kidRenumberedABullet;
1862 : }
1863 :
1864 : bool
1865 0 : nsContainerFrame::RenumberChildFrames(int32_t* aOrdinal,
1866 : int32_t aDepth,
1867 : int32_t aIncrement,
1868 : bool aForCounting)
1869 : {
1870 0 : bool renumbered = false;
1871 0 : for (auto kid : mFrames) {
1872 : bool kidRenumbered =
1873 0 : kid->RenumberFrameAndDescendants(aOrdinal, aDepth, aIncrement, aForCounting);
1874 0 : if (!aForCounting && kidRenumbered) {
1875 0 : renumbered = true;
1876 : }
1877 : }
1878 :
1879 : // We need to set NS_FRAME_HAS_DIRTY_CHILDREN bits up the tree between
1880 : // the bullet and the caller of RenumberLists. But the caller itself
1881 : // has to be responsible for setting the bit itself, since that caller
1882 : // might be making a FrameNeedsReflow call, which requires that the
1883 : // bit not be set yet.
1884 0 : if (renumbered && aDepth != 0) {
1885 0 : AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
1886 : }
1887 :
1888 0 : return renumbered;
1889 : }
1890 :
1891 : uint16_t
1892 0 : nsContainerFrame::CSSAlignmentForAbsPosChild(const ReflowInput& aChildRI,
1893 : LogicalAxis aLogicalAxis) const
1894 : {
1895 0 : MOZ_ASSERT(aChildRI.mFrame->IsAbsolutelyPositioned(),
1896 : "This method should only be called for abspos children");
1897 0 : NS_ERROR("Child classes that use css box alignment for abspos children "
1898 : "should provide their own implementation of this method!");
1899 :
1900 : // In the unexpected/unlikely event that this implementation gets invoked,
1901 : // just use "start" alignment.
1902 0 : return NS_STYLE_ALIGN_START;
1903 : }
1904 :
1905 : nsresult
1906 134 : nsContainerFrame::AttributeChanged(int32_t aNameSpaceID,
1907 : nsIAtom* aAttribute,
1908 : int32_t aModType)
1909 : {
1910 134 : nsresult rv = nsSplittableFrame::AttributeChanged(aNameSpaceID,
1911 134 : aAttribute, aModType);
1912 134 : if (NS_FAILED(rv)) {
1913 0 : return rv;
1914 : }
1915 268 : if (nsGkAtoms::start == aAttribute ||
1916 134 : (nsGkAtoms::reversed == aAttribute &&
1917 0 : mContent->IsHTMLElement(nsGkAtoms::ol))) {
1918 :
1919 : // XXX Not sure if this is necessary anymore
1920 0 : if (RenumberList()) {
1921 0 : PresContext()->PresShell()->
1922 0 : FrameNeedsReflow(this, nsIPresShell::eStyleChange,
1923 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
1924 : }
1925 : }
1926 134 : return rv;
1927 : }
1928 :
1929 185 : nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsContainerFrame* aFrame,
1930 : bool aWalkOOFFrames,
1931 185 : bool aSkipOverflowContainerChildren)
1932 : : mOverflowContList(nullptr),
1933 : mPrevOverflowCont(nullptr),
1934 : mSentry(nullptr),
1935 : mParent(aFrame),
1936 : mSkipOverflowContainerChildren(aSkipOverflowContainerChildren),
1937 185 : mWalkOOFFrames(aWalkOOFFrames)
1938 : {
1939 185 : NS_PRECONDITION(aFrame, "null frame pointer");
1940 185 : SetupOverflowContList();
1941 185 : }
1942 :
1943 : void
1944 185 : nsOverflowContinuationTracker::SetupOverflowContList()
1945 : {
1946 185 : NS_PRECONDITION(mParent, "null frame pointer");
1947 185 : NS_PRECONDITION(!mOverflowContList, "already have list");
1948 : nsContainerFrame* nif =
1949 185 : static_cast<nsContainerFrame*>(mParent->GetNextInFlow());
1950 185 : if (nif) {
1951 0 : mOverflowContList = nif->GetPropTableFrames(
1952 : nsContainerFrame::OverflowContainersProperty());
1953 0 : if (mOverflowContList) {
1954 0 : mParent = nif;
1955 0 : SetUpListWalker();
1956 : }
1957 : }
1958 185 : if (!mOverflowContList) {
1959 185 : mOverflowContList = mParent->GetPropTableFrames(
1960 : nsContainerFrame::ExcessOverflowContainersProperty());
1961 185 : if (mOverflowContList) {
1962 0 : SetUpListWalker();
1963 : }
1964 : }
1965 185 : }
1966 :
1967 : /**
1968 : * Helper function to walk past overflow continuations whose prev-in-flow
1969 : * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
1970 : */
1971 : void
1972 0 : nsOverflowContinuationTracker::SetUpListWalker()
1973 : {
1974 0 : NS_ASSERTION(!mSentry && !mPrevOverflowCont,
1975 : "forgot to reset mSentry or mPrevOverflowCont");
1976 0 : if (mOverflowContList) {
1977 0 : nsIFrame* cur = mOverflowContList->FirstChild();
1978 0 : if (mSkipOverflowContainerChildren) {
1979 0 : while (cur && (cur->GetPrevInFlow()->GetStateBits()
1980 0 : & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1981 0 : mPrevOverflowCont = cur;
1982 0 : cur = cur->GetNextSibling();
1983 : }
1984 0 : while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
1985 0 : == mWalkOOFFrames)) {
1986 0 : mPrevOverflowCont = cur;
1987 0 : cur = cur->GetNextSibling();
1988 : }
1989 : }
1990 0 : if (cur) {
1991 0 : mSentry = cur->GetPrevInFlow();
1992 : }
1993 : }
1994 0 : }
1995 :
1996 : /**
1997 : * Helper function to step forward through the overflow continuations list.
1998 : * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
1999 : * as appropriate. May only be called when we have already set up an
2000 : * mOverflowContList; mOverflowContList cannot be null.
2001 : */
2002 : void
2003 0 : nsOverflowContinuationTracker::StepForward()
2004 : {
2005 0 : NS_PRECONDITION(mOverflowContList, "null list");
2006 :
2007 : // Step forward
2008 0 : if (mPrevOverflowCont) {
2009 0 : mPrevOverflowCont = mPrevOverflowCont->GetNextSibling();
2010 : }
2011 : else {
2012 0 : mPrevOverflowCont = mOverflowContList->FirstChild();
2013 : }
2014 :
2015 : // Skip over oof or non-oof frames as appropriate
2016 0 : if (mSkipOverflowContainerChildren) {
2017 0 : nsIFrame* cur = mPrevOverflowCont->GetNextSibling();
2018 0 : while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
2019 0 : == mWalkOOFFrames)) {
2020 0 : mPrevOverflowCont = cur;
2021 0 : cur = cur->GetNextSibling();
2022 : }
2023 : }
2024 :
2025 : // Set up the sentry
2026 0 : mSentry = (mPrevOverflowCont->GetNextSibling())
2027 0 : ? mPrevOverflowCont->GetNextSibling()->GetPrevInFlow()
2028 : : nullptr;
2029 0 : }
2030 :
2031 : nsresult
2032 0 : nsOverflowContinuationTracker::Insert(nsIFrame* aOverflowCont,
2033 : nsReflowStatus& aReflowStatus)
2034 : {
2035 0 : NS_PRECONDITION(aOverflowCont, "null frame pointer");
2036 0 : NS_PRECONDITION(!mSkipOverflowContainerChildren || mWalkOOFFrames ==
2037 : !!(aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
2038 : "shouldn't insert frame that doesn't match walker type");
2039 0 : NS_PRECONDITION(aOverflowCont->GetPrevInFlow(),
2040 : "overflow containers must have a prev-in-flow");
2041 0 : nsresult rv = NS_OK;
2042 0 : bool reparented = false;
2043 0 : nsPresContext* presContext = aOverflowCont->PresContext();
2044 0 : bool addToList = !mSentry || aOverflowCont != mSentry->GetNextInFlow();
2045 :
2046 : // If we have a list and aOverflowCont is already in it then don't try to
2047 : // add it again.
2048 0 : if (addToList && aOverflowCont->GetParent() == mParent &&
2049 0 : (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) &&
2050 0 : mOverflowContList && mOverflowContList->ContainsFrame(aOverflowCont)) {
2051 0 : addToList = false;
2052 0 : mPrevOverflowCont = aOverflowCont->GetPrevSibling();
2053 : }
2054 :
2055 0 : if (addToList) {
2056 0 : if (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
2057 : // aOverflowCont is in some other overflow container list,
2058 : // steal it first
2059 0 : NS_ASSERTION(!(mOverflowContList &&
2060 : mOverflowContList->ContainsFrame(aOverflowCont)),
2061 : "overflow containers out of order");
2062 0 : rv = aOverflowCont->GetParent()->StealFrame(aOverflowCont);
2063 0 : NS_ENSURE_SUCCESS(rv, rv);
2064 : }
2065 : else {
2066 0 : aOverflowCont->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
2067 : }
2068 0 : if (!mOverflowContList) {
2069 0 : mOverflowContList = new (presContext->PresShell()) nsFrameList();
2070 0 : mParent->SetPropTableFrames(mOverflowContList,
2071 0 : nsContainerFrame::ExcessOverflowContainersProperty());
2072 0 : SetUpListWalker();
2073 : }
2074 0 : if (aOverflowCont->GetParent() != mParent) {
2075 : nsContainerFrame::ReparentFrameView(aOverflowCont,
2076 0 : aOverflowCont->GetParent(),
2077 0 : mParent);
2078 0 : reparented = true;
2079 : }
2080 :
2081 : // If aOverflowCont has a prev/next-in-flow that might be in
2082 : // mOverflowContList we need to find it and insert after/before it to
2083 : // maintain the order amongst next-in-flows in this list.
2084 0 : nsIFrame* pif = aOverflowCont->GetPrevInFlow();
2085 0 : nsIFrame* nif = aOverflowCont->GetNextInFlow();
2086 0 : if ((pif && pif->GetParent() == mParent && pif != mPrevOverflowCont) ||
2087 0 : (nif && nif->GetParent() == mParent && mPrevOverflowCont)) {
2088 0 : for (nsFrameList::Enumerator e(*mOverflowContList); !e.AtEnd(); e.Next()) {
2089 0 : nsIFrame* f = e.get();
2090 0 : if (f == pif) {
2091 0 : mPrevOverflowCont = pif;
2092 0 : break;
2093 : }
2094 0 : if (f == nif) {
2095 0 : mPrevOverflowCont = f->GetPrevSibling();
2096 0 : break;
2097 : }
2098 : }
2099 : }
2100 :
2101 0 : mOverflowContList->InsertFrame(mParent, mPrevOverflowCont, aOverflowCont);
2102 0 : aReflowStatus.SetNextInFlowNeedsReflow();
2103 : }
2104 :
2105 : // If we need to reflow it, mark it dirty
2106 0 : if (aReflowStatus.NextInFlowNeedsReflow())
2107 0 : aOverflowCont->AddStateBits(NS_FRAME_IS_DIRTY);
2108 :
2109 : // It's in our list, just step forward
2110 0 : StepForward();
2111 0 : NS_ASSERTION(mPrevOverflowCont == aOverflowCont ||
2112 : (mSkipOverflowContainerChildren &&
2113 : (mPrevOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW) !=
2114 : (aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW)),
2115 : "OverflowContTracker in unexpected state");
2116 :
2117 0 : if (addToList) {
2118 : // Convert all non-overflow-container continuations of aOverflowCont
2119 : // into overflow containers and move them to our overflow
2120 : // tracker. This preserves the invariant that the next-continuations
2121 : // of an overflow container are also overflow containers.
2122 0 : nsIFrame* f = aOverflowCont->GetNextContinuation();
2123 0 : if (f && (!(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) ||
2124 0 : (!reparented && f->GetParent() == mParent) ||
2125 0 : (reparented && f->GetParent() != mParent))) {
2126 0 : if (!(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
2127 0 : rv = f->GetParent()->StealFrame(f);
2128 0 : NS_ENSURE_SUCCESS(rv, rv);
2129 : }
2130 0 : Insert(f, aReflowStatus);
2131 : }
2132 : }
2133 0 : return rv;
2134 : }
2135 :
2136 : void
2137 0 : nsOverflowContinuationTracker::BeginFinish(nsIFrame* aChild)
2138 : {
2139 0 : NS_PRECONDITION(aChild, "null ptr");
2140 0 : NS_PRECONDITION(aChild->GetNextInFlow(),
2141 : "supposed to call Finish *before* deleting next-in-flow!");
2142 0 : for (nsIFrame* f = aChild; f; f = f->GetNextInFlow()) {
2143 : // We'll update these in EndFinish after the next-in-flows are gone.
2144 0 : if (f == mPrevOverflowCont) {
2145 0 : mSentry = nullptr;
2146 0 : mPrevOverflowCont = nullptr;
2147 0 : break;
2148 : }
2149 0 : if (f == mSentry) {
2150 0 : mSentry = nullptr;
2151 0 : break;
2152 : }
2153 : }
2154 0 : }
2155 :
2156 : void
2157 0 : nsOverflowContinuationTracker::EndFinish(nsIFrame* aChild)
2158 : {
2159 0 : if (!mOverflowContList) {
2160 0 : return;
2161 : }
2162 : // Forget mOverflowContList if it was deleted.
2163 0 : nsFrameList* eoc = mParent->GetProperty
2164 0 : (nsContainerFrame::ExcessOverflowContainersProperty());
2165 0 : if (eoc != mOverflowContList) {
2166 0 : nsFrameList* oc = static_cast<nsFrameList*>(mParent->GetProperty
2167 0 : (nsContainerFrame::OverflowContainersProperty()));
2168 0 : if (oc != mOverflowContList) {
2169 : // mOverflowContList was deleted
2170 0 : mPrevOverflowCont = nullptr;
2171 0 : mSentry = nullptr;
2172 0 : mParent = aChild->GetParent();
2173 0 : mOverflowContList = nullptr;
2174 0 : SetupOverflowContList();
2175 0 : return;
2176 : }
2177 : }
2178 : // The list survived, update mSentry if needed.
2179 0 : if (!mSentry) {
2180 0 : if (!mPrevOverflowCont) {
2181 0 : SetUpListWalker();
2182 : } else {
2183 0 : mozilla::AutoRestore<nsIFrame*> saved(mPrevOverflowCont);
2184 : // step backward to make StepForward() use our current mPrevOverflowCont
2185 0 : mPrevOverflowCont = mPrevOverflowCont->GetPrevSibling();
2186 0 : StepForward();
2187 : }
2188 : }
2189 : }
2190 :
2191 : /////////////////////////////////////////////////////////////////////////////
2192 : // Debugging
2193 :
2194 : #ifdef DEBUG_FRAME_DUMP
2195 : void
2196 0 : nsContainerFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
2197 : {
2198 0 : nsCString str;
2199 0 : ListGeneric(str, aPrefix, aFlags);
2200 :
2201 : // Output the children
2202 0 : bool outputOneList = false;
2203 0 : ChildListIterator lists(this);
2204 0 : for (; !lists.IsDone(); lists.Next()) {
2205 0 : if (outputOneList) {
2206 0 : str += aPrefix;
2207 : }
2208 0 : if (lists.CurrentID() != kPrincipalList) {
2209 0 : if (!outputOneList) {
2210 0 : str += "\n";
2211 0 : str += aPrefix;
2212 : }
2213 0 : str += nsPrintfCString("%s %p ", mozilla::layout::ChildListName(lists.CurrentID()),
2214 0 : &GetChildList(lists.CurrentID()));
2215 : }
2216 0 : fprintf_stderr(out, "%s<\n", str.get());
2217 0 : str = "";
2218 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
2219 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
2220 0 : nsIFrame* kid = childFrames.get();
2221 : // Verify the child frame's parent frame pointer is correct
2222 0 : NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");
2223 :
2224 : // Have the child frame list
2225 0 : nsCString pfx(aPrefix);
2226 0 : pfx += " ";
2227 0 : kid->List(out, pfx.get(), aFlags);
2228 : }
2229 0 : fprintf_stderr(out, "%s>\n", aPrefix);
2230 0 : outputOneList = true;
2231 : }
2232 :
2233 0 : if (!outputOneList) {
2234 0 : fprintf_stderr(out, "%s<>\n", str.get());
2235 : }
2236 0 : }
2237 : #endif
|