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/. */
6 /* base class #1 for rendering objects that have child lists */
8 #include "nsContainerFrame.h"
10 #include "nsAbsoluteContainingBlock.h"
11 #include "nsIDocument.h"
12 #include "nsPresContext.h"
13 #include "nsStyleContext.h"
16 #include "nsStyleConsts.h"
18 #include "nsIPresShell.h"
20 #include "nsGkAtoms.h"
21 #include "nsViewManager.h"
22 #include "nsIWidget.h"
23 #include "nsCSSRendering.h"
25 #include "nsDisplayList.h"
26 #include "nsIBaseWindow.h"
27 #include "nsBoxLayoutState.h"
28 #include "nsCSSFrameConstructor.h"
29 #include "nsBlockFrame.h"
30 #include "mozilla/AutoRestore.h"
31 #include "nsIFrameInlines.h"
32 #include "nsPrintfCString.h"
41 using namespace mozilla
;
42 using namespace mozilla::dom
;
43 using namespace mozilla::layout
;
45 NS_IMPL_FRAMEARENA_HELPERS(nsContainerFrame
)
47 nsContainerFrame::~nsContainerFrame()
51 NS_QUERYFRAME_HEAD(nsContainerFrame
)
52 NS_QUERYFRAME_ENTRY(nsContainerFrame
)
53 NS_QUERYFRAME_TAIL_INHERITING(nsSplittableFrame
)
56 nsContainerFrame::Init(nsIContent
* aContent
,
57 nsContainerFrame
* aParent
,
58 nsIFrame
* aPrevInFlow
)
60 nsSplittableFrame::Init(aContent
, aParent
, aPrevInFlow
);
62 // Make sure we copy bits from our prev-in-flow that will affect
63 // us. A continuation for a container frame needs to know if it
64 // has a child with a view so that we'll properly reposition it.
65 if (aPrevInFlow
->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW
)
66 AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW
);
71 nsContainerFrame::SetInitialChildList(ChildListID aListID
,
72 nsFrameList
& aChildList
)
74 MOZ_ASSERT(mFrames
.IsEmpty(),
75 "unexpected second call to SetInitialChildList");
76 MOZ_ASSERT(aListID
== kPrincipalList
, "unexpected child list");
78 nsFrame::VerifyDirtyBitSet(aChildList
);
80 mFrames
.SetFrames(aChildList
);
84 nsContainerFrame::AppendFrames(ChildListID aListID
,
85 nsFrameList
& aFrameList
)
87 MOZ_ASSERT(aListID
== kPrincipalList
|| aListID
== kNoReflowPrincipalList
,
88 "unexpected child list");
89 if (aFrameList
.NotEmpty()) {
90 mFrames
.AppendFrames(this, aFrameList
);
92 // Ask the parent frame to reflow me.
93 if (aListID
== kPrincipalList
)
95 PresContext()->PresShell()->
96 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
97 NS_FRAME_HAS_DIRTY_CHILDREN
);
103 nsContainerFrame::InsertFrames(ChildListID aListID
,
104 nsIFrame
* aPrevFrame
,
105 nsFrameList
& aFrameList
)
107 MOZ_ASSERT(aListID
== kPrincipalList
|| aListID
== kNoReflowPrincipalList
,
108 "unexpected child list");
109 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
110 "inserting after sibling frame with different parent");
112 if (aFrameList
.NotEmpty()) {
113 // Insert frames after aPrevFrame
114 mFrames
.InsertFrames(this, aPrevFrame
, aFrameList
);
116 if (aListID
== kPrincipalList
)
118 PresContext()->PresShell()->
119 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
120 NS_FRAME_HAS_DIRTY_CHILDREN
);
126 nsContainerFrame::RemoveFrame(ChildListID aListID
,
129 MOZ_ASSERT(aListID
== kPrincipalList
|| aListID
== kNoReflowPrincipalList
,
130 "unexpected child list");
132 // Loop and destroy aOldFrame and all of its continuations.
133 // Request a reflow on the parent frames involved unless we were explicitly
134 // told not to (kNoReflowPrincipalList).
135 bool generateReflowCommand
= true;
136 if (kNoReflowPrincipalList
== aListID
) {
137 generateReflowCommand
= false;
139 nsIPresShell
* shell
= PresContext()->PresShell();
140 nsContainerFrame
* lastParent
= nullptr;
142 //XXXfr probably should use StealFrame here. I'm not sure if we need to
143 // check the overflow lists atm, but we'll need a prescontext lookup
144 // for overflow containers once we can split abspos elements with
145 // inline containing blocks.
146 nsIFrame
* oldFrameNextContinuation
= aOldFrame
->GetNextContinuation();
147 nsContainerFrame
* parent
= aOldFrame
->GetParent();
148 parent
->StealFrame(aOldFrame
, true);
149 aOldFrame
->Destroy();
150 aOldFrame
= oldFrameNextContinuation
;
151 if (parent
!= lastParent
&& generateReflowCommand
) {
152 shell
->FrameNeedsReflow(parent
, nsIPresShell::eTreeChange
,
153 NS_FRAME_HAS_DIRTY_CHILDREN
);
160 nsContainerFrame::DestroyAbsoluteFrames(nsIFrame
* aDestructRoot
)
162 if (IsAbsoluteContainer()) {
163 GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot
);
164 MarkAsNotAbsoluteContainingBlock();
169 nsContainerFrame::SafelyDestroyFrameListProp(nsIFrame
* aDestructRoot
,
170 nsIPresShell
* aPresShell
,
171 FramePropertyTable
* aPropTable
,
172 const FramePropertyDescriptor
* aProp
)
174 // Note that the last frame can be removed through another route and thus
175 // delete the property -- that's why we fetch the property again before
176 // removing each frame rather than fetching it once and iterating the list.
177 while (nsFrameList
* frameList
=
178 static_cast<nsFrameList
*>(aPropTable
->Get(this, aProp
))) {
179 nsIFrame
* frame
= frameList
->RemoveFirstChild();
180 if (MOZ_LIKELY(frame
)) {
181 frame
->DestroyFrom(aDestructRoot
);
183 aPropTable
->Remove(this, aProp
);
184 frameList
->Delete(aPresShell
);
191 nsContainerFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
193 // Prevent event dispatch during destruction.
195 GetView()->SetFrame(nullptr);
198 DestroyAbsoluteFrames(aDestructRoot
);
200 // Destroy frames on the principal child list.
201 mFrames
.DestroyFramesFrom(aDestructRoot
);
203 // Destroy frames on the auxiliary frame lists and delete the lists.
204 nsPresContext
* pc
= PresContext();
205 nsIPresShell
* shell
= pc
->PresShell();
206 FramePropertyTable
* props
= pc
->PropertyTable();
207 SafelyDestroyFrameListProp(aDestructRoot
, shell
, props
, OverflowProperty());
209 MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers
) ||
210 !(props
->Get(this, nsContainerFrame::OverflowContainersProperty()) ||
211 props
->Get(this, nsContainerFrame::ExcessOverflowContainersProperty())),
212 "this type of frame should't have overflow containers");
214 SafelyDestroyFrameListProp(aDestructRoot
, shell
, props
,
215 OverflowContainersProperty());
216 SafelyDestroyFrameListProp(aDestructRoot
, shell
, props
,
217 ExcessOverflowContainersProperty());
219 nsSplittableFrame::DestroyFrom(aDestructRoot
);
222 /////////////////////////////////////////////////////////////////////////////
223 // Child frame enumeration
226 nsContainerFrame::GetChildList(ChildListID aListID
) const
228 // We only know about the principal child list and the overflow lists.
232 case kOverflowList
: {
233 nsFrameList
* list
= GetOverflowFrames();
234 return list
? *list
: nsFrameList::EmptyList();
236 case kOverflowContainersList
: {
237 nsFrameList
* list
= GetPropTableFrames(OverflowContainersProperty());
238 return list
? *list
: nsFrameList::EmptyList();
240 case kExcessOverflowContainersList
: {
242 GetPropTableFrames(ExcessOverflowContainersProperty());
243 return list
? *list
: nsFrameList::EmptyList();
246 return nsSplittableFrame::GetChildList(aListID
);
250 static void AppendIfNonempty(const nsIFrame
* aFrame
,
251 FramePropertyTable
* aPropTable
,
252 const FramePropertyDescriptor
* aProperty
,
253 nsTArray
<nsIFrame::ChildList
>* aLists
,
254 nsIFrame::ChildListID aListID
)
256 nsFrameList
* list
= static_cast<nsFrameList
*>(
257 aPropTable
->Get(aFrame
, aProperty
));
259 list
->AppendIfNonempty(aLists
, aListID
);
264 nsContainerFrame::GetChildLists(nsTArray
<ChildList
>* aLists
) const
266 mFrames
.AppendIfNonempty(aLists
, kPrincipalList
);
267 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
268 ::AppendIfNonempty(this, propTable
, OverflowProperty(),
269 aLists
, kOverflowList
);
270 if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers
)) {
271 ::AppendIfNonempty(this, propTable
, OverflowContainersProperty(),
272 aLists
, kOverflowContainersList
);
273 ::AppendIfNonempty(this, propTable
, ExcessOverflowContainersProperty(),
274 aLists
, kExcessOverflowContainersList
);
276 nsSplittableFrame::GetChildLists(aLists
);
279 /////////////////////////////////////////////////////////////////////////////
283 nsContainerFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
284 const nsRect
& aDirtyRect
,
285 const nsDisplayListSet
& aLists
)
287 DisplayBorderBackgroundOutline(aBuilder
, aLists
);
289 BuildDisplayListForNonBlockChildren(aBuilder
, aDirtyRect
, aLists
);
293 nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder
* aBuilder
,
294 const nsRect
& aDirtyRect
,
295 const nsDisplayListSet
& aLists
,
298 nsIFrame
* kid
= mFrames
.FirstChild();
299 // Put each child's background directly onto the content list
300 nsDisplayListSet
set(aLists
, aLists
.Content());
301 // The children should be in content order
303 BuildDisplayListForChild(aBuilder
, kid
, aDirtyRect
, set
, aFlags
);
304 kid
= kid
->GetNextSibling();
309 nsContainerFrame::ChildIsDirty(nsIFrame
* aChild
)
311 NS_ASSERTION(NS_SUBTREE_DIRTY(aChild
), "child isn't actually dirty");
313 AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN
);
317 nsContainerFrame::IsLeaf() const
322 nsIFrame::FrameSearchResult
323 nsContainerFrame::PeekOffsetNoAmount(bool aForward
, int32_t* aOffset
)
325 NS_ASSERTION (aOffset
&& *aOffset
<= 1, "aOffset out of range");
326 // Don't allow the caret to stay in an empty (leaf) container frame.
327 return CONTINUE_EMPTY
;
330 nsIFrame::FrameSearchResult
331 nsContainerFrame::PeekOffsetCharacter(bool aForward
, int32_t* aOffset
,
332 bool aRespectClusters
)
334 NS_ASSERTION (aOffset
&& *aOffset
<= 1, "aOffset out of range");
335 // Don't allow the caret to stay in an empty (leaf) container frame.
336 return CONTINUE_EMPTY
;
339 /////////////////////////////////////////////////////////////////////////////
340 // Helper member functions
343 ReparentFrameViewTo(nsIFrame
* aFrame
,
344 nsViewManager
* aViewManager
,
345 nsView
* aNewParentView
,
346 nsView
* aOldParentView
)
349 // XXX What to do about placeholder views for "position: fixed" elements?
350 // They should be reparented too.
352 // Does aFrame have a view?
353 if (aFrame
->HasView()) {
355 if (aFrame
->GetType() == nsGkAtoms::menuPopupFrame
) {
356 // This view must be parented by the root view, don't reparent it.
360 nsView
* view
= aFrame
->GetView();
361 // Verify that the current parent view is what we think it is
362 //nsView* parentView;
363 //NS_ASSERTION(parentView == aOldParentView, "unexpected parent view");
365 aViewManager
->RemoveChild(view
);
367 // The view will remember the Z-order and other attributes that have been set on it.
368 nsView
* insertBefore
= nsLayoutUtils::FindSiblingViewFor(aNewParentView
, aFrame
);
369 aViewManager
->InsertChild(aNewParentView
, view
, insertBefore
, insertBefore
!= nullptr);
371 nsIFrame::ChildListIterator
lists(aFrame
);
372 for (; !lists
.IsDone(); lists
.Next()) {
373 // Iterate the child frames, and check each child frame to see if it has
375 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
376 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
377 ReparentFrameViewTo(childFrames
.get(), aViewManager
,
378 aNewParentView
, aOldParentView
);
387 nsContainerFrame::CreateViewForFrame(nsIFrame
* aFrame
,
390 if (aFrame
->HasView()) {
394 // If we don't yet have a view, see if we need a view
395 if (!aForce
&& !aFrame
->NeedsView()) {
400 nsView
* parentView
= aFrame
->GetParent()->GetClosestView();
401 NS_ASSERTION(parentView
, "no parent with view");
403 nsViewManager
* viewManager
= parentView
->GetViewManager();
404 NS_ASSERTION(viewManager
, "null view manager");
407 nsView
* view
= viewManager
->CreateView(aFrame
->GetRect(), parentView
);
409 SyncFrameViewProperties(aFrame
->PresContext(), aFrame
, nullptr, view
);
411 nsView
* insertBefore
= nsLayoutUtils::FindSiblingViewFor(parentView
, aFrame
);
412 // we insert this view 'above' the insertBefore view, unless insertBefore is null,
413 // in which case we want to call with aAbove == false to insert at the beginning
415 viewManager
->InsertChild(parentView
, view
, insertBefore
, insertBefore
!= nullptr);
417 // REVIEW: Don't create a widget for fixed-pos elements anymore.
418 // ComputeRepaintRegionForCopy will calculate the right area to repaint
420 // Reparent views on any child frames (or their descendants) to this
421 // view. We can just call ReparentFrameViewTo on this frame because
422 // we know this frame has no view, so it will crawl the children. Also,
423 // we know that any descendants with views must have 'parentView' as their
425 ReparentFrameViewTo(aFrame
, viewManager
, view
, parentView
);
428 aFrame
->SetView(view
);
430 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS
,
431 ("nsContainerFrame::CreateViewForFrame: frame=%p view=%p",
436 * Position the view associated with |aKidFrame|, if there is one. A
437 * container frame should call this method after positioning a frame,
438 * but before |Reflow|.
441 nsContainerFrame::PositionFrameView(nsIFrame
* aKidFrame
)
443 nsIFrame
* parentFrame
= aKidFrame
->GetParent();
444 if (!aKidFrame
->HasView() || !parentFrame
)
447 nsView
* view
= aKidFrame
->GetView();
448 nsViewManager
* vm
= view
->GetViewManager();
450 nsView
* ancestorView
= parentFrame
->GetClosestView(&pt
);
452 if (ancestorView
!= view
->GetParent()) {
453 NS_ASSERTION(ancestorView
== view
->GetParent()->GetParent(),
454 "Allowed only one anonymous view between frames");
455 // parentFrame is responsible for positioning aKidFrame's view
460 pt
+= aKidFrame
->GetPosition();
461 vm
->MoveViewTo(view
, pt
.x
, pt
.y
);
465 nsContainerFrame::ReparentFrameView(nsIFrame
* aChildFrame
,
466 nsIFrame
* aOldParentFrame
,
467 nsIFrame
* aNewParentFrame
)
469 NS_PRECONDITION(aChildFrame
, "null child frame pointer");
470 NS_PRECONDITION(aOldParentFrame
, "null old parent frame pointer");
471 NS_PRECONDITION(aNewParentFrame
, "null new parent frame pointer");
472 NS_PRECONDITION(aOldParentFrame
!= aNewParentFrame
, "same old and new parent frame");
474 // See if either the old parent frame or the new parent frame have a view
475 while (!aOldParentFrame
->HasView() && !aNewParentFrame
->HasView()) {
476 // Walk up both the old parent frame and the new parent frame nodes
477 // stopping when we either find a common parent or views for one
478 // or both of the frames.
480 // This works well in the common case where we push/pull and the old parent
481 // frame and the new parent frame are part of the same flow. They will
482 // typically be the same distance (height wise) from the
483 aOldParentFrame
= aOldParentFrame
->GetParent();
484 aNewParentFrame
= aNewParentFrame
->GetParent();
486 // We should never walk all the way to the root frame without finding
488 NS_ASSERTION(aOldParentFrame
&& aNewParentFrame
, "didn't find view");
490 // See if we reached a common ancestor
491 if (aOldParentFrame
== aNewParentFrame
) {
496 // See if we found a common parent frame
497 if (aOldParentFrame
== aNewParentFrame
) {
498 // We found a common parent and there are no views between the old parent
499 // and the common parent or the new parent frame and the common parent.
500 // Because neither the old parent frame nor the new parent frame have views,
501 // then any child views don't need reparenting
505 // We found views for one or both of the ancestor frames before we
506 // found a common ancestor.
507 nsView
* oldParentView
= aOldParentFrame
->GetClosestView();
508 nsView
* newParentView
= aNewParentFrame
->GetClosestView();
510 // See if the old parent frame and the new parent frame are in the
511 // same view sub-hierarchy. If they are then we don't have to do
513 if (oldParentView
!= newParentView
) {
514 // They're not so we need to reparent any child views
515 return ReparentFrameViewTo(aChildFrame
, oldParentView
->GetViewManager(), newParentView
,
523 nsContainerFrame::ReparentFrameViewList(const nsFrameList
& aChildFrameList
,
524 nsIFrame
* aOldParentFrame
,
525 nsIFrame
* aNewParentFrame
)
527 NS_PRECONDITION(aChildFrameList
.NotEmpty(), "empty child frame list");
528 NS_PRECONDITION(aOldParentFrame
, "null old parent frame pointer");
529 NS_PRECONDITION(aNewParentFrame
, "null new parent frame pointer");
530 NS_PRECONDITION(aOldParentFrame
!= aNewParentFrame
, "same old and new parent frame");
532 // See if either the old parent frame or the new parent frame have a view
533 while (!aOldParentFrame
->HasView() && !aNewParentFrame
->HasView()) {
534 // Walk up both the old parent frame and the new parent frame nodes
535 // stopping when we either find a common parent or views for one
536 // or both of the frames.
538 // This works well in the common case where we push/pull and the old parent
539 // frame and the new parent frame are part of the same flow. They will
540 // typically be the same distance (height wise) from the
541 aOldParentFrame
= aOldParentFrame
->GetParent();
542 aNewParentFrame
= aNewParentFrame
->GetParent();
544 // We should never walk all the way to the root frame without finding
546 NS_ASSERTION(aOldParentFrame
&& aNewParentFrame
, "didn't find view");
548 // See if we reached a common ancestor
549 if (aOldParentFrame
== aNewParentFrame
) {
555 // See if we found a common parent frame
556 if (aOldParentFrame
== aNewParentFrame
) {
557 // We found a common parent and there are no views between the old parent
558 // and the common parent or the new parent frame and the common parent.
559 // Because neither the old parent frame nor the new parent frame have views,
560 // then any child views don't need reparenting
564 // We found views for one or both of the ancestor frames before we
565 // found a common ancestor.
566 nsView
* oldParentView
= aOldParentFrame
->GetClosestView();
567 nsView
* newParentView
= aNewParentFrame
->GetClosestView();
569 // See if the old parent frame and the new parent frame are in the
570 // same view sub-hierarchy. If they are then we don't have to do
572 if (oldParentView
!= newParentView
) {
573 nsViewManager
* viewManager
= oldParentView
->GetViewManager();
575 // They're not so we need to reparent any child views
576 for (nsFrameList::Enumerator
e(aChildFrameList
); !e
.AtEnd(); e
.Next()) {
577 ReparentFrameViewTo(e
.get(), viewManager
, newParentView
, oldParentView
);
585 GetPresContextContainerWidget(nsPresContext
* aPresContext
)
587 nsCOMPtr
<nsISupports
> container
= aPresContext
->Document()->GetContainer();
588 nsCOMPtr
<nsIBaseWindow
> baseWindow
= do_QueryInterface(container
);
592 nsCOMPtr
<nsIWidget
> mainWidget
;
593 baseWindow
->GetMainWidget(getter_AddRefs(mainWidget
));
598 IsTopLevelWidget(nsIWidget
* aWidget
)
600 nsWindowType windowType
= aWidget
->WindowType();
601 return windowType
== eWindowType_toplevel
||
602 windowType
== eWindowType_dialog
||
603 windowType
== eWindowType_sheet
;
604 // popups aren't toplevel so they're not handled here
608 nsContainerFrame::SyncWindowProperties(nsPresContext
* aPresContext
,
611 nsRenderingContext
* aRC
)
614 if (!aView
|| !nsCSSRendering::IsCanvasFrame(aFrame
) || !aView
->HasWidget())
617 nsIWidget
* windowWidget
= GetPresContextContainerWidget(aPresContext
);
618 if (!windowWidget
|| !IsTopLevelWidget(windowWidget
))
621 nsViewManager
* vm
= aView
->GetViewManager();
622 nsView
* rootView
= vm
->GetRootView();
624 if (aView
!= rootView
)
627 Element
* rootElement
= aPresContext
->Document()->GetRootElement();
628 if (!rootElement
|| !rootElement
->IsXUL()) {
629 // Scrollframes use native widgets which don't work well with
630 // translucent windows, at least in Windows XP. So if the document
631 // has a root scrollrame it's useless to try to make it transparent,
632 // we'll just get something broken.
633 // nsCSSFrameConstructor::ConstructRootFrame constructs root
634 // scrollframes whenever the root element is not a XUL element, so
635 // we test for that here. We can't just call
636 // presShell->GetRootScrollFrame() since that might not have
637 // been constructed yet.
638 // We can change this to allow translucent toplevel HTML documents
639 // (e.g. to do something like Dashboard widgets), once we
640 // have broad support for translucent scrolled documents, but be
641 // careful because apparently some Firefox extensions expect
642 // openDialog("something.html") to produce an opaque window
643 // even if the HTML doesn't have a background-color set.
647 nsIFrame
*rootFrame
= aPresContext
->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
651 nsTransparencyMode mode
= nsLayoutUtils::GetFrameTransparency(aFrame
, rootFrame
);
652 nsIWidget
* viewWidget
= aView
->GetWidget();
653 viewWidget
->SetTransparencyMode(mode
);
654 windowWidget
->SetWindowShadowStyle(rootFrame
->StyleUIReset()->mWindowShadow
);
659 nsBoxLayoutState
aState(aPresContext
, aRC
);
660 nsSize minSize
= rootFrame
->GetMinSize(aState
);
661 nsSize maxSize
= rootFrame
->GetMaxSize(aState
);
663 SetSizeConstraints(aPresContext
, windowWidget
, minSize
, maxSize
);
667 void nsContainerFrame::SetSizeConstraints(nsPresContext
* aPresContext
,
669 const nsSize
& aMinSize
,
670 const nsSize
& aMaxSize
)
672 nsIntSize
devMinSize(aPresContext
->AppUnitsToDevPixels(aMinSize
.width
),
673 aPresContext
->AppUnitsToDevPixels(aMinSize
.height
));
674 nsIntSize
devMaxSize(aMaxSize
.width
== NS_INTRINSICSIZE
? NS_MAXSIZE
:
675 aPresContext
->AppUnitsToDevPixels(aMaxSize
.width
),
676 aMaxSize
.height
== NS_INTRINSICSIZE
? NS_MAXSIZE
:
677 aPresContext
->AppUnitsToDevPixels(aMaxSize
.height
));
679 // MinSize has a priority over MaxSize
680 if (devMinSize
.width
> devMaxSize
.width
)
681 devMaxSize
.width
= devMinSize
.width
;
682 if (devMinSize
.height
> devMaxSize
.height
)
683 devMaxSize
.height
= devMinSize
.height
;
685 widget::SizeConstraints
constraints(devMinSize
, devMaxSize
);
687 // The sizes are in inner window sizes, so convert them into outer window sizes.
688 // Use a size of (200, 200) as only the difference between the inner and outer
690 nsIntSize windowSize
= aWidget
->ClientToWindowSize(nsIntSize(200, 200));
691 if (constraints
.mMinSize
.width
)
692 constraints
.mMinSize
.width
+= windowSize
.width
- 200;
693 if (constraints
.mMinSize
.height
)
694 constraints
.mMinSize
.height
+= windowSize
.height
- 200;
695 if (constraints
.mMaxSize
.width
!= NS_MAXSIZE
)
696 constraints
.mMaxSize
.width
+= windowSize
.width
- 200;
697 if (constraints
.mMaxSize
.height
!= NS_MAXSIZE
)
698 constraints
.mMaxSize
.height
+= windowSize
.height
- 200;
700 aWidget
->SetSizeConstraints(constraints
);
704 nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext
* aPresContext
,
707 const nsRect
& aVisualOverflowArea
,
714 // Make sure the view is sized and positioned correctly
715 if (0 == (aFlags
& NS_FRAME_NO_MOVE_VIEW
)) {
716 PositionFrameView(aFrame
);
719 if (0 == (aFlags
& NS_FRAME_NO_SIZE_VIEW
)) {
720 nsViewManager
* vm
= aView
->GetViewManager();
722 vm
->ResizeView(aView
, aVisualOverflowArea
, true);
727 nsContainerFrame::SyncFrameViewProperties(nsPresContext
* aPresContext
,
729 nsStyleContext
* aStyleContext
,
733 NS_ASSERTION(!aStyleContext
|| aFrame
->StyleContext() == aStyleContext
,
734 "Wrong style context for frame?");
740 nsViewManager
* vm
= aView
->GetViewManager();
742 if (nullptr == aStyleContext
) {
743 aStyleContext
= aFrame
->StyleContext();
746 // Make sure visibility is correct. This only affects nsSubdocumentFrame.
747 if (0 == (aFlags
& NS_FRAME_NO_VISIBILITY
) &&
748 !aFrame
->SupportsVisibilityHidden()) {
749 // See if the view should be hidden or visible
750 vm
->SetViewVisibility(aView
,
751 aStyleContext
->StyleVisibility()->IsVisible()
752 ? nsViewVisibility_kShow
: nsViewVisibility_kHide
);
755 // See if the frame is being relatively positioned or absolutely
757 bool isPositioned
= aFrame
->IsPositioned();
760 bool autoZIndex
= false;
765 // Make sure z-index is correct
766 const nsStylePosition
* position
= aStyleContext
->StylePosition();
768 if (position
->mZIndex
.GetUnit() == eStyleUnit_Integer
) {
769 zIndex
= position
->mZIndex
.GetIntValue();
770 } else if (position
->mZIndex
.GetUnit() == eStyleUnit_Auto
) {
775 vm
->SetViewZIndex(aView
, autoZIndex
, zIndex
);
778 static nscoord
GetCoord(const nsStyleCoord
& aCoord
, nscoord aIfNotCoord
)
780 if (aCoord
.ConvertsToLength()) {
781 return nsRuleNode::ComputeCoordPercentCalc(aCoord
, 0);
787 nsContainerFrame::DoInlineIntrinsicISize(nsRenderingContext
*aRenderingContext
,
788 InlineIntrinsicISizeData
*aData
,
789 nsLayoutUtils::IntrinsicISizeType aType
)
792 return; // Already added.
794 NS_PRECONDITION(aType
== nsLayoutUtils::MIN_ISIZE
||
795 aType
== nsLayoutUtils::PREF_ISIZE
, "bad type");
797 mozilla::css::Side startSide
, endSide
;
798 if (StyleVisibility()->mDirection
== NS_STYLE_DIRECTION_LTR
) {
799 startSide
= NS_SIDE_LEFT
;
800 endSide
= NS_SIDE_RIGHT
;
802 startSide
= NS_SIDE_RIGHT
;
803 endSide
= NS_SIDE_LEFT
;
806 const nsStylePadding
*stylePadding
= StylePadding();
807 const nsStyleBorder
*styleBorder
= StyleBorder();
808 const nsStyleMargin
*styleMargin
= StyleMargin();
810 // This goes at the beginning no matter how things are broken and how
811 // messy the bidi situations are, since per CSS2.1 section 8.6
812 // (implemented in bug 328168), the startSide border is always on the
814 // This frame is a first-in-flow, but it might have a previous bidi
815 // continuation, in which case that continuation should handle the startSide
817 // For box-decoration-break:clone we setup clonePBM = startPBM + endPBM and
818 // add that to each line. For box-decoration-break:slice clonePBM is zero.
819 nscoord clonePBM
= 0; // PBM = PaddingBorderMargin
820 const bool sliceBreak
=
821 styleBorder
->mBoxDecorationBreak
== NS_STYLE_BOX_DECORATION_BREAK_SLICE
;
822 if (!GetPrevContinuation()) {
824 // clamp negative calc() to 0
825 std::max(GetCoord(stylePadding
->mPadding
.Get(startSide
), 0), 0) +
826 styleBorder
->GetComputedBorderWidth(startSide
) +
827 GetCoord(styleMargin
->mMargin
.Get(startSide
), 0);
828 if (MOZ_LIKELY(sliceBreak
)) {
829 aData
->currentLine
+= startPBM
;
836 // clamp negative calc() to 0
837 std::max(GetCoord(stylePadding
->mPadding
.Get(endSide
), 0), 0) +
838 styleBorder
->GetComputedBorderWidth(endSide
) +
839 GetCoord(styleMargin
->mMargin
.Get(endSide
), 0);
840 if (MOZ_UNLIKELY(!sliceBreak
)) {
844 const nsLineList_iterator
* savedLine
= aData
->line
;
845 nsIFrame
* const savedLineContainer
= aData
->lineContainer
;
847 nsContainerFrame
*lastInFlow
;
848 for (nsContainerFrame
*nif
= this; nif
;
849 nif
= static_cast<nsContainerFrame
*>(nif
->GetNextInFlow())) {
850 if (aData
->currentLine
== 0) {
851 aData
->currentLine
= clonePBM
;
853 for (nsIFrame
*kid
= nif
->mFrames
.FirstChild(); kid
;
854 kid
= kid
->GetNextSibling()) {
855 if (aType
== nsLayoutUtils::MIN_ISIZE
)
856 kid
->AddInlineMinISize(aRenderingContext
,
857 static_cast<InlineMinISizeData
*>(aData
));
859 kid
->AddInlinePrefISize(aRenderingContext
,
860 static_cast<InlinePrefISizeData
*>(aData
));
863 // After we advance to our next-in-flow, the stored line and line container
864 // may no longer be correct. Just forget them.
865 aData
->line
= nullptr;
866 aData
->lineContainer
= nullptr;
871 aData
->line
= savedLine
;
872 aData
->lineContainer
= savedLineContainer
;
874 // This goes at the end no matter how things are broken and how
875 // messy the bidi situations are, since per CSS2.1 section 8.6
876 // (implemented in bug 328168), the endSide border is always on the
878 // We reached the last-in-flow, but it might have a next bidi
879 // continuation, in which case that continuation should handle
880 // the endSide border.
881 if (MOZ_LIKELY(!lastInFlow
->GetNextContinuation() && sliceBreak
)) {
882 aData
->currentLine
+= endPBM
;
888 nsContainerFrame::ComputeAutoSize(nsRenderingContext
*aRenderingContext
,
890 const LogicalSize
& aCBSize
,
891 nscoord aAvailableISize
,
892 const LogicalSize
& aMargin
,
893 const LogicalSize
& aBorder
,
894 const LogicalSize
& aPadding
,
897 LogicalSize
result(aWM
, 0xdeadbeef, NS_UNCONSTRAINEDSIZE
);
898 nscoord availBased
= aAvailableISize
- aMargin
.ISize(aWM
) -
899 aBorder
.ISize(aWM
) - aPadding
.ISize(aWM
);
900 // replaced elements always shrink-wrap
901 if (aShrinkWrap
|| IsFrameOfType(eReplaced
)) {
902 // don't bother setting it if the result won't be used
903 const nsStyleCoord
& inlineStyleCoord
=
904 aWM
.IsVertical() ? StylePosition()->mHeight
: StylePosition()->mWidth
;
905 if (inlineStyleCoord
.GetUnit() == eStyleUnit_Auto
) {
906 result
.ISize(aWM
) = ShrinkWidthToFit(aRenderingContext
, availBased
);
909 result
.ISize(aWM
) = availBased
;
915 * Invokes the WillReflow() function, positions the frame and its view (if
916 * requested), and then calls Reflow(). If the reflow succeeds and the child
917 * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
920 nsContainerFrame::ReflowChild(nsIFrame
* aKidFrame
,
921 nsPresContext
* aPresContext
,
922 nsHTMLReflowMetrics
& aDesiredSize
,
923 const nsHTMLReflowState
& aReflowState
,
927 nsReflowStatus
& aStatus
,
928 nsOverflowContinuationTracker
* aTracker
)
930 NS_PRECONDITION(aReflowState
.frame
== aKidFrame
, "bad reflow state");
932 // Send the WillReflow() notification, and position the child frame
933 // and its view if requested
934 aKidFrame
->WillReflow(aPresContext
);
936 if (NS_FRAME_NO_MOVE_FRAME
!= (aFlags
& NS_FRAME_NO_MOVE_FRAME
)) {
937 aKidFrame
->SetPosition(nsPoint(aX
, aY
));
940 if (0 == (aFlags
& NS_FRAME_NO_MOVE_VIEW
)) {
941 PositionFrameView(aKidFrame
);
944 // Reflow the child frame
945 aKidFrame
->Reflow(aPresContext
, aDesiredSize
, aReflowState
, aStatus
);
947 // If the child frame is complete, delete any next-in-flows,
948 // but only if the NO_DELETE_NEXT_IN_FLOW flag isn't set.
949 if (NS_FRAME_IS_FULLY_COMPLETE(aStatus
) &&
950 !(aFlags
& NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD
)) {
951 nsIFrame
* kidNextInFlow
= aKidFrame
->GetNextInFlow();
953 // Remove all of the childs next-in-flows. Make sure that we ask
954 // the right parent to do the removal (it's possible that the
955 // parent is not this because we are executing pullup code)
956 nsOverflowContinuationTracker::AutoFinish
fini(aTracker
, aKidFrame
);
957 kidNextInFlow
->GetParent()->DeleteNextInFlowChild(kidNextInFlow
, true);
964 * Position the views of |aFrame|'s descendants. A container frame
965 * should call this method if it moves a frame after |Reflow|.
968 nsContainerFrame::PositionChildViews(nsIFrame
* aFrame
)
970 if (!(aFrame
->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW
)) {
974 // Recursively walk aFrame's child frames.
975 // Process the additional child lists, but skip the popup list as the
976 // view for popups is managed by the parent. Currently only nsMenuFrame
977 // and nsPopupSetFrame have a popupList and during layout will adjust the
978 // view manually to position the popup.
979 ChildListIterator
lists(aFrame
);
980 for (; !lists
.IsDone(); lists
.Next()) {
981 if (lists
.CurrentID() == kPopupList
) {
984 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
985 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
986 // Position the frame's view (if it has one) otherwise recursively
987 // process its children
988 nsIFrame
* childFrame
= childFrames
.get();
989 if (childFrame
->HasView()) {
990 PositionFrameView(childFrame
);
992 PositionChildViews(childFrame
);
999 * The second half of frame reflow. Does the following:
1000 * - sets the frame's bounds
1001 * - sizes and positions (if requested) the frame's view. If the frame's final
1002 * position differs from the current position and the frame itself does not
1003 * have a view, then any child frames with views are positioned so they stay
1005 * - sets the view's visibility, opacity, content transparency, and clip
1006 * - invoked the DidReflow() function
1009 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
1010 * case. Also implies NS_FRAME_NO_MOVE_VIEW
1011 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
1012 * don't want to automatically sync the frame and view
1013 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
1016 nsContainerFrame::FinishReflowChild(nsIFrame
* aKidFrame
,
1017 nsPresContext
* aPresContext
,
1018 const nsHTMLReflowMetrics
& aDesiredSize
,
1019 const nsHTMLReflowState
* aReflowState
,
1024 nsPoint curOrigin
= aKidFrame
->GetPosition();
1026 if (NS_FRAME_NO_MOVE_FRAME
!= (aFlags
& NS_FRAME_NO_MOVE_FRAME
)) {
1027 aKidFrame
->SetRect(nsRect(aX
, aY
, aDesiredSize
.Width(), aDesiredSize
.Height()));
1029 aKidFrame
->SetSize(nsSize(aDesiredSize
.Width(), aDesiredSize
.Height()));
1032 if (aKidFrame
->HasView()) {
1033 nsView
* view
= aKidFrame
->GetView();
1034 // Make sure the frame's view is properly sized and positioned and has
1035 // things like opacity correct
1036 SyncFrameViewAfterReflow(aPresContext
, aKidFrame
, view
,
1037 aDesiredSize
.VisualOverflow(), aFlags
);
1040 if (!(aFlags
& NS_FRAME_NO_MOVE_VIEW
) &&
1041 (curOrigin
.x
!= aX
|| curOrigin
.y
!= aY
)) {
1042 if (!aKidFrame
->HasView()) {
1043 // If the frame has moved, then we need to make sure any child views are
1044 // correctly positioned
1045 PositionChildViews(aKidFrame
);
1049 aKidFrame
->DidReflow(aPresContext
, aReflowState
, nsDidReflowStatus::FINISHED
);
1053 nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext
* aPresContext
,
1054 const nsHTMLReflowState
& aReflowState
,
1055 nsOverflowAreas
& aOverflowRects
,
1057 nsReflowStatus
& aStatus
)
1059 NS_PRECONDITION(aPresContext
, "null pointer");
1061 nsFrameList
* overflowContainers
=
1062 GetPropTableFrames(OverflowContainersProperty());
1064 NS_ASSERTION(!(overflowContainers
&& GetPrevInFlow()
1065 && static_cast<nsContainerFrame
*>(GetPrevInFlow())
1066 ->GetPropTableFrames(ExcessOverflowContainersProperty())),
1067 "conflicting overflow containers lists");
1069 if (!overflowContainers
) {
1070 // Drain excess from previnflow
1071 nsContainerFrame
* prev
= (nsContainerFrame
*) GetPrevInFlow();
1073 nsFrameList
* excessFrames
=
1074 prev
->RemovePropTableFrames(ExcessOverflowContainersProperty());
1076 excessFrames
->ApplySetParent(this);
1077 nsContainerFrame::ReparentFrameViewList(*excessFrames
, prev
, this);
1078 overflowContainers
= excessFrames
;
1079 SetPropTableFrames(overflowContainers
, OverflowContainersProperty());
1084 // Our own excess overflow containers from a previous reflow can still be
1085 // present if our next-in-flow hasn't been reflown yet.
1086 nsFrameList
* selfExcessOCFrames
=
1087 RemovePropTableFrames(ExcessOverflowContainersProperty());
1088 if (selfExcessOCFrames
) {
1089 if (overflowContainers
) {
1090 overflowContainers
->AppendFrames(nullptr, *selfExcessOCFrames
);
1091 selfExcessOCFrames
->Delete(aPresContext
->PresShell());
1093 overflowContainers
= selfExcessOCFrames
;
1094 SetPropTableFrames(overflowContainers
, OverflowContainersProperty());
1097 if (!overflowContainers
) {
1098 return; // nothing to reflow
1101 nsOverflowContinuationTracker
tracker(this, false, false);
1102 bool shouldReflowAllKids
= aReflowState
.ShouldReflowAllKids();
1104 for (nsIFrame
* frame
= overflowContainers
->FirstChild(); frame
;
1105 frame
= frame
->GetNextSibling()) {
1106 if (frame
->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
1107 // frame's prevInFlow has moved, skip reflowing this frame;
1108 // it will get reflowed once it's been placed
1111 // If the available vertical height has changed, we need to reflow
1112 // even if the frame isn't dirty.
1113 if (shouldReflowAllKids
|| NS_SUBTREE_DIRTY(frame
)) {
1115 nsIFrame
* prevInFlow
= frame
->GetPrevInFlow();
1116 NS_ASSERTION(prevInFlow
,
1117 "overflow container frame must have a prev-in-flow");
1118 NS_ASSERTION(frame
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
,
1119 "overflow container frame must have overflow container bit set");
1120 nsRect prevRect
= prevInFlow
->GetRect();
1122 // Initialize reflow params
1123 WritingMode wm
= frame
->GetWritingMode();
1124 LogicalSize
availSpace(wm
, LogicalSize(wm
, prevRect
.Size()).ISize(wm
),
1125 aReflowState
.AvailableSize(wm
).BSize(wm
));
1126 nsHTMLReflowMetrics
desiredSize(aReflowState
);
1127 nsHTMLReflowState
frameState(aPresContext
, aReflowState
,
1129 nsReflowStatus frameStatus
;
1132 ReflowChild(frame
, aPresContext
, desiredSize
, frameState
,
1133 prevRect
.x
, 0, aFlags
, frameStatus
, &tracker
);
1134 //XXXfr Do we need to override any shrinkwrap effects here?
1135 // e.g. desiredSize.Width() = prevRect.width;
1136 FinishReflowChild(frame
, aPresContext
, desiredSize
, &frameState
,
1137 prevRect
.x
, 0, aFlags
);
1139 // Handle continuations
1140 if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus
)) {
1141 if (frame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
1142 // Abspos frames can't cause their parent to be incomplete,
1143 // only overflow incomplete.
1144 NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus
);
1147 NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus
),
1148 "overflow container frames can't be incomplete, only overflow-incomplete");
1151 // Acquire a next-in-flow, creating it if necessary
1152 nsIFrame
* nif
= frame
->GetNextInFlow();
1154 NS_ASSERTION(frameStatus
& NS_FRAME_REFLOW_NEXTINFLOW
,
1155 "Someone forgot a REFLOW_NEXTINFLOW flag");
1156 nif
= aPresContext
->PresShell()->FrameConstructor()->
1157 CreateContinuingFrame(aPresContext
, frame
, this);
1159 else if (!(nif
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1160 // used to be a normal next-in-flow; steal it from the child list
1161 nsresult rv
= nif
->GetParent()->StealFrame(nif
);
1162 if (NS_FAILED(rv
)) {
1167 tracker
.Insert(nif
, frameStatus
);
1169 NS_MergeReflowStatusInto(&aStatus
, frameStatus
);
1170 // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
1171 // but we have some unsplittable frames that, when taller than
1172 // availableHeight will push zero-height content into a next-in-flow.
1175 tracker
.Skip(frame
, aStatus
);
1176 if (aReflowState
.mFloatManager
)
1177 nsBlockFrame::RecoverFloatsFor(frame
, *aReflowState
.mFloatManager
);
1179 ConsiderChildOverflow(aOverflowRects
, frame
);
1184 nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder
* aBuilder
,
1185 const nsRect
& aDirtyRect
,
1186 const nsDisplayListSet
& aLists
)
1188 nsFrameList
* overflowconts
= GetPropTableFrames(OverflowContainersProperty());
1189 if (overflowconts
) {
1190 for (nsIFrame
* frame
= overflowconts
->FirstChild(); frame
;
1191 frame
= frame
->GetNextSibling()) {
1192 BuildDisplayListForChild(aBuilder
, frame
, aDirtyRect
, aLists
);
1198 TryRemoveFrame(nsIFrame
* aFrame
, FramePropertyTable
* aPropTable
,
1199 const FramePropertyDescriptor
* aProp
, nsIFrame
* aChildToRemove
)
1201 nsFrameList
* list
= static_cast<nsFrameList
*>(aPropTable
->Get(aFrame
, aProp
));
1202 if (list
&& list
->StartRemoveFrame(aChildToRemove
)) {
1203 // aChildToRemove *may* have been removed from this list.
1204 if (list
->IsEmpty()) {
1205 aPropTable
->Remove(aFrame
, aProp
);
1206 list
->Delete(aFrame
->PresContext()->PresShell());
1214 nsContainerFrame::StealFrame(nsIFrame
* aChild
,
1218 if (!mFrames
.ContainsFrame(aChild
)) {
1219 nsFrameList
* list
= GetOverflowFrames();
1220 if (!list
|| !list
->ContainsFrame(aChild
)) {
1221 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
1222 list
= static_cast<nsFrameList
*>(
1223 propTable
->Get(this, OverflowContainersProperty()));
1224 if (!list
|| !list
->ContainsFrame(aChild
)) {
1225 list
= static_cast<nsFrameList
*>(
1226 propTable
->Get(this, ExcessOverflowContainersProperty()));
1227 MOZ_ASSERT(list
&& list
->ContainsFrame(aChild
), "aChild isn't our child"
1228 " or on a frame list not supported by StealFrame");
1235 if ((aChild
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)
1237 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
1238 // Try removing from the overflow container list.
1239 removed
= ::TryRemoveFrame(this, propTable
, OverflowContainersProperty(),
1242 // It must be in the excess overflow container list.
1243 removed
= ::TryRemoveFrame(this, propTable
,
1244 ExcessOverflowContainersProperty(),
1248 removed
= mFrames
.StartRemoveFrame(aChild
);
1250 // We didn't find the child in our principal child list.
1251 // Maybe it's on the overflow list?
1252 nsFrameList
* frameList
= GetOverflowFrames();
1254 removed
= frameList
->ContinueRemoveFrame(aChild
);
1255 if (frameList
->IsEmpty()) {
1256 DestroyOverflowList();
1262 NS_POSTCONDITION(removed
, "StealFrame: can't find aChild");
1263 return removed
? NS_OK
: NS_ERROR_UNEXPECTED
;
1267 nsContainerFrame::StealFramesAfter(nsIFrame
* aChild
)
1269 NS_ASSERTION(!aChild
||
1270 !(aChild
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
),
1271 "StealFramesAfter doesn't handle overflow containers");
1272 NS_ASSERTION(GetType() != nsGkAtoms::blockFrame
, "unexpected call");
1275 nsFrameList
copy(mFrames
);
1280 for (nsFrameList::FrameLinkEnumerator
iter(mFrames
); !iter
.AtEnd();
1282 if (iter
.PrevFrame() == aChild
) {
1283 return mFrames
.ExtractTail(iter
);
1287 // We didn't find the child in the principal child list.
1288 // Maybe it's on the overflow list?
1289 nsFrameList
* overflowFrames
= GetOverflowFrames();
1290 if (overflowFrames
) {
1291 for (nsFrameList::FrameLinkEnumerator
iter(*overflowFrames
); !iter
.AtEnd();
1293 if (iter
.PrevFrame() == aChild
) {
1294 return overflowFrames
->ExtractTail(iter
);
1299 NS_ERROR("StealFramesAfter: can't find aChild");
1300 return nsFrameList::EmptyList();
1304 * Create a next-in-flow for aFrame. Will return the newly created
1305 * frame in aNextInFlowResult <b>if and only if</b> a new frame is
1306 * created; otherwise nullptr is returned in aNextInFlowResult.
1309 nsContainerFrame::CreateNextInFlow(nsIFrame
* aFrame
,
1310 nsIFrame
*& aNextInFlowResult
)
1312 NS_PRECONDITION(GetType() != nsGkAtoms::blockFrame
,
1313 "you should have called nsBlockFrame::CreateContinuationFor instead");
1314 NS_PRECONDITION(mFrames
.ContainsFrame(aFrame
), "expected an in-flow child frame");
1316 nsPresContext
* pc
= PresContext();
1317 aNextInFlowResult
= nullptr;
1319 nsIFrame
* nextInFlow
= aFrame
->GetNextInFlow();
1320 if (nullptr == nextInFlow
) {
1321 // Create a continuation frame for the child frame and insert it
1322 // into our child list.
1323 nextInFlow
= pc
->PresShell()->FrameConstructor()->
1324 CreateContinuingFrame(pc
, aFrame
, this);
1325 mFrames
.InsertFrame(nullptr, aFrame
, nextInFlow
);
1327 NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES
,
1328 ("nsContainerFrame::CreateNextInFlow: frame=%p nextInFlow=%p",
1329 aFrame
, nextInFlow
));
1331 aNextInFlowResult
= nextInFlow
;
1337 * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
1341 nsContainerFrame::DeleteNextInFlowChild(nsIFrame
* aNextInFlow
,
1342 bool aDeletingEmptyFrames
)
1345 nsIFrame
* prevInFlow
= aNextInFlow
->GetPrevInFlow();
1347 NS_PRECONDITION(prevInFlow
, "bad prev-in-flow");
1349 // If the next-in-flow has a next-in-flow then delete it, too (and
1350 // delete it first).
1351 // Do this in a loop so we don't overflow the stack for frames
1352 // with very many next-in-flows
1353 nsIFrame
* nextNextInFlow
= aNextInFlow
->GetNextInFlow();
1354 if (nextNextInFlow
) {
1355 nsAutoTArray
<nsIFrame
*, 8> frames
;
1356 for (nsIFrame
* f
= nextNextInFlow
; f
; f
= f
->GetNextInFlow()) {
1357 frames
.AppendElement(f
);
1359 for (int32_t i
= frames
.Length() - 1; i
>= 0; --i
) {
1360 nsIFrame
* delFrame
= frames
.ElementAt(i
);
1361 delFrame
->GetParent()->
1362 DeleteNextInFlowChild(delFrame
, aDeletingEmptyFrames
);
1366 // Take the next-in-flow out of the parent's child list
1367 DebugOnly
<nsresult
> rv
= StealFrame(aNextInFlow
);
1368 NS_ASSERTION(NS_SUCCEEDED(rv
), "StealFrame failure");
1371 if (aDeletingEmptyFrames
) {
1372 nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow
);
1376 // Delete the next-in-flow frame and its descendants. This will also
1377 // remove it from its next-in-flow/prev-in-flow chain.
1378 aNextInFlow
->Destroy();
1380 NS_POSTCONDITION(!prevInFlow
->GetNextInFlow(), "non null next-in-flow");
1384 * Set the frames on the overflow list
1387 nsContainerFrame::SetOverflowFrames(const nsFrameList
& aOverflowFrames
)
1389 NS_PRECONDITION(aOverflowFrames
.NotEmpty(), "Shouldn't be called");
1391 nsPresContext
* pc
= PresContext();
1392 nsFrameList
* newList
= new (pc
->PresShell()) nsFrameList(aOverflowFrames
);
1394 pc
->PropertyTable()->Set(this, OverflowProperty(), newList
);
1398 nsContainerFrame::GetPropTableFrames(const FramePropertyDescriptor
* aProperty
) const
1400 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
1401 return static_cast<nsFrameList
*>(propTable
->Get(this, aProperty
));
1405 nsContainerFrame::RemovePropTableFrames(const FramePropertyDescriptor
* aProperty
)
1407 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
1408 return static_cast<nsFrameList
*>(propTable
->Remove(this, aProperty
));
1412 nsContainerFrame::SetPropTableFrames(nsFrameList
* aFrameList
,
1413 const FramePropertyDescriptor
* aProperty
)
1415 NS_PRECONDITION(aProperty
&& aFrameList
, "null ptr");
1417 (aProperty
!= nsContainerFrame::OverflowContainersProperty() &&
1418 aProperty
!= nsContainerFrame::ExcessOverflowContainersProperty()) ||
1419 IsFrameOfType(nsIFrame::eCanContainOverflowContainers
),
1420 "this type of frame can't have overflow containers");
1421 MOZ_ASSERT(!GetPropTableFrames(aProperty
));
1422 PresContext()->PropertyTable()->Set(this, aProperty
, aFrameList
);
1426 * Push aFromChild and its next siblings to the next-in-flow. Change the
1427 * geometric parent of each frame that's pushed. If there is no next-in-flow
1428 * the frames are placed on the overflow list (and the geometric parent is
1431 * Updates the next-in-flow's child count. Does <b>not</b> update the
1432 * pusher's child count.
1434 * @param aFromChild the first child frame to push. It is disconnected from
1436 * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's
1437 * an error to push a parent's first child frame
1440 nsContainerFrame::PushChildren(nsIFrame
* aFromChild
,
1441 nsIFrame
* aPrevSibling
)
1443 NS_PRECONDITION(aFromChild
, "null pointer");
1444 NS_PRECONDITION(aPrevSibling
, "pushing first child");
1445 NS_PRECONDITION(aPrevSibling
->GetNextSibling() == aFromChild
, "bad prev sibling");
1447 // Disconnect aFromChild from its previous sibling
1448 nsFrameList tail
= mFrames
.RemoveFramesAfter(aPrevSibling
);
1450 nsContainerFrame
* nextInFlow
=
1451 static_cast<nsContainerFrame
*>(GetNextInFlow());
1453 // XXX This is not a very good thing to do. If it gets removed
1454 // then remove the copy of this routine that doesn't do this from
1456 // When pushing and pulling frames we need to check for whether any
1457 // views need to be reparented.
1458 for (nsIFrame
* f
= aFromChild
; f
; f
= f
->GetNextSibling()) {
1459 nsContainerFrame::ReparentFrameView(f
, this, nextInFlow
);
1461 nextInFlow
->mFrames
.InsertFrames(nextInFlow
, nullptr, tail
);
1464 // Add the frames to our overflow list
1465 SetOverflowFrames(tail
);
1470 * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
1471 * the receiver's overflow list) to the child list.
1473 * Updates this frame's child count and content mapping.
1475 * @return true if any frames were moved and false otherwise
1478 nsContainerFrame::MoveOverflowToChildList()
1480 bool result
= false;
1482 // Check for an overflow list with our prev-in-flow
1483 nsContainerFrame
* prevInFlow
= (nsContainerFrame
*)GetPrevInFlow();
1484 if (nullptr != prevInFlow
) {
1485 AutoFrameListPtr
prevOverflowFrames(PresContext(),
1486 prevInFlow
->StealOverflowFrames());
1487 if (prevOverflowFrames
) {
1488 // Tables are special; they can have repeated header/footer
1489 // frames on mFrames at this point.
1490 NS_ASSERTION(mFrames
.IsEmpty() || GetType() == nsGkAtoms::tableFrame
,
1491 "bad overflow list");
1492 // When pushing and pulling frames we need to check for whether any
1493 // views need to be reparented.
1494 nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames
,
1496 mFrames
.AppendFrames(this, *prevOverflowFrames
);
1501 // It's also possible that we have an overflow list for ourselves.
1502 return DrainSelfOverflowList() || result
;
1506 nsContainerFrame::DrainSelfOverflowList()
1508 AutoFrameListPtr
overflowFrames(PresContext(), StealOverflowFrames());
1509 if (overflowFrames
) {
1510 NS_ASSERTION(mFrames
.NotEmpty(), "overflow list w/o frames");
1511 mFrames
.AppendFrames(nullptr, *overflowFrames
);
1517 nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsContainerFrame
* aFrame
,
1518 bool aWalkOOFFrames
,
1519 bool aSkipOverflowContainerChildren
)
1520 : mOverflowContList(nullptr),
1521 mPrevOverflowCont(nullptr),
1524 mSkipOverflowContainerChildren(aSkipOverflowContainerChildren
),
1525 mWalkOOFFrames(aWalkOOFFrames
)
1527 NS_PRECONDITION(aFrame
, "null frame pointer");
1528 SetupOverflowContList();
1532 nsOverflowContinuationTracker::SetupOverflowContList()
1534 NS_PRECONDITION(mParent
, "null frame pointer");
1535 NS_PRECONDITION(!mOverflowContList
, "already have list");
1536 nsContainerFrame
* nif
=
1537 static_cast<nsContainerFrame
*>(mParent
->GetNextInFlow());
1539 mOverflowContList
= nif
->GetPropTableFrames(
1540 nsContainerFrame::OverflowContainersProperty());
1541 if (mOverflowContList
) {
1546 if (!mOverflowContList
) {
1547 mOverflowContList
= mParent
->GetPropTableFrames(
1548 nsContainerFrame::ExcessOverflowContainersProperty());
1549 if (mOverflowContList
) {
1556 * Helper function to walk past overflow continuations whose prev-in-flow
1557 * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
1560 nsOverflowContinuationTracker::SetUpListWalker()
1562 NS_ASSERTION(!mSentry
&& !mPrevOverflowCont
,
1563 "forgot to reset mSentry or mPrevOverflowCont");
1564 if (mOverflowContList
) {
1565 nsIFrame
* cur
= mOverflowContList
->FirstChild();
1566 if (mSkipOverflowContainerChildren
) {
1567 while (cur
&& (cur
->GetPrevInFlow()->GetStateBits()
1568 & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1569 mPrevOverflowCont
= cur
;
1570 cur
= cur
->GetNextSibling();
1572 while (cur
&& (!(cur
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
1573 == mWalkOOFFrames
)) {
1574 mPrevOverflowCont
= cur
;
1575 cur
= cur
->GetNextSibling();
1579 mSentry
= cur
->GetPrevInFlow();
1585 * Helper function to step forward through the overflow continuations list.
1586 * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
1587 * as appropriate. May only be called when we have already set up an
1588 * mOverflowContList; mOverflowContList cannot be null.
1591 nsOverflowContinuationTracker::StepForward()
1593 NS_PRECONDITION(mOverflowContList
, "null list");
1596 if (mPrevOverflowCont
) {
1597 mPrevOverflowCont
= mPrevOverflowCont
->GetNextSibling();
1600 mPrevOverflowCont
= mOverflowContList
->FirstChild();
1603 // Skip over oof or non-oof frames as appropriate
1604 if (mSkipOverflowContainerChildren
) {
1605 nsIFrame
* cur
= mPrevOverflowCont
->GetNextSibling();
1606 while (cur
&& (!(cur
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
1607 == mWalkOOFFrames
)) {
1608 mPrevOverflowCont
= cur
;
1609 cur
= cur
->GetNextSibling();
1613 // Set up the sentry
1614 mSentry
= (mPrevOverflowCont
->GetNextSibling())
1615 ? mPrevOverflowCont
->GetNextSibling()->GetPrevInFlow()
1620 nsOverflowContinuationTracker::Insert(nsIFrame
* aOverflowCont
,
1621 nsReflowStatus
& aReflowStatus
)
1623 NS_PRECONDITION(aOverflowCont
, "null frame pointer");
1624 NS_PRECONDITION(!mSkipOverflowContainerChildren
|| mWalkOOFFrames
==
1625 !!(aOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
),
1626 "shouldn't insert frame that doesn't match walker type");
1627 NS_PRECONDITION(aOverflowCont
->GetPrevInFlow(),
1628 "overflow containers must have a prev-in-flow");
1629 nsresult rv
= NS_OK
;
1630 bool reparented
= false;
1631 nsPresContext
* presContext
= aOverflowCont
->PresContext();
1632 bool addToList
= !mSentry
|| aOverflowCont
!= mSentry
->GetNextInFlow();
1634 // If we have a list and aOverflowCont is already in it then don't try to
1636 if (addToList
&& aOverflowCont
->GetParent() == mParent
&&
1637 (aOverflowCont
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) &&
1638 mOverflowContList
&& mOverflowContList
->ContainsFrame(aOverflowCont
)) {
1640 mPrevOverflowCont
= aOverflowCont
->GetPrevSibling();
1644 if (aOverflowCont
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) {
1645 // aOverflowCont is in some other overflow container list,
1647 NS_ASSERTION(!(mOverflowContList
&&
1648 mOverflowContList
->ContainsFrame(aOverflowCont
)),
1649 "overflow containers out of order");
1650 rv
= aOverflowCont
->GetParent()->StealFrame(aOverflowCont
);
1651 NS_ENSURE_SUCCESS(rv
, rv
);
1654 aOverflowCont
->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER
);
1656 if (!mOverflowContList
) {
1657 mOverflowContList
= new (presContext
->PresShell()) nsFrameList();
1658 mParent
->SetPropTableFrames(mOverflowContList
,
1659 nsContainerFrame::ExcessOverflowContainersProperty());
1662 if (aOverflowCont
->GetParent() != mParent
) {
1663 nsContainerFrame::ReparentFrameView(aOverflowCont
,
1664 aOverflowCont
->GetParent(),
1669 // If aOverflowCont has a prev/next-in-flow that might be in
1670 // mOverflowContList we need to find it and insert after/before it to
1671 // maintain the order amongst next-in-flows in this list.
1672 nsIFrame
* pif
= aOverflowCont
->GetPrevInFlow();
1673 nsIFrame
* nif
= aOverflowCont
->GetNextInFlow();
1674 if ((pif
&& pif
->GetParent() == mParent
&& pif
!= mPrevOverflowCont
) ||
1675 (nif
&& nif
->GetParent() == mParent
&& mPrevOverflowCont
)) {
1676 for (nsFrameList::Enumerator
e(*mOverflowContList
); !e
.AtEnd(); e
.Next()) {
1677 nsIFrame
* f
= e
.get();
1679 mPrevOverflowCont
= pif
;
1683 mPrevOverflowCont
= f
->GetPrevSibling();
1689 mOverflowContList
->InsertFrame(mParent
, mPrevOverflowCont
, aOverflowCont
);
1690 aReflowStatus
|= NS_FRAME_REFLOW_NEXTINFLOW
;
1693 // If we need to reflow it, mark it dirty
1694 if (aReflowStatus
& NS_FRAME_REFLOW_NEXTINFLOW
)
1695 aOverflowCont
->AddStateBits(NS_FRAME_IS_DIRTY
);
1697 // It's in our list, just step forward
1699 NS_ASSERTION(mPrevOverflowCont
== aOverflowCont
||
1700 (mSkipOverflowContainerChildren
&&
1701 (mPrevOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) !=
1702 (aOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)),
1703 "OverflowContTracker in unexpected state");
1706 // Convert all non-overflow-container continuations of aOverflowCont
1707 // into overflow containers and move them to our overflow
1708 // tracker. This preserves the invariant that the next-continuations
1709 // of an overflow container are also overflow containers.
1710 nsIFrame
* f
= aOverflowCont
->GetNextContinuation();
1711 if (f
&& (!(f
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) ||
1712 (!reparented
&& f
->GetParent() == mParent
) ||
1713 (reparented
&& f
->GetParent() != mParent
))) {
1714 if (!(f
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1715 rv
= f
->GetParent()->StealFrame(f
);
1716 NS_ENSURE_SUCCESS(rv
, rv
);
1718 Insert(f
, aReflowStatus
);
1725 nsOverflowContinuationTracker::BeginFinish(nsIFrame
* aChild
)
1727 NS_PRECONDITION(aChild
, "null ptr");
1728 NS_PRECONDITION(aChild
->GetNextInFlow(),
1729 "supposed to call Finish *before* deleting next-in-flow!");
1730 for (nsIFrame
* f
= aChild
; f
; f
= f
->GetNextInFlow()) {
1731 // We'll update these in EndFinish after the next-in-flows are gone.
1732 if (f
== mPrevOverflowCont
) {
1734 mPrevOverflowCont
= nullptr;
1745 nsOverflowContinuationTracker::EndFinish(nsIFrame
* aChild
)
1747 if (!mOverflowContList
) {
1750 // Forget mOverflowContList if it was deleted.
1751 nsPresContext
* pc
= aChild
->PresContext();
1752 FramePropertyTable
* propTable
= pc
->PropertyTable();
1753 nsFrameList
* eoc
= static_cast<nsFrameList
*>(propTable
->Get(mParent
,
1754 nsContainerFrame::ExcessOverflowContainersProperty()));
1755 if (eoc
!= mOverflowContList
) {
1756 nsFrameList
* oc
= static_cast<nsFrameList
*>(propTable
->Get(mParent
,
1757 nsContainerFrame::OverflowContainersProperty()));
1758 if (oc
!= mOverflowContList
) {
1759 // mOverflowContList was deleted
1760 mPrevOverflowCont
= nullptr;
1762 mParent
= aChild
->GetParent();
1763 mOverflowContList
= nullptr;
1764 SetupOverflowContList();
1768 // The list survived, update mSentry if needed.
1770 if (!mPrevOverflowCont
) {
1773 mozilla::AutoRestore
<nsIFrame
*> saved(mPrevOverflowCont
);
1774 // step backward to make StepForward() use our current mPrevOverflowCont
1775 mPrevOverflowCont
= mPrevOverflowCont
->GetPrevSibling();
1781 /////////////////////////////////////////////////////////////////////////////
1784 #ifdef DEBUG_FRAME_DUMP
1786 nsContainerFrame::List(FILE* out
, const char* aPrefix
, uint32_t aFlags
) const
1789 ListGeneric(str
, aPrefix
, aFlags
);
1791 // Output the children
1792 bool outputOneList
= false;
1793 ChildListIterator
lists(this);
1794 for (; !lists
.IsDone(); lists
.Next()) {
1795 if (outputOneList
) {
1798 if (lists
.CurrentID() != kPrincipalList
) {
1799 if (!outputOneList
) {
1803 str
+= nsPrintfCString("%s %p ", mozilla::layout::ChildListName(lists
.CurrentID()),
1804 &GetChildList(lists
.CurrentID()));
1806 fprintf_stderr(out
, "%s<\n", str
.get());
1808 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
1809 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
1810 nsIFrame
* kid
= childFrames
.get();
1811 // Verify the child frame's parent frame pointer is correct
1812 NS_ASSERTION(kid
->GetParent() == this, "bad parent frame pointer");
1814 // Have the child frame list
1815 nsCString
pfx(aPrefix
);
1817 kid
->List(out
, pfx
.get(), aFlags
);
1819 fprintf_stderr(out
, "%s>\n", aPrefix
);
1820 outputOneList
= true;
1823 if (!outputOneList
) {
1824 fprintf_stderr(out
, "%s<>\n", str
.get());