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");
90 if (MOZ_UNLIKELY(aFrameList
.IsEmpty())) {
94 DrainSelfOverflowList(); // ensure the last frame is in mFrames
95 mFrames
.AppendFrames(this, aFrameList
);
97 if (aListID
!= kNoReflowPrincipalList
) {
98 PresContext()->PresShell()->
99 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
100 NS_FRAME_HAS_DIRTY_CHILDREN
);
105 nsContainerFrame::InsertFrames(ChildListID aListID
,
106 nsIFrame
* aPrevFrame
,
107 nsFrameList
& aFrameList
)
109 MOZ_ASSERT(aListID
== kPrincipalList
|| aListID
== kNoReflowPrincipalList
,
110 "unexpected child list");
111 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
112 "inserting after sibling frame with different parent");
114 if (MOZ_UNLIKELY(aFrameList
.IsEmpty())) {
118 DrainSelfOverflowList(); // ensure aPrevFrame is in mFrames
119 mFrames
.InsertFrames(this, aPrevFrame
, aFrameList
);
121 if (aListID
!= kNoReflowPrincipalList
) {
122 PresContext()->PresShell()->
123 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
124 NS_FRAME_HAS_DIRTY_CHILDREN
);
129 nsContainerFrame::RemoveFrame(ChildListID aListID
,
132 MOZ_ASSERT(aListID
== kPrincipalList
|| aListID
== kNoReflowPrincipalList
,
133 "unexpected child list");
135 // Loop and destroy aOldFrame and all of its continuations.
136 // Request a reflow on the parent frames involved unless we were explicitly
137 // told not to (kNoReflowPrincipalList).
138 bool generateReflowCommand
= true;
139 if (kNoReflowPrincipalList
== aListID
) {
140 generateReflowCommand
= false;
142 nsIPresShell
* shell
= PresContext()->PresShell();
143 nsContainerFrame
* lastParent
= nullptr;
145 nsIFrame
* oldFrameNextContinuation
= aOldFrame
->GetNextContinuation();
146 nsContainerFrame
* parent
= aOldFrame
->GetParent();
147 // Please note that 'parent' may not actually be where 'aOldFrame' lives.
148 // We really MUST use StealFrame() and nothing else here.
149 // @see nsInlineFrame::StealFrame for details.
150 parent
->StealFrame(aOldFrame
, true);
151 aOldFrame
->Destroy();
152 aOldFrame
= oldFrameNextContinuation
;
153 if (parent
!= lastParent
&& generateReflowCommand
) {
154 shell
->FrameNeedsReflow(parent
, nsIPresShell::eTreeChange
,
155 NS_FRAME_HAS_DIRTY_CHILDREN
);
162 nsContainerFrame::DestroyAbsoluteFrames(nsIFrame
* aDestructRoot
)
164 if (IsAbsoluteContainer()) {
165 GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot
);
166 MarkAsNotAbsoluteContainingBlock();
171 nsContainerFrame::SafelyDestroyFrameListProp(nsIFrame
* aDestructRoot
,
172 nsIPresShell
* aPresShell
,
173 FramePropertyTable
* aPropTable
,
174 const FramePropertyDescriptor
* aProp
)
176 // Note that the last frame can be removed through another route and thus
177 // delete the property -- that's why we fetch the property again before
178 // removing each frame rather than fetching it once and iterating the list.
179 while (nsFrameList
* frameList
=
180 static_cast<nsFrameList
*>(aPropTable
->Get(this, aProp
))) {
181 nsIFrame
* frame
= frameList
->RemoveFirstChild();
182 if (MOZ_LIKELY(frame
)) {
183 frame
->DestroyFrom(aDestructRoot
);
185 aPropTable
->Remove(this, aProp
);
186 frameList
->Delete(aPresShell
);
193 nsContainerFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
195 // Prevent event dispatch during destruction.
197 GetView()->SetFrame(nullptr);
200 DestroyAbsoluteFrames(aDestructRoot
);
202 // Destroy frames on the principal child list.
203 mFrames
.DestroyFramesFrom(aDestructRoot
);
205 // Destroy frames on the auxiliary frame lists and delete the lists.
206 nsPresContext
* pc
= PresContext();
207 nsIPresShell
* shell
= pc
->PresShell();
208 FramePropertyTable
* props
= pc
->PropertyTable();
209 SafelyDestroyFrameListProp(aDestructRoot
, shell
, props
, OverflowProperty());
211 MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers
) ||
212 !(props
->Get(this, nsContainerFrame::OverflowContainersProperty()) ||
213 props
->Get(this, nsContainerFrame::ExcessOverflowContainersProperty())),
214 "this type of frame should't have overflow containers");
216 SafelyDestroyFrameListProp(aDestructRoot
, shell
, props
,
217 OverflowContainersProperty());
218 SafelyDestroyFrameListProp(aDestructRoot
, shell
, props
,
219 ExcessOverflowContainersProperty());
221 nsSplittableFrame::DestroyFrom(aDestructRoot
);
224 /////////////////////////////////////////////////////////////////////////////
225 // Child frame enumeration
228 nsContainerFrame::GetChildList(ChildListID aListID
) const
230 // We only know about the principal child list and the overflow lists.
234 case kOverflowList
: {
235 nsFrameList
* list
= GetOverflowFrames();
236 return list
? *list
: nsFrameList::EmptyList();
238 case kOverflowContainersList
: {
239 nsFrameList
* list
= GetPropTableFrames(OverflowContainersProperty());
240 return list
? *list
: nsFrameList::EmptyList();
242 case kExcessOverflowContainersList
: {
244 GetPropTableFrames(ExcessOverflowContainersProperty());
245 return list
? *list
: nsFrameList::EmptyList();
248 return nsSplittableFrame::GetChildList(aListID
);
252 static void AppendIfNonempty(const nsIFrame
* aFrame
,
253 FramePropertyTable
* aPropTable
,
254 const FramePropertyDescriptor
* aProperty
,
255 nsTArray
<nsIFrame::ChildList
>* aLists
,
256 nsIFrame::ChildListID aListID
)
258 nsFrameList
* list
= static_cast<nsFrameList
*>(
259 aPropTable
->Get(aFrame
, aProperty
));
261 list
->AppendIfNonempty(aLists
, aListID
);
266 nsContainerFrame::GetChildLists(nsTArray
<ChildList
>* aLists
) const
268 mFrames
.AppendIfNonempty(aLists
, kPrincipalList
);
269 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
270 ::AppendIfNonempty(this, propTable
, OverflowProperty(),
271 aLists
, kOverflowList
);
272 if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers
)) {
273 ::AppendIfNonempty(this, propTable
, OverflowContainersProperty(),
274 aLists
, kOverflowContainersList
);
275 ::AppendIfNonempty(this, propTable
, ExcessOverflowContainersProperty(),
276 aLists
, kExcessOverflowContainersList
);
278 nsSplittableFrame::GetChildLists(aLists
);
281 /////////////////////////////////////////////////////////////////////////////
285 nsContainerFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
286 const nsRect
& aDirtyRect
,
287 const nsDisplayListSet
& aLists
)
289 DisplayBorderBackgroundOutline(aBuilder
, aLists
);
291 BuildDisplayListForNonBlockChildren(aBuilder
, aDirtyRect
, aLists
);
295 nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder
* aBuilder
,
296 const nsRect
& aDirtyRect
,
297 const nsDisplayListSet
& aLists
,
300 nsIFrame
* kid
= mFrames
.FirstChild();
301 // Put each child's background directly onto the content list
302 nsDisplayListSet
set(aLists
, aLists
.Content());
303 // The children should be in content order
305 BuildDisplayListForChild(aBuilder
, kid
, aDirtyRect
, set
, aFlags
);
306 kid
= kid
->GetNextSibling();
311 nsContainerFrame::ChildIsDirty(nsIFrame
* aChild
)
313 NS_ASSERTION(NS_SUBTREE_DIRTY(aChild
), "child isn't actually dirty");
315 AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN
);
319 nsContainerFrame::IsLeaf() const
324 nsIFrame::FrameSearchResult
325 nsContainerFrame::PeekOffsetNoAmount(bool aForward
, int32_t* aOffset
)
327 NS_ASSERTION (aOffset
&& *aOffset
<= 1, "aOffset out of range");
328 // Don't allow the caret to stay in an empty (leaf) container frame.
329 return CONTINUE_EMPTY
;
332 nsIFrame::FrameSearchResult
333 nsContainerFrame::PeekOffsetCharacter(bool aForward
, int32_t* aOffset
,
334 bool aRespectClusters
)
336 NS_ASSERTION (aOffset
&& *aOffset
<= 1, "aOffset out of range");
337 // Don't allow the caret to stay in an empty (leaf) container frame.
338 return CONTINUE_EMPTY
;
341 /////////////////////////////////////////////////////////////////////////////
342 // Helper member functions
345 ReparentFrameViewTo(nsIFrame
* aFrame
,
346 nsViewManager
* aViewManager
,
347 nsView
* aNewParentView
,
348 nsView
* aOldParentView
)
351 // XXX What to do about placeholder views for "position: fixed" elements?
352 // They should be reparented too.
354 // Does aFrame have a view?
355 if (aFrame
->HasView()) {
357 if (aFrame
->GetType() == nsGkAtoms::menuPopupFrame
) {
358 // This view must be parented by the root view, don't reparent it.
362 nsView
* view
= aFrame
->GetView();
363 // Verify that the current parent view is what we think it is
364 //nsView* parentView;
365 //NS_ASSERTION(parentView == aOldParentView, "unexpected parent view");
367 aViewManager
->RemoveChild(view
);
369 // The view will remember the Z-order and other attributes that have been set on it.
370 nsView
* insertBefore
= nsLayoutUtils::FindSiblingViewFor(aNewParentView
, aFrame
);
371 aViewManager
->InsertChild(aNewParentView
, view
, insertBefore
, insertBefore
!= nullptr);
373 nsIFrame::ChildListIterator
lists(aFrame
);
374 for (; !lists
.IsDone(); lists
.Next()) {
375 // Iterate the child frames, and check each child frame to see if it has
377 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
378 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
379 ReparentFrameViewTo(childFrames
.get(), aViewManager
,
380 aNewParentView
, aOldParentView
);
389 nsContainerFrame::CreateViewForFrame(nsIFrame
* aFrame
,
392 if (aFrame
->HasView()) {
396 // If we don't yet have a view, see if we need a view
397 if (!aForce
&& !aFrame
->NeedsView()) {
402 nsView
* parentView
= aFrame
->GetParent()->GetClosestView();
403 NS_ASSERTION(parentView
, "no parent with view");
405 nsViewManager
* viewManager
= parentView
->GetViewManager();
406 NS_ASSERTION(viewManager
, "null view manager");
409 nsView
* view
= viewManager
->CreateView(aFrame
->GetRect(), parentView
);
411 SyncFrameViewProperties(aFrame
->PresContext(), aFrame
, nullptr, view
);
413 nsView
* insertBefore
= nsLayoutUtils::FindSiblingViewFor(parentView
, aFrame
);
414 // we insert this view 'above' the insertBefore view, unless insertBefore is null,
415 // in which case we want to call with aAbove == false to insert at the beginning
417 viewManager
->InsertChild(parentView
, view
, insertBefore
, insertBefore
!= nullptr);
419 // REVIEW: Don't create a widget for fixed-pos elements anymore.
420 // ComputeRepaintRegionForCopy will calculate the right area to repaint
422 // Reparent views on any child frames (or their descendants) to this
423 // view. We can just call ReparentFrameViewTo on this frame because
424 // we know this frame has no view, so it will crawl the children. Also,
425 // we know that any descendants with views must have 'parentView' as their
427 ReparentFrameViewTo(aFrame
, viewManager
, view
, parentView
);
430 aFrame
->SetView(view
);
432 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS
,
433 ("nsContainerFrame::CreateViewForFrame: frame=%p view=%p",
438 * Position the view associated with |aKidFrame|, if there is one. A
439 * container frame should call this method after positioning a frame,
440 * but before |Reflow|.
443 nsContainerFrame::PositionFrameView(nsIFrame
* aKidFrame
)
445 nsIFrame
* parentFrame
= aKidFrame
->GetParent();
446 if (!aKidFrame
->HasView() || !parentFrame
)
449 nsView
* view
= aKidFrame
->GetView();
450 nsViewManager
* vm
= view
->GetViewManager();
452 nsView
* ancestorView
= parentFrame
->GetClosestView(&pt
);
454 if (ancestorView
!= view
->GetParent()) {
455 NS_ASSERTION(ancestorView
== view
->GetParent()->GetParent(),
456 "Allowed only one anonymous view between frames");
457 // parentFrame is responsible for positioning aKidFrame's view
462 pt
+= aKidFrame
->GetPosition();
463 vm
->MoveViewTo(view
, pt
.x
, pt
.y
);
467 nsContainerFrame::ReparentFrameView(nsIFrame
* aChildFrame
,
468 nsIFrame
* aOldParentFrame
,
469 nsIFrame
* aNewParentFrame
)
471 NS_PRECONDITION(aChildFrame
, "null child frame pointer");
472 NS_PRECONDITION(aOldParentFrame
, "null old parent frame pointer");
473 NS_PRECONDITION(aNewParentFrame
, "null new parent frame pointer");
474 NS_PRECONDITION(aOldParentFrame
!= aNewParentFrame
, "same old and new parent frame");
476 // See if either the old parent frame or the new parent frame have a view
477 while (!aOldParentFrame
->HasView() && !aNewParentFrame
->HasView()) {
478 // Walk up both the old parent frame and the new parent frame nodes
479 // stopping when we either find a common parent or views for one
480 // or both of the frames.
482 // This works well in the common case where we push/pull and the old parent
483 // frame and the new parent frame are part of the same flow. They will
484 // typically be the same distance (height wise) from the
485 aOldParentFrame
= aOldParentFrame
->GetParent();
486 aNewParentFrame
= aNewParentFrame
->GetParent();
488 // We should never walk all the way to the root frame without finding
490 NS_ASSERTION(aOldParentFrame
&& aNewParentFrame
, "didn't find view");
492 // See if we reached a common ancestor
493 if (aOldParentFrame
== aNewParentFrame
) {
498 // See if we found a common parent frame
499 if (aOldParentFrame
== aNewParentFrame
) {
500 // We found a common parent and there are no views between the old parent
501 // and the common parent or the new parent frame and the common parent.
502 // Because neither the old parent frame nor the new parent frame have views,
503 // then any child views don't need reparenting
507 // We found views for one or both of the ancestor frames before we
508 // found a common ancestor.
509 nsView
* oldParentView
= aOldParentFrame
->GetClosestView();
510 nsView
* newParentView
= aNewParentFrame
->GetClosestView();
512 // See if the old parent frame and the new parent frame are in the
513 // same view sub-hierarchy. If they are then we don't have to do
515 if (oldParentView
!= newParentView
) {
516 // They're not so we need to reparent any child views
517 return ReparentFrameViewTo(aChildFrame
, oldParentView
->GetViewManager(), newParentView
,
525 nsContainerFrame::ReparentFrameViewList(const nsFrameList
& aChildFrameList
,
526 nsIFrame
* aOldParentFrame
,
527 nsIFrame
* aNewParentFrame
)
529 NS_PRECONDITION(aChildFrameList
.NotEmpty(), "empty child frame list");
530 NS_PRECONDITION(aOldParentFrame
, "null old parent frame pointer");
531 NS_PRECONDITION(aNewParentFrame
, "null new parent frame pointer");
532 NS_PRECONDITION(aOldParentFrame
!= aNewParentFrame
, "same old and new parent frame");
534 // See if either the old parent frame or the new parent frame have a view
535 while (!aOldParentFrame
->HasView() && !aNewParentFrame
->HasView()) {
536 // Walk up both the old parent frame and the new parent frame nodes
537 // stopping when we either find a common parent or views for one
538 // or both of the frames.
540 // This works well in the common case where we push/pull and the old parent
541 // frame and the new parent frame are part of the same flow. They will
542 // typically be the same distance (height wise) from the
543 aOldParentFrame
= aOldParentFrame
->GetParent();
544 aNewParentFrame
= aNewParentFrame
->GetParent();
546 // We should never walk all the way to the root frame without finding
548 NS_ASSERTION(aOldParentFrame
&& aNewParentFrame
, "didn't find view");
550 // See if we reached a common ancestor
551 if (aOldParentFrame
== aNewParentFrame
) {
557 // See if we found a common parent frame
558 if (aOldParentFrame
== aNewParentFrame
) {
559 // We found a common parent and there are no views between the old parent
560 // and the common parent or the new parent frame and the common parent.
561 // Because neither the old parent frame nor the new parent frame have views,
562 // then any child views don't need reparenting
566 // We found views for one or both of the ancestor frames before we
567 // found a common ancestor.
568 nsView
* oldParentView
= aOldParentFrame
->GetClosestView();
569 nsView
* newParentView
= aNewParentFrame
->GetClosestView();
571 // See if the old parent frame and the new parent frame are in the
572 // same view sub-hierarchy. If they are then we don't have to do
574 if (oldParentView
!= newParentView
) {
575 nsViewManager
* viewManager
= oldParentView
->GetViewManager();
577 // They're not so we need to reparent any child views
578 for (nsFrameList::Enumerator
e(aChildFrameList
); !e
.AtEnd(); e
.Next()) {
579 ReparentFrameViewTo(e
.get(), viewManager
, newParentView
, oldParentView
);
587 GetPresContextContainerWidget(nsPresContext
* aPresContext
)
589 nsCOMPtr
<nsISupports
> container
= aPresContext
->Document()->GetContainer();
590 nsCOMPtr
<nsIBaseWindow
> baseWindow
= do_QueryInterface(container
);
594 nsCOMPtr
<nsIWidget
> mainWidget
;
595 baseWindow
->GetMainWidget(getter_AddRefs(mainWidget
));
600 IsTopLevelWidget(nsIWidget
* aWidget
)
602 nsWindowType windowType
= aWidget
->WindowType();
603 return windowType
== eWindowType_toplevel
||
604 windowType
== eWindowType_dialog
||
605 windowType
== eWindowType_sheet
;
606 // popups aren't toplevel so they're not handled here
610 nsContainerFrame::SyncWindowProperties(nsPresContext
* aPresContext
,
613 nsRenderingContext
* aRC
)
616 if (!aView
|| !nsCSSRendering::IsCanvasFrame(aFrame
) || !aView
->HasWidget())
619 nsIWidget
* windowWidget
= GetPresContextContainerWidget(aPresContext
);
620 if (!windowWidget
|| !IsTopLevelWidget(windowWidget
))
623 nsViewManager
* vm
= aView
->GetViewManager();
624 nsView
* rootView
= vm
->GetRootView();
626 if (aView
!= rootView
)
629 Element
* rootElement
= aPresContext
->Document()->GetRootElement();
630 if (!rootElement
|| !rootElement
->IsXUL()) {
631 // Scrollframes use native widgets which don't work well with
632 // translucent windows, at least in Windows XP. So if the document
633 // has a root scrollrame it's useless to try to make it transparent,
634 // we'll just get something broken.
635 // nsCSSFrameConstructor::ConstructRootFrame constructs root
636 // scrollframes whenever the root element is not a XUL element, so
637 // we test for that here. We can't just call
638 // presShell->GetRootScrollFrame() since that might not have
639 // been constructed yet.
640 // We can change this to allow translucent toplevel HTML documents
641 // (e.g. to do something like Dashboard widgets), once we
642 // have broad support for translucent scrolled documents, but be
643 // careful because apparently some Firefox extensions expect
644 // openDialog("something.html") to produce an opaque window
645 // even if the HTML doesn't have a background-color set.
649 nsIFrame
*rootFrame
= aPresContext
->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
653 nsTransparencyMode mode
= nsLayoutUtils::GetFrameTransparency(aFrame
, rootFrame
);
654 nsIWidget
* viewWidget
= aView
->GetWidget();
655 viewWidget
->SetTransparencyMode(mode
);
656 windowWidget
->SetWindowShadowStyle(rootFrame
->StyleUIReset()->mWindowShadow
);
661 nsBoxLayoutState
aState(aPresContext
, aRC
);
662 nsSize minSize
= rootFrame
->GetMinSize(aState
);
663 nsSize maxSize
= rootFrame
->GetMaxSize(aState
);
665 SetSizeConstraints(aPresContext
, windowWidget
, minSize
, maxSize
);
669 void nsContainerFrame::SetSizeConstraints(nsPresContext
* aPresContext
,
671 const nsSize
& aMinSize
,
672 const nsSize
& aMaxSize
)
674 nsIntSize
devMinSize(aPresContext
->AppUnitsToDevPixels(aMinSize
.width
),
675 aPresContext
->AppUnitsToDevPixels(aMinSize
.height
));
676 nsIntSize
devMaxSize(aMaxSize
.width
== NS_INTRINSICSIZE
? NS_MAXSIZE
:
677 aPresContext
->AppUnitsToDevPixels(aMaxSize
.width
),
678 aMaxSize
.height
== NS_INTRINSICSIZE
? NS_MAXSIZE
:
679 aPresContext
->AppUnitsToDevPixels(aMaxSize
.height
));
681 // MinSize has a priority over MaxSize
682 if (devMinSize
.width
> devMaxSize
.width
)
683 devMaxSize
.width
= devMinSize
.width
;
684 if (devMinSize
.height
> devMaxSize
.height
)
685 devMaxSize
.height
= devMinSize
.height
;
687 widget::SizeConstraints
constraints(devMinSize
, devMaxSize
);
689 // The sizes are in inner window sizes, so convert them into outer window sizes.
690 // Use a size of (200, 200) as only the difference between the inner and outer
692 nsIntSize windowSize
= aWidget
->ClientToWindowSize(nsIntSize(200, 200));
693 if (constraints
.mMinSize
.width
)
694 constraints
.mMinSize
.width
+= windowSize
.width
- 200;
695 if (constraints
.mMinSize
.height
)
696 constraints
.mMinSize
.height
+= windowSize
.height
- 200;
697 if (constraints
.mMaxSize
.width
!= NS_MAXSIZE
)
698 constraints
.mMaxSize
.width
+= windowSize
.width
- 200;
699 if (constraints
.mMaxSize
.height
!= NS_MAXSIZE
)
700 constraints
.mMaxSize
.height
+= windowSize
.height
- 200;
702 aWidget
->SetSizeConstraints(constraints
);
706 nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext
* aPresContext
,
709 const nsRect
& aVisualOverflowArea
,
716 // Make sure the view is sized and positioned correctly
717 if (0 == (aFlags
& NS_FRAME_NO_MOVE_VIEW
)) {
718 PositionFrameView(aFrame
);
721 if (0 == (aFlags
& NS_FRAME_NO_SIZE_VIEW
)) {
722 nsViewManager
* vm
= aView
->GetViewManager();
724 vm
->ResizeView(aView
, aVisualOverflowArea
, true);
729 nsContainerFrame::SyncFrameViewProperties(nsPresContext
* aPresContext
,
731 nsStyleContext
* aStyleContext
,
735 NS_ASSERTION(!aStyleContext
|| aFrame
->StyleContext() == aStyleContext
,
736 "Wrong style context for frame?");
742 nsViewManager
* vm
= aView
->GetViewManager();
744 if (nullptr == aStyleContext
) {
745 aStyleContext
= aFrame
->StyleContext();
748 // Make sure visibility is correct. This only affects nsSubdocumentFrame.
749 if (0 == (aFlags
& NS_FRAME_NO_VISIBILITY
) &&
750 !aFrame
->SupportsVisibilityHidden()) {
751 // See if the view should be hidden or visible
752 vm
->SetViewVisibility(aView
,
753 aStyleContext
->StyleVisibility()->IsVisible()
754 ? nsViewVisibility_kShow
: nsViewVisibility_kHide
);
757 // See if the frame is being relatively positioned or absolutely
759 bool isPositioned
= aFrame
->IsPositioned();
762 bool autoZIndex
= false;
767 // Make sure z-index is correct
768 const nsStylePosition
* position
= aStyleContext
->StylePosition();
770 if (position
->mZIndex
.GetUnit() == eStyleUnit_Integer
) {
771 zIndex
= position
->mZIndex
.GetIntValue();
772 } else if (position
->mZIndex
.GetUnit() == eStyleUnit_Auto
) {
777 vm
->SetViewZIndex(aView
, autoZIndex
, zIndex
);
780 static nscoord
GetCoord(const nsStyleCoord
& aCoord
, nscoord aIfNotCoord
)
782 if (aCoord
.ConvertsToLength()) {
783 return nsRuleNode::ComputeCoordPercentCalc(aCoord
, 0);
789 nsContainerFrame::DoInlineIntrinsicISize(nsRenderingContext
*aRenderingContext
,
790 InlineIntrinsicISizeData
*aData
,
791 nsLayoutUtils::IntrinsicISizeType aType
)
794 return; // Already added.
796 NS_PRECONDITION(aType
== nsLayoutUtils::MIN_ISIZE
||
797 aType
== nsLayoutUtils::PREF_ISIZE
, "bad type");
799 mozilla::css::Side startSide
, endSide
;
800 if (StyleVisibility()->mDirection
== NS_STYLE_DIRECTION_LTR
) {
801 startSide
= NS_SIDE_LEFT
;
802 endSide
= NS_SIDE_RIGHT
;
804 startSide
= NS_SIDE_RIGHT
;
805 endSide
= NS_SIDE_LEFT
;
808 const nsStylePadding
*stylePadding
= StylePadding();
809 const nsStyleBorder
*styleBorder
= StyleBorder();
810 const nsStyleMargin
*styleMargin
= StyleMargin();
812 // This goes at the beginning no matter how things are broken and how
813 // messy the bidi situations are, since per CSS2.1 section 8.6
814 // (implemented in bug 328168), the startSide border is always on the
816 // This frame is a first-in-flow, but it might have a previous bidi
817 // continuation, in which case that continuation should handle the startSide
819 // For box-decoration-break:clone we setup clonePBM = startPBM + endPBM and
820 // add that to each line. For box-decoration-break:slice clonePBM is zero.
821 nscoord clonePBM
= 0; // PBM = PaddingBorderMargin
822 const bool sliceBreak
=
823 styleBorder
->mBoxDecorationBreak
== NS_STYLE_BOX_DECORATION_BREAK_SLICE
;
824 if (!GetPrevContinuation()) {
826 // clamp negative calc() to 0
827 std::max(GetCoord(stylePadding
->mPadding
.Get(startSide
), 0), 0) +
828 styleBorder
->GetComputedBorderWidth(startSide
) +
829 GetCoord(styleMargin
->mMargin
.Get(startSide
), 0);
830 if (MOZ_LIKELY(sliceBreak
)) {
831 aData
->currentLine
+= startPBM
;
838 // clamp negative calc() to 0
839 std::max(GetCoord(stylePadding
->mPadding
.Get(endSide
), 0), 0) +
840 styleBorder
->GetComputedBorderWidth(endSide
) +
841 GetCoord(styleMargin
->mMargin
.Get(endSide
), 0);
842 if (MOZ_UNLIKELY(!sliceBreak
)) {
846 const nsLineList_iterator
* savedLine
= aData
->line
;
847 nsIFrame
* const savedLineContainer
= aData
->lineContainer
;
849 nsContainerFrame
*lastInFlow
;
850 for (nsContainerFrame
*nif
= this; nif
;
851 nif
= static_cast<nsContainerFrame
*>(nif
->GetNextInFlow())) {
852 if (aData
->currentLine
== 0) {
853 aData
->currentLine
= clonePBM
;
855 for (nsIFrame
*kid
= nif
->mFrames
.FirstChild(); kid
;
856 kid
= kid
->GetNextSibling()) {
857 if (aType
== nsLayoutUtils::MIN_ISIZE
)
858 kid
->AddInlineMinISize(aRenderingContext
,
859 static_cast<InlineMinISizeData
*>(aData
));
861 kid
->AddInlinePrefISize(aRenderingContext
,
862 static_cast<InlinePrefISizeData
*>(aData
));
865 // After we advance to our next-in-flow, the stored line and line container
866 // may no longer be correct. Just forget them.
867 aData
->line
= nullptr;
868 aData
->lineContainer
= nullptr;
873 aData
->line
= savedLine
;
874 aData
->lineContainer
= savedLineContainer
;
876 // This goes at the end no matter how things are broken and how
877 // messy the bidi situations are, since per CSS2.1 section 8.6
878 // (implemented in bug 328168), the endSide border is always on the
880 // We reached the last-in-flow, but it might have a next bidi
881 // continuation, in which case that continuation should handle
882 // the endSide border.
883 if (MOZ_LIKELY(!lastInFlow
->GetNextContinuation() && sliceBreak
)) {
884 aData
->currentLine
+= endPBM
;
890 nsContainerFrame::ComputeAutoSize(nsRenderingContext
* aRenderingContext
,
892 const LogicalSize
& aCBSize
,
893 nscoord aAvailableISize
,
894 const LogicalSize
& aMargin
,
895 const LogicalSize
& aBorder
,
896 const LogicalSize
& aPadding
,
899 LogicalSize
result(aWM
, 0xdeadbeef, NS_UNCONSTRAINEDSIZE
);
900 nscoord availBased
= aAvailableISize
- aMargin
.ISize(aWM
) -
901 aBorder
.ISize(aWM
) - aPadding
.ISize(aWM
);
902 // replaced elements always shrink-wrap
903 if (aShrinkWrap
|| IsFrameOfType(eReplaced
)) {
904 // don't bother setting it if the result won't be used
905 const nsStyleCoord
& inlineStyleCoord
=
906 aWM
.IsVertical() ? StylePosition()->mHeight
: StylePosition()->mWidth
;
907 if (inlineStyleCoord
.GetUnit() == eStyleUnit_Auto
) {
908 result
.ISize(aWM
) = ShrinkWidthToFit(aRenderingContext
, availBased
);
911 result
.ISize(aWM
) = availBased
;
914 if (IsTableCaption()) {
915 // If we're a container for font size inflation, then shrink
916 // wrapping inside of us should not apply font size inflation.
917 AutoMaybeDisableFontInflation
an(this);
919 // XXX todo: make this aware of vertical writing modes
920 uint8_t captionSide
= StyleTableBorder()->mCaptionSide
;
921 if (captionSide
== NS_STYLE_CAPTION_SIDE_LEFT
||
922 captionSide
== NS_STYLE_CAPTION_SIDE_RIGHT
) {
923 result
.ISize(aWM
) = GetMinISize(aRenderingContext
);
924 } else if (captionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
925 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
) {
926 // The outer frame constrains our available width to the width of
927 // the table. Grow if our min-width is bigger than that, but not
928 // larger than the containing block width. (It would really be nice
929 // to transmit that information another way, so we could grow up to
930 // the table's available width, but that's harder.)
931 nscoord min
= GetMinISize(aRenderingContext
);
932 if (min
> aCBSize
.ISize(aWM
)) {
933 min
= aCBSize
.ISize(aWM
);
935 if (min
> result
.ISize(aWM
)) {
936 result
.ISize(aWM
) = min
;
944 * Invokes the WillReflow() function, positions the frame and its view (if
945 * requested), and then calls Reflow(). If the reflow succeeds and the child
946 * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
949 nsContainerFrame::ReflowChild(nsIFrame
* aKidFrame
,
950 nsPresContext
* aPresContext
,
951 nsHTMLReflowMetrics
& aDesiredSize
,
952 const nsHTMLReflowState
& aReflowState
,
956 nsReflowStatus
& aStatus
,
957 nsOverflowContinuationTracker
* aTracker
)
959 NS_PRECONDITION(aReflowState
.frame
== aKidFrame
, "bad reflow state");
961 // Send the WillReflow() notification, and position the child frame
962 // and its view if requested
963 aKidFrame
->WillReflow(aPresContext
);
965 if (NS_FRAME_NO_MOVE_FRAME
!= (aFlags
& NS_FRAME_NO_MOVE_FRAME
)) {
966 aKidFrame
->SetPosition(nsPoint(aX
, aY
));
969 if (0 == (aFlags
& NS_FRAME_NO_MOVE_VIEW
)) {
970 PositionFrameView(aKidFrame
);
973 // Reflow the child frame
974 aKidFrame
->Reflow(aPresContext
, aDesiredSize
, aReflowState
, aStatus
);
976 // If the child frame is complete, delete any next-in-flows,
977 // but only if the NO_DELETE_NEXT_IN_FLOW flag isn't set.
978 if (NS_FRAME_IS_FULLY_COMPLETE(aStatus
) &&
979 !(aFlags
& NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD
)) {
980 nsIFrame
* kidNextInFlow
= aKidFrame
->GetNextInFlow();
982 // Remove all of the childs next-in-flows. Make sure that we ask
983 // the right parent to do the removal (it's possible that the
984 // parent is not this because we are executing pullup code)
985 nsOverflowContinuationTracker::AutoFinish
fini(aTracker
, aKidFrame
);
986 kidNextInFlow
->GetParent()->DeleteNextInFlowChild(kidNextInFlow
, true);
993 * Position the views of |aFrame|'s descendants. A container frame
994 * should call this method if it moves a frame after |Reflow|.
997 nsContainerFrame::PositionChildViews(nsIFrame
* aFrame
)
999 if (!(aFrame
->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW
)) {
1003 // Recursively walk aFrame's child frames.
1004 // Process the additional child lists, but skip the popup list as the
1005 // view for popups is managed by the parent. Currently only nsMenuFrame
1006 // and nsPopupSetFrame have a popupList and during layout will adjust the
1007 // view manually to position the popup.
1008 ChildListIterator
lists(aFrame
);
1009 for (; !lists
.IsDone(); lists
.Next()) {
1010 if (lists
.CurrentID() == kPopupList
) {
1013 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
1014 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
1015 // Position the frame's view (if it has one) otherwise recursively
1016 // process its children
1017 nsIFrame
* childFrame
= childFrames
.get();
1018 if (childFrame
->HasView()) {
1019 PositionFrameView(childFrame
);
1021 PositionChildViews(childFrame
);
1028 * The second half of frame reflow. Does the following:
1029 * - sets the frame's bounds
1030 * - sizes and positions (if requested) the frame's view. If the frame's final
1031 * position differs from the current position and the frame itself does not
1032 * have a view, then any child frames with views are positioned so they stay
1034 * - sets the view's visibility, opacity, content transparency, and clip
1035 * - invoked the DidReflow() function
1038 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
1039 * case. Also implies NS_FRAME_NO_MOVE_VIEW
1040 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
1041 * don't want to automatically sync the frame and view
1042 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
1045 nsContainerFrame::FinishReflowChild(nsIFrame
* aKidFrame
,
1046 nsPresContext
* aPresContext
,
1047 const nsHTMLReflowMetrics
& aDesiredSize
,
1048 const nsHTMLReflowState
* aReflowState
,
1053 nsPoint curOrigin
= aKidFrame
->GetPosition();
1055 if (NS_FRAME_NO_MOVE_FRAME
!= (aFlags
& NS_FRAME_NO_MOVE_FRAME
)) {
1056 aKidFrame
->SetRect(nsRect(aX
, aY
, aDesiredSize
.Width(), aDesiredSize
.Height()));
1058 aKidFrame
->SetSize(nsSize(aDesiredSize
.Width(), aDesiredSize
.Height()));
1061 if (aKidFrame
->HasView()) {
1062 nsView
* view
= aKidFrame
->GetView();
1063 // Make sure the frame's view is properly sized and positioned and has
1064 // things like opacity correct
1065 SyncFrameViewAfterReflow(aPresContext
, aKidFrame
, view
,
1066 aDesiredSize
.VisualOverflow(), aFlags
);
1069 if (!(aFlags
& NS_FRAME_NO_MOVE_VIEW
) &&
1070 (curOrigin
.x
!= aX
|| curOrigin
.y
!= aY
)) {
1071 if (!aKidFrame
->HasView()) {
1072 // If the frame has moved, then we need to make sure any child views are
1073 // correctly positioned
1074 PositionChildViews(aKidFrame
);
1078 aKidFrame
->DidReflow(aPresContext
, aReflowState
, nsDidReflowStatus::FINISHED
);
1082 nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext
* aPresContext
,
1083 const nsHTMLReflowState
& aReflowState
,
1084 nsOverflowAreas
& aOverflowRects
,
1086 nsReflowStatus
& aStatus
)
1088 NS_PRECONDITION(aPresContext
, "null pointer");
1090 nsFrameList
* overflowContainers
=
1091 GetPropTableFrames(OverflowContainersProperty());
1093 NS_ASSERTION(!(overflowContainers
&& GetPrevInFlow()
1094 && static_cast<nsContainerFrame
*>(GetPrevInFlow())
1095 ->GetPropTableFrames(ExcessOverflowContainersProperty())),
1096 "conflicting overflow containers lists");
1098 if (!overflowContainers
) {
1099 // Drain excess from previnflow
1100 nsContainerFrame
* prev
= (nsContainerFrame
*) GetPrevInFlow();
1102 nsFrameList
* excessFrames
=
1103 prev
->RemovePropTableFrames(ExcessOverflowContainersProperty());
1105 excessFrames
->ApplySetParent(this);
1106 nsContainerFrame::ReparentFrameViewList(*excessFrames
, prev
, this);
1107 overflowContainers
= excessFrames
;
1108 SetPropTableFrames(overflowContainers
, OverflowContainersProperty());
1113 // Our own excess overflow containers from a previous reflow can still be
1114 // present if our next-in-flow hasn't been reflown yet.
1115 nsFrameList
* selfExcessOCFrames
=
1116 RemovePropTableFrames(ExcessOverflowContainersProperty());
1117 if (selfExcessOCFrames
) {
1118 if (overflowContainers
) {
1119 overflowContainers
->AppendFrames(nullptr, *selfExcessOCFrames
);
1120 selfExcessOCFrames
->Delete(aPresContext
->PresShell());
1122 overflowContainers
= selfExcessOCFrames
;
1123 SetPropTableFrames(overflowContainers
, OverflowContainersProperty());
1126 if (!overflowContainers
) {
1127 return; // nothing to reflow
1130 nsOverflowContinuationTracker
tracker(this, false, false);
1131 bool shouldReflowAllKids
= aReflowState
.ShouldReflowAllKids();
1133 for (nsIFrame
* frame
= overflowContainers
->FirstChild(); frame
;
1134 frame
= frame
->GetNextSibling()) {
1135 if (frame
->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
1136 // frame's prevInFlow has moved, skip reflowing this frame;
1137 // it will get reflowed once it's been placed
1140 // If the available vertical height has changed, we need to reflow
1141 // even if the frame isn't dirty.
1142 if (shouldReflowAllKids
|| NS_SUBTREE_DIRTY(frame
)) {
1144 nsIFrame
* prevInFlow
= frame
->GetPrevInFlow();
1145 NS_ASSERTION(prevInFlow
,
1146 "overflow container frame must have a prev-in-flow");
1147 NS_ASSERTION(frame
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
,
1148 "overflow container frame must have overflow container bit set");
1149 nsRect prevRect
= prevInFlow
->GetRect();
1151 // Initialize reflow params
1152 WritingMode wm
= frame
->GetWritingMode();
1153 LogicalSize
availSpace(wm
, LogicalSize(wm
, prevRect
.Size()).ISize(wm
),
1154 aReflowState
.AvailableSize(wm
).BSize(wm
));
1155 nsHTMLReflowMetrics
desiredSize(aReflowState
);
1156 nsHTMLReflowState
frameState(aPresContext
, aReflowState
,
1158 nsReflowStatus frameStatus
;
1161 ReflowChild(frame
, aPresContext
, desiredSize
, frameState
,
1162 prevRect
.x
, 0, aFlags
, frameStatus
, &tracker
);
1163 //XXXfr Do we need to override any shrinkwrap effects here?
1164 // e.g. desiredSize.Width() = prevRect.width;
1165 FinishReflowChild(frame
, aPresContext
, desiredSize
, &frameState
,
1166 prevRect
.x
, 0, aFlags
);
1168 // Handle continuations
1169 if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus
)) {
1170 if (frame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
1171 // Abspos frames can't cause their parent to be incomplete,
1172 // only overflow incomplete.
1173 NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus
);
1176 NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus
),
1177 "overflow container frames can't be incomplete, only overflow-incomplete");
1180 // Acquire a next-in-flow, creating it if necessary
1181 nsIFrame
* nif
= frame
->GetNextInFlow();
1183 NS_ASSERTION(frameStatus
& NS_FRAME_REFLOW_NEXTINFLOW
,
1184 "Someone forgot a REFLOW_NEXTINFLOW flag");
1185 nif
= aPresContext
->PresShell()->FrameConstructor()->
1186 CreateContinuingFrame(aPresContext
, frame
, this);
1188 else if (!(nif
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1189 // used to be a normal next-in-flow; steal it from the child list
1190 nsresult rv
= nif
->GetParent()->StealFrame(nif
);
1191 if (NS_FAILED(rv
)) {
1196 tracker
.Insert(nif
, frameStatus
);
1198 NS_MergeReflowStatusInto(&aStatus
, frameStatus
);
1199 // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
1200 // but we have some unsplittable frames that, when taller than
1201 // availableHeight will push zero-height content into a next-in-flow.
1204 tracker
.Skip(frame
, aStatus
);
1205 if (aReflowState
.mFloatManager
)
1206 nsBlockFrame::RecoverFloatsFor(frame
, *aReflowState
.mFloatManager
);
1208 ConsiderChildOverflow(aOverflowRects
, frame
);
1213 nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder
* aBuilder
,
1214 const nsRect
& aDirtyRect
,
1215 const nsDisplayListSet
& aLists
)
1217 nsFrameList
* overflowconts
= GetPropTableFrames(OverflowContainersProperty());
1218 if (overflowconts
) {
1219 for (nsIFrame
* frame
= overflowconts
->FirstChild(); frame
;
1220 frame
= frame
->GetNextSibling()) {
1221 BuildDisplayListForChild(aBuilder
, frame
, aDirtyRect
, aLists
);
1227 TryRemoveFrame(nsIFrame
* aFrame
, FramePropertyTable
* aPropTable
,
1228 const FramePropertyDescriptor
* aProp
, nsIFrame
* aChildToRemove
)
1230 nsFrameList
* list
= static_cast<nsFrameList
*>(aPropTable
->Get(aFrame
, aProp
));
1231 if (list
&& list
->StartRemoveFrame(aChildToRemove
)) {
1232 // aChildToRemove *may* have been removed from this list.
1233 if (list
->IsEmpty()) {
1234 aPropTable
->Remove(aFrame
, aProp
);
1235 list
->Delete(aFrame
->PresContext()->PresShell());
1243 nsContainerFrame::StealFrame(nsIFrame
* aChild
,
1247 if (!mFrames
.ContainsFrame(aChild
)) {
1248 nsFrameList
* list
= GetOverflowFrames();
1249 if (!list
|| !list
->ContainsFrame(aChild
)) {
1250 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
1251 list
= static_cast<nsFrameList
*>(
1252 propTable
->Get(this, OverflowContainersProperty()));
1253 if (!list
|| !list
->ContainsFrame(aChild
)) {
1254 list
= static_cast<nsFrameList
*>(
1255 propTable
->Get(this, ExcessOverflowContainersProperty()));
1256 MOZ_ASSERT(list
&& list
->ContainsFrame(aChild
), "aChild isn't our child"
1257 " or on a frame list not supported by StealFrame");
1264 if ((aChild
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)
1266 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
1267 // Try removing from the overflow container list.
1268 removed
= ::TryRemoveFrame(this, propTable
, OverflowContainersProperty(),
1271 // It must be in the excess overflow container list.
1272 removed
= ::TryRemoveFrame(this, propTable
,
1273 ExcessOverflowContainersProperty(),
1277 removed
= mFrames
.StartRemoveFrame(aChild
);
1279 // We didn't find the child in our principal child list.
1280 // Maybe it's on the overflow list?
1281 nsFrameList
* frameList
= GetOverflowFrames();
1283 removed
= frameList
->ContinueRemoveFrame(aChild
);
1284 if (frameList
->IsEmpty()) {
1285 DestroyOverflowList();
1291 NS_POSTCONDITION(removed
, "StealFrame: can't find aChild");
1292 return removed
? NS_OK
: NS_ERROR_UNEXPECTED
;
1296 nsContainerFrame::StealFramesAfter(nsIFrame
* aChild
)
1298 NS_ASSERTION(!aChild
||
1299 !(aChild
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
),
1300 "StealFramesAfter doesn't handle overflow containers");
1301 NS_ASSERTION(GetType() != nsGkAtoms::blockFrame
, "unexpected call");
1304 nsFrameList
copy(mFrames
);
1309 for (nsFrameList::FrameLinkEnumerator
iter(mFrames
); !iter
.AtEnd();
1311 if (iter
.PrevFrame() == aChild
) {
1312 return mFrames
.ExtractTail(iter
);
1316 // We didn't find the child in the principal child list.
1317 // Maybe it's on the overflow list?
1318 nsFrameList
* overflowFrames
= GetOverflowFrames();
1319 if (overflowFrames
) {
1320 for (nsFrameList::FrameLinkEnumerator
iter(*overflowFrames
); !iter
.AtEnd();
1322 if (iter
.PrevFrame() == aChild
) {
1323 return overflowFrames
->ExtractTail(iter
);
1328 NS_ERROR("StealFramesAfter: can't find aChild");
1329 return nsFrameList::EmptyList();
1333 * Create a next-in-flow for aFrame. Will return the newly created
1334 * frame <b>if and only if</b> a new frame is created; otherwise
1335 * nullptr is returned.
1338 nsContainerFrame::CreateNextInFlow(nsIFrame
* aFrame
)
1340 NS_PRECONDITION(GetType() != nsGkAtoms::blockFrame
,
1341 "you should have called nsBlockFrame::CreateContinuationFor instead");
1342 NS_PRECONDITION(mFrames
.ContainsFrame(aFrame
), "expected an in-flow child frame");
1344 nsPresContext
* pc
= PresContext();
1345 nsIFrame
* nextInFlow
= aFrame
->GetNextInFlow();
1346 if (nullptr == nextInFlow
) {
1347 // Create a continuation frame for the child frame and insert it
1348 // into our child list.
1349 nextInFlow
= pc
->PresShell()->FrameConstructor()->
1350 CreateContinuingFrame(pc
, aFrame
, this);
1351 mFrames
.InsertFrame(nullptr, aFrame
, nextInFlow
);
1353 NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES
,
1354 ("nsContainerFrame::CreateNextInFlow: frame=%p nextInFlow=%p",
1355 aFrame
, nextInFlow
));
1363 * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
1367 nsContainerFrame::DeleteNextInFlowChild(nsIFrame
* aNextInFlow
,
1368 bool aDeletingEmptyFrames
)
1371 nsIFrame
* prevInFlow
= aNextInFlow
->GetPrevInFlow();
1373 NS_PRECONDITION(prevInFlow
, "bad prev-in-flow");
1375 // If the next-in-flow has a next-in-flow then delete it, too (and
1376 // delete it first).
1377 // Do this in a loop so we don't overflow the stack for frames
1378 // with very many next-in-flows
1379 nsIFrame
* nextNextInFlow
= aNextInFlow
->GetNextInFlow();
1380 if (nextNextInFlow
) {
1381 nsAutoTArray
<nsIFrame
*, 8> frames
;
1382 for (nsIFrame
* f
= nextNextInFlow
; f
; f
= f
->GetNextInFlow()) {
1383 frames
.AppendElement(f
);
1385 for (int32_t i
= frames
.Length() - 1; i
>= 0; --i
) {
1386 nsIFrame
* delFrame
= frames
.ElementAt(i
);
1387 delFrame
->GetParent()->
1388 DeleteNextInFlowChild(delFrame
, aDeletingEmptyFrames
);
1392 // Take the next-in-flow out of the parent's child list
1393 DebugOnly
<nsresult
> rv
= StealFrame(aNextInFlow
);
1394 NS_ASSERTION(NS_SUCCEEDED(rv
), "StealFrame failure");
1397 if (aDeletingEmptyFrames
) {
1398 nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow
);
1402 // Delete the next-in-flow frame and its descendants. This will also
1403 // remove it from its next-in-flow/prev-in-flow chain.
1404 aNextInFlow
->Destroy();
1406 NS_POSTCONDITION(!prevInFlow
->GetNextInFlow(), "non null next-in-flow");
1410 * Set the frames on the overflow list
1413 nsContainerFrame::SetOverflowFrames(const nsFrameList
& aOverflowFrames
)
1415 NS_PRECONDITION(aOverflowFrames
.NotEmpty(), "Shouldn't be called");
1417 nsPresContext
* pc
= PresContext();
1418 nsFrameList
* newList
= new (pc
->PresShell()) nsFrameList(aOverflowFrames
);
1420 pc
->PropertyTable()->Set(this, OverflowProperty(), newList
);
1424 nsContainerFrame::GetPropTableFrames(const FramePropertyDescriptor
* aProperty
) const
1426 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
1427 return static_cast<nsFrameList
*>(propTable
->Get(this, aProperty
));
1431 nsContainerFrame::RemovePropTableFrames(const FramePropertyDescriptor
* aProperty
)
1433 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
1434 return static_cast<nsFrameList
*>(propTable
->Remove(this, aProperty
));
1438 nsContainerFrame::SetPropTableFrames(nsFrameList
* aFrameList
,
1439 const FramePropertyDescriptor
* aProperty
)
1441 NS_PRECONDITION(aProperty
&& aFrameList
, "null ptr");
1443 (aProperty
!= nsContainerFrame::OverflowContainersProperty() &&
1444 aProperty
!= nsContainerFrame::ExcessOverflowContainersProperty()) ||
1445 IsFrameOfType(nsIFrame::eCanContainOverflowContainers
),
1446 "this type of frame can't have overflow containers");
1447 MOZ_ASSERT(!GetPropTableFrames(aProperty
));
1448 PresContext()->PropertyTable()->Set(this, aProperty
, aFrameList
);
1452 * Push aFromChild and its next siblings to the next-in-flow. Change the
1453 * geometric parent of each frame that's pushed. If there is no next-in-flow
1454 * the frames are placed on the overflow list (and the geometric parent is
1457 * Updates the next-in-flow's child count. Does <b>not</b> update the
1458 * pusher's child count.
1460 * @param aFromChild the first child frame to push. It is disconnected from
1462 * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's
1463 * an error to push a parent's first child frame
1466 nsContainerFrame::PushChildren(nsIFrame
* aFromChild
,
1467 nsIFrame
* aPrevSibling
)
1469 NS_PRECONDITION(aFromChild
, "null pointer");
1470 NS_PRECONDITION(aPrevSibling
, "pushing first child");
1471 NS_PRECONDITION(aPrevSibling
->GetNextSibling() == aFromChild
, "bad prev sibling");
1473 // Disconnect aFromChild from its previous sibling
1474 nsFrameList tail
= mFrames
.RemoveFramesAfter(aPrevSibling
);
1476 nsContainerFrame
* nextInFlow
=
1477 static_cast<nsContainerFrame
*>(GetNextInFlow());
1479 // XXX This is not a very good thing to do. If it gets removed
1480 // then remove the copy of this routine that doesn't do this from
1482 // When pushing and pulling frames we need to check for whether any
1483 // views need to be reparented.
1484 for (nsIFrame
* f
= aFromChild
; f
; f
= f
->GetNextSibling()) {
1485 nsContainerFrame::ReparentFrameView(f
, this, nextInFlow
);
1487 nextInFlow
->mFrames
.InsertFrames(nextInFlow
, nullptr, tail
);
1490 // Add the frames to our overflow list
1491 SetOverflowFrames(tail
);
1496 * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
1497 * the receiver's overflow list) to the child list.
1499 * Updates this frame's child count and content mapping.
1501 * @return true if any frames were moved and false otherwise
1504 nsContainerFrame::MoveOverflowToChildList()
1506 bool result
= false;
1508 // Check for an overflow list with our prev-in-flow
1509 nsContainerFrame
* prevInFlow
= (nsContainerFrame
*)GetPrevInFlow();
1510 if (nullptr != prevInFlow
) {
1511 AutoFrameListPtr
prevOverflowFrames(PresContext(),
1512 prevInFlow
->StealOverflowFrames());
1513 if (prevOverflowFrames
) {
1514 // Tables are special; they can have repeated header/footer
1515 // frames on mFrames at this point.
1516 NS_ASSERTION(mFrames
.IsEmpty() || GetType() == nsGkAtoms::tableFrame
,
1517 "bad overflow list");
1518 // When pushing and pulling frames we need to check for whether any
1519 // views need to be reparented.
1520 nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames
,
1522 mFrames
.AppendFrames(this, *prevOverflowFrames
);
1527 // It's also possible that we have an overflow list for ourselves.
1528 return DrainSelfOverflowList() || result
;
1532 nsContainerFrame::DrainSelfOverflowList()
1534 AutoFrameListPtr
overflowFrames(PresContext(), StealOverflowFrames());
1535 if (overflowFrames
) {
1536 mFrames
.AppendFrames(nullptr, *overflowFrames
);
1543 nsContainerFrame::GetNextInFlowChild(ContinuationTraversingState
& aState
,
1544 bool* aIsInOverflow
)
1546 nsContainerFrame
*& nextInFlow
= aState
.mNextInFlow
;
1547 while (nextInFlow
) {
1548 // See if there is any frame in the container
1549 nsIFrame
* frame
= nextInFlow
->mFrames
.FirstChild();
1551 if (aIsInOverflow
) {
1552 *aIsInOverflow
= false;
1556 // No frames in the principal list, try its overflow list
1557 nsFrameList
* overflowFrames
= nextInFlow
->GetOverflowFrames();
1558 if (overflowFrames
) {
1559 if (aIsInOverflow
) {
1560 *aIsInOverflow
= true;
1562 return overflowFrames
->FirstChild();
1564 nextInFlow
= static_cast<nsContainerFrame
*>(nextInFlow
->GetNextInFlow());
1570 nsContainerFrame::PullNextInFlowChild(ContinuationTraversingState
& aState
)
1573 nsIFrame
* frame
= GetNextInFlowChild(aState
, &isInOverflow
);
1575 nsContainerFrame
* nextInFlow
= aState
.mNextInFlow
;
1577 nsFrameList
* overflowFrames
= nextInFlow
->GetOverflowFrames();
1578 overflowFrames
->RemoveFirstChild();
1579 if (overflowFrames
->IsEmpty()) {
1580 nextInFlow
->DestroyOverflowList();
1583 nextInFlow
->mFrames
.RemoveFirstChild();
1586 // Move the frame to the principal frame list of this container
1587 mFrames
.AppendFrame(this, frame
);
1588 // AppendFrame has reparented the frame, we need
1589 // to reparent the frame view then.
1590 nsContainerFrame::ReparentFrameView(frame
, nextInFlow
, this);
1595 nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsContainerFrame
* aFrame
,
1596 bool aWalkOOFFrames
,
1597 bool aSkipOverflowContainerChildren
)
1598 : mOverflowContList(nullptr),
1599 mPrevOverflowCont(nullptr),
1602 mSkipOverflowContainerChildren(aSkipOverflowContainerChildren
),
1603 mWalkOOFFrames(aWalkOOFFrames
)
1605 NS_PRECONDITION(aFrame
, "null frame pointer");
1606 SetupOverflowContList();
1610 nsOverflowContinuationTracker::SetupOverflowContList()
1612 NS_PRECONDITION(mParent
, "null frame pointer");
1613 NS_PRECONDITION(!mOverflowContList
, "already have list");
1614 nsContainerFrame
* nif
=
1615 static_cast<nsContainerFrame
*>(mParent
->GetNextInFlow());
1617 mOverflowContList
= nif
->GetPropTableFrames(
1618 nsContainerFrame::OverflowContainersProperty());
1619 if (mOverflowContList
) {
1624 if (!mOverflowContList
) {
1625 mOverflowContList
= mParent
->GetPropTableFrames(
1626 nsContainerFrame::ExcessOverflowContainersProperty());
1627 if (mOverflowContList
) {
1634 * Helper function to walk past overflow continuations whose prev-in-flow
1635 * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
1638 nsOverflowContinuationTracker::SetUpListWalker()
1640 NS_ASSERTION(!mSentry
&& !mPrevOverflowCont
,
1641 "forgot to reset mSentry or mPrevOverflowCont");
1642 if (mOverflowContList
) {
1643 nsIFrame
* cur
= mOverflowContList
->FirstChild();
1644 if (mSkipOverflowContainerChildren
) {
1645 while (cur
&& (cur
->GetPrevInFlow()->GetStateBits()
1646 & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1647 mPrevOverflowCont
= cur
;
1648 cur
= cur
->GetNextSibling();
1650 while (cur
&& (!(cur
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
1651 == mWalkOOFFrames
)) {
1652 mPrevOverflowCont
= cur
;
1653 cur
= cur
->GetNextSibling();
1657 mSentry
= cur
->GetPrevInFlow();
1663 * Helper function to step forward through the overflow continuations list.
1664 * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
1665 * as appropriate. May only be called when we have already set up an
1666 * mOverflowContList; mOverflowContList cannot be null.
1669 nsOverflowContinuationTracker::StepForward()
1671 NS_PRECONDITION(mOverflowContList
, "null list");
1674 if (mPrevOverflowCont
) {
1675 mPrevOverflowCont
= mPrevOverflowCont
->GetNextSibling();
1678 mPrevOverflowCont
= mOverflowContList
->FirstChild();
1681 // Skip over oof or non-oof frames as appropriate
1682 if (mSkipOverflowContainerChildren
) {
1683 nsIFrame
* cur
= mPrevOverflowCont
->GetNextSibling();
1684 while (cur
&& (!(cur
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
1685 == mWalkOOFFrames
)) {
1686 mPrevOverflowCont
= cur
;
1687 cur
= cur
->GetNextSibling();
1691 // Set up the sentry
1692 mSentry
= (mPrevOverflowCont
->GetNextSibling())
1693 ? mPrevOverflowCont
->GetNextSibling()->GetPrevInFlow()
1698 nsOverflowContinuationTracker::Insert(nsIFrame
* aOverflowCont
,
1699 nsReflowStatus
& aReflowStatus
)
1701 NS_PRECONDITION(aOverflowCont
, "null frame pointer");
1702 NS_PRECONDITION(!mSkipOverflowContainerChildren
|| mWalkOOFFrames
==
1703 !!(aOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
),
1704 "shouldn't insert frame that doesn't match walker type");
1705 NS_PRECONDITION(aOverflowCont
->GetPrevInFlow(),
1706 "overflow containers must have a prev-in-flow");
1707 nsresult rv
= NS_OK
;
1708 bool reparented
= false;
1709 nsPresContext
* presContext
= aOverflowCont
->PresContext();
1710 bool addToList
= !mSentry
|| aOverflowCont
!= mSentry
->GetNextInFlow();
1712 // If we have a list and aOverflowCont is already in it then don't try to
1714 if (addToList
&& aOverflowCont
->GetParent() == mParent
&&
1715 (aOverflowCont
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) &&
1716 mOverflowContList
&& mOverflowContList
->ContainsFrame(aOverflowCont
)) {
1718 mPrevOverflowCont
= aOverflowCont
->GetPrevSibling();
1722 if (aOverflowCont
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) {
1723 // aOverflowCont is in some other overflow container list,
1725 NS_ASSERTION(!(mOverflowContList
&&
1726 mOverflowContList
->ContainsFrame(aOverflowCont
)),
1727 "overflow containers out of order");
1728 rv
= aOverflowCont
->GetParent()->StealFrame(aOverflowCont
);
1729 NS_ENSURE_SUCCESS(rv
, rv
);
1732 aOverflowCont
->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER
);
1734 if (!mOverflowContList
) {
1735 mOverflowContList
= new (presContext
->PresShell()) nsFrameList();
1736 mParent
->SetPropTableFrames(mOverflowContList
,
1737 nsContainerFrame::ExcessOverflowContainersProperty());
1740 if (aOverflowCont
->GetParent() != mParent
) {
1741 nsContainerFrame::ReparentFrameView(aOverflowCont
,
1742 aOverflowCont
->GetParent(),
1747 // If aOverflowCont has a prev/next-in-flow that might be in
1748 // mOverflowContList we need to find it and insert after/before it to
1749 // maintain the order amongst next-in-flows in this list.
1750 nsIFrame
* pif
= aOverflowCont
->GetPrevInFlow();
1751 nsIFrame
* nif
= aOverflowCont
->GetNextInFlow();
1752 if ((pif
&& pif
->GetParent() == mParent
&& pif
!= mPrevOverflowCont
) ||
1753 (nif
&& nif
->GetParent() == mParent
&& mPrevOverflowCont
)) {
1754 for (nsFrameList::Enumerator
e(*mOverflowContList
); !e
.AtEnd(); e
.Next()) {
1755 nsIFrame
* f
= e
.get();
1757 mPrevOverflowCont
= pif
;
1761 mPrevOverflowCont
= f
->GetPrevSibling();
1767 mOverflowContList
->InsertFrame(mParent
, mPrevOverflowCont
, aOverflowCont
);
1768 aReflowStatus
|= NS_FRAME_REFLOW_NEXTINFLOW
;
1771 // If we need to reflow it, mark it dirty
1772 if (aReflowStatus
& NS_FRAME_REFLOW_NEXTINFLOW
)
1773 aOverflowCont
->AddStateBits(NS_FRAME_IS_DIRTY
);
1775 // It's in our list, just step forward
1777 NS_ASSERTION(mPrevOverflowCont
== aOverflowCont
||
1778 (mSkipOverflowContainerChildren
&&
1779 (mPrevOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) !=
1780 (aOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)),
1781 "OverflowContTracker in unexpected state");
1784 // Convert all non-overflow-container continuations of aOverflowCont
1785 // into overflow containers and move them to our overflow
1786 // tracker. This preserves the invariant that the next-continuations
1787 // of an overflow container are also overflow containers.
1788 nsIFrame
* f
= aOverflowCont
->GetNextContinuation();
1789 if (f
&& (!(f
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) ||
1790 (!reparented
&& f
->GetParent() == mParent
) ||
1791 (reparented
&& f
->GetParent() != mParent
))) {
1792 if (!(f
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1793 rv
= f
->GetParent()->StealFrame(f
);
1794 NS_ENSURE_SUCCESS(rv
, rv
);
1796 Insert(f
, aReflowStatus
);
1803 nsOverflowContinuationTracker::BeginFinish(nsIFrame
* aChild
)
1805 NS_PRECONDITION(aChild
, "null ptr");
1806 NS_PRECONDITION(aChild
->GetNextInFlow(),
1807 "supposed to call Finish *before* deleting next-in-flow!");
1808 for (nsIFrame
* f
= aChild
; f
; f
= f
->GetNextInFlow()) {
1809 // We'll update these in EndFinish after the next-in-flows are gone.
1810 if (f
== mPrevOverflowCont
) {
1812 mPrevOverflowCont
= nullptr;
1823 nsOverflowContinuationTracker::EndFinish(nsIFrame
* aChild
)
1825 if (!mOverflowContList
) {
1828 // Forget mOverflowContList if it was deleted.
1829 nsPresContext
* pc
= aChild
->PresContext();
1830 FramePropertyTable
* propTable
= pc
->PropertyTable();
1831 nsFrameList
* eoc
= static_cast<nsFrameList
*>(propTable
->Get(mParent
,
1832 nsContainerFrame::ExcessOverflowContainersProperty()));
1833 if (eoc
!= mOverflowContList
) {
1834 nsFrameList
* oc
= static_cast<nsFrameList
*>(propTable
->Get(mParent
,
1835 nsContainerFrame::OverflowContainersProperty()));
1836 if (oc
!= mOverflowContList
) {
1837 // mOverflowContList was deleted
1838 mPrevOverflowCont
= nullptr;
1840 mParent
= aChild
->GetParent();
1841 mOverflowContList
= nullptr;
1842 SetupOverflowContList();
1846 // The list survived, update mSentry if needed.
1848 if (!mPrevOverflowCont
) {
1851 mozilla::AutoRestore
<nsIFrame
*> saved(mPrevOverflowCont
);
1852 // step backward to make StepForward() use our current mPrevOverflowCont
1853 mPrevOverflowCont
= mPrevOverflowCont
->GetPrevSibling();
1859 /////////////////////////////////////////////////////////////////////////////
1862 #ifdef DEBUG_FRAME_DUMP
1864 nsContainerFrame::List(FILE* out
, const char* aPrefix
, uint32_t aFlags
) const
1867 ListGeneric(str
, aPrefix
, aFlags
);
1869 // Output the children
1870 bool outputOneList
= false;
1871 ChildListIterator
lists(this);
1872 for (; !lists
.IsDone(); lists
.Next()) {
1873 if (outputOneList
) {
1876 if (lists
.CurrentID() != kPrincipalList
) {
1877 if (!outputOneList
) {
1881 str
+= nsPrintfCString("%s %p ", mozilla::layout::ChildListName(lists
.CurrentID()),
1882 &GetChildList(lists
.CurrentID()));
1884 fprintf_stderr(out
, "%s<\n", str
.get());
1886 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
1887 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
1888 nsIFrame
* kid
= childFrames
.get();
1889 // Verify the child frame's parent frame pointer is correct
1890 NS_ASSERTION(kid
->GetParent() == this, "bad parent frame pointer");
1892 // Have the child frame list
1893 nsCString
pfx(aPrefix
);
1895 kid
->List(out
, pfx
.get(), aFlags
);
1897 fprintf_stderr(out
, "%s>\n", aPrefix
);
1898 outputOneList
= true;
1901 if (!outputOneList
) {
1902 fprintf_stderr(out
, "%s<>\n", str
.get());