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"
40 using namespace mozilla
;
41 using namespace mozilla::dom
;
42 using namespace mozilla::layout
;
44 NS_IMPL_FRAMEARENA_HELPERS(nsContainerFrame
)
46 nsContainerFrame::~nsContainerFrame()
50 NS_QUERYFRAME_HEAD(nsContainerFrame
)
51 NS_QUERYFRAME_ENTRY(nsContainerFrame
)
52 NS_QUERYFRAME_TAIL_INHERITING(nsSplittableFrame
)
55 nsContainerFrame::Init(nsIContent
* aContent
,
57 nsIFrame
* aPrevInFlow
)
59 nsSplittableFrame::Init(aContent
, aParent
, aPrevInFlow
);
61 // Make sure we copy bits from our prev-in-flow that will affect
62 // us. A continuation for a container frame needs to know if it
63 // has a child with a view so that we'll properly reposition it.
64 if (aPrevInFlow
->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW
)
65 AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW
);
70 nsContainerFrame::SetInitialChildList(ChildListID aListID
,
71 nsFrameList
& aChildList
)
74 if (mFrames
.NotEmpty()) {
75 // We already have child frames which means we've already been
77 NS_NOTREACHED("unexpected second call to SetInitialChildList");
78 result
= NS_ERROR_UNEXPECTED
;
79 } else if (aListID
!= kPrincipalList
) {
80 // All we know about is the principal child list.
81 NS_NOTREACHED("unknown frame list");
82 result
= NS_ERROR_INVALID_ARG
;
85 nsFrame::VerifyDirtyBitSet(aChildList
);
87 mFrames
.SetFrames(aChildList
);
94 nsContainerFrame::AppendFrames(ChildListID aListID
,
95 nsFrameList
& aFrameList
)
97 if (aListID
!= kPrincipalList
) {
99 if (aListID
!= kNoReflowPrincipalList
)
102 NS_ERROR("unexpected child list");
103 return NS_ERROR_INVALID_ARG
;
106 if (aFrameList
.NotEmpty()) {
107 mFrames
.AppendFrames(this, aFrameList
);
109 // Ask the parent frame to reflow me.
111 if (aListID
== kPrincipalList
)
114 PresContext()->PresShell()->
115 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
116 NS_FRAME_HAS_DIRTY_CHILDREN
);
123 nsContainerFrame::InsertFrames(ChildListID aListID
,
124 nsIFrame
* aPrevFrame
,
125 nsFrameList
& aFrameList
)
127 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
128 "inserting after sibling frame with different parent");
130 if (aListID
!= kPrincipalList
) {
132 if (aListID
!= kNoReflowPrincipalList
)
135 NS_ERROR("unexpected child list");
136 return NS_ERROR_INVALID_ARG
;
139 if (aFrameList
.NotEmpty()) {
140 // Insert frames after aPrevFrame
141 mFrames
.InsertFrames(this, aPrevFrame
, aFrameList
);
144 if (aListID
== kPrincipalList
)
147 PresContext()->PresShell()->
148 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
149 NS_FRAME_HAS_DIRTY_CHILDREN
);
156 nsContainerFrame::RemoveFrame(ChildListID aListID
,
159 if (aListID
!= kPrincipalList
) {
161 if (kNoReflowPrincipalList
!= aListID
)
164 NS_ERROR("unexpected child list");
165 return NS_ERROR_INVALID_ARG
;
169 // Loop and destroy aOldFrame and all of its continuations.
170 // Request a reflow on the parent frames involved unless we were explicitly
171 // told not to (kNoReflowPrincipalList).
172 bool generateReflowCommand
= true;
174 if (kNoReflowPrincipalList
== aListID
) {
175 generateReflowCommand
= false;
178 nsPresContext
* pc
= PresContext();
179 nsContainerFrame
* lastParent
= nullptr;
181 //XXXfr probably should use StealFrame here. I'm not sure if we need to
182 // check the overflow lists atm, but we'll need a prescontext lookup
183 // for overflow containers once we can split abspos elements with
184 // inline containing blocks.
185 nsIFrame
* oldFrameNextContinuation
= aOldFrame
->GetNextContinuation();
186 nsContainerFrame
* parent
=
187 static_cast<nsContainerFrame
*>(aOldFrame
->GetParent());
188 parent
->StealFrame(pc
, aOldFrame
, true);
189 aOldFrame
->Destroy();
190 aOldFrame
= oldFrameNextContinuation
;
191 if (parent
!= lastParent
&& generateReflowCommand
) {
193 FrameNeedsReflow(parent
, nsIPresShell::eTreeChange
,
194 NS_FRAME_HAS_DIRTY_CHILDREN
);
202 nsContainerFrame::DestroyAbsoluteFrames(nsIFrame
* aDestructRoot
)
204 if (IsAbsoluteContainer()) {
205 GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot
);
206 MarkAsNotAbsoluteContainingBlock();
211 nsContainerFrame::SafelyDestroyFrameListProp(nsIFrame
* aDestructRoot
,
212 nsIPresShell
* aPresShell
,
213 FramePropertyTable
* aPropTable
,
214 const FramePropertyDescriptor
* aProp
)
216 // Note that the last frame can be removed through another route and thus
217 // delete the property -- that's why we fetch the property again before
218 // removing each frame rather than fetching it once and iterating the list.
219 while (nsFrameList
* frameList
=
220 static_cast<nsFrameList
*>(aPropTable
->Get(this, aProp
))) {
221 nsIFrame
* frame
= frameList
->RemoveFirstChild();
222 if (MOZ_LIKELY(frame
)) {
223 frame
->DestroyFrom(aDestructRoot
);
225 aPropTable
->Remove(this, aProp
);
226 frameList
->Delete(aPresShell
);
233 nsContainerFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
235 // Prevent event dispatch during destruction.
237 GetView()->SetFrame(nullptr);
240 DestroyAbsoluteFrames(aDestructRoot
);
242 // Destroy frames on the principal child list.
243 mFrames
.DestroyFramesFrom(aDestructRoot
);
245 // Destroy frames on the auxiliary frame lists and delete the lists.
246 nsPresContext
* pc
= PresContext();
247 nsIPresShell
* shell
= pc
->PresShell();
248 FramePropertyTable
* props
= pc
->PropertyTable();
249 SafelyDestroyFrameListProp(aDestructRoot
, shell
, props
, OverflowProperty());
251 MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers
) ||
252 !(props
->Get(this, nsContainerFrame::OverflowContainersProperty()) ||
253 props
->Get(this, nsContainerFrame::ExcessOverflowContainersProperty())),
254 "this type of frame should't have overflow containers");
256 SafelyDestroyFrameListProp(aDestructRoot
, shell
, props
,
257 OverflowContainersProperty());
258 SafelyDestroyFrameListProp(aDestructRoot
, shell
, props
,
259 ExcessOverflowContainersProperty());
261 nsSplittableFrame::DestroyFrom(aDestructRoot
);
264 /////////////////////////////////////////////////////////////////////////////
265 // Child frame enumeration
268 nsContainerFrame::GetChildList(ChildListID aListID
) const
270 // We only know about the principal child list and the overflow lists.
274 case kOverflowList
: {
275 nsFrameList
* list
= GetOverflowFrames();
276 return list
? *list
: nsFrameList::EmptyList();
278 case kOverflowContainersList
: {
280 GetPropTableFrames(PresContext(), OverflowContainersProperty());
281 return list
? *list
: nsFrameList::EmptyList();
283 case kExcessOverflowContainersList
: {
285 GetPropTableFrames(PresContext(), ExcessOverflowContainersProperty());
286 return list
? *list
: nsFrameList::EmptyList();
289 return nsSplittableFrame::GetChildList(aListID
);
293 static void AppendIfNonempty(const nsIFrame
* aFrame
,
294 FramePropertyTable
* aPropTable
,
295 const FramePropertyDescriptor
* aProperty
,
296 nsTArray
<nsIFrame::ChildList
>* aLists
,
297 nsIFrame::ChildListID aListID
)
299 nsFrameList
* list
= static_cast<nsFrameList
*>(
300 aPropTable
->Get(aFrame
, aProperty
));
302 list
->AppendIfNonempty(aLists
, aListID
);
307 nsContainerFrame::GetChildLists(nsTArray
<ChildList
>* aLists
) const
309 mFrames
.AppendIfNonempty(aLists
, kPrincipalList
);
310 FramePropertyTable
* propTable
= PresContext()->PropertyTable();
311 ::AppendIfNonempty(this, propTable
, OverflowProperty(),
312 aLists
, kOverflowList
);
313 if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers
)) {
314 ::AppendIfNonempty(this, propTable
, OverflowContainersProperty(),
315 aLists
, kOverflowContainersList
);
316 ::AppendIfNonempty(this, propTable
, ExcessOverflowContainersProperty(),
317 aLists
, kExcessOverflowContainersList
);
319 nsSplittableFrame::GetChildLists(aLists
);
322 /////////////////////////////////////////////////////////////////////////////
326 nsContainerFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
327 const nsRect
& aDirtyRect
,
328 const nsDisplayListSet
& aLists
)
330 DisplayBorderBackgroundOutline(aBuilder
, aLists
);
332 BuildDisplayListForNonBlockChildren(aBuilder
, aDirtyRect
, aLists
);
336 nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder
* aBuilder
,
337 const nsRect
& aDirtyRect
,
338 const nsDisplayListSet
& aLists
,
341 nsIFrame
* kid
= mFrames
.FirstChild();
342 // Put each child's background directly onto the content list
343 nsDisplayListSet
set(aLists
, aLists
.Content());
344 // The children should be in content order
346 BuildDisplayListForChild(aBuilder
, kid
, aDirtyRect
, set
, aFlags
);
347 kid
= kid
->GetNextSibling();
352 nsContainerFrame::ChildIsDirty(nsIFrame
* aChild
)
354 NS_ASSERTION(NS_SUBTREE_DIRTY(aChild
), "child isn't actually dirty");
356 AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN
);
360 nsContainerFrame::IsLeaf() const
366 nsContainerFrame::PeekOffsetNoAmount(bool aForward
, int32_t* aOffset
)
368 NS_ASSERTION (aOffset
&& *aOffset
<= 1, "aOffset out of range");
369 // Don't allow the caret to stay in an empty (leaf) container frame.
374 nsContainerFrame::PeekOffsetCharacter(bool aForward
, int32_t* aOffset
,
375 bool aRespectClusters
)
377 NS_ASSERTION (aOffset
&& *aOffset
<= 1, "aOffset out of range");
378 // Don't allow the caret to stay in an empty (leaf) container frame.
382 /////////////////////////////////////////////////////////////////////////////
383 // Helper member functions
386 ReparentFrameViewTo(nsIFrame
* aFrame
,
387 nsViewManager
* aViewManager
,
388 nsView
* aNewParentView
,
389 nsView
* aOldParentView
)
392 // XXX What to do about placeholder views for "position: fixed" elements?
393 // They should be reparented too.
395 // Does aFrame have a view?
396 if (aFrame
->HasView()) {
398 if (aFrame
->GetType() == nsGkAtoms::menuPopupFrame
) {
399 // This view must be parented by the root view, don't reparent it.
403 nsView
* view
= aFrame
->GetView();
404 // Verify that the current parent view is what we think it is
405 //nsView* parentView;
406 //NS_ASSERTION(parentView == aOldParentView, "unexpected parent view");
408 aViewManager
->RemoveChild(view
);
410 // The view will remember the Z-order and other attributes that have been set on it.
411 nsView
* insertBefore
= nsLayoutUtils::FindSiblingViewFor(aNewParentView
, aFrame
);
412 aViewManager
->InsertChild(aNewParentView
, view
, insertBefore
, insertBefore
!= nullptr);
414 nsIFrame::ChildListIterator
lists(aFrame
);
415 for (; !lists
.IsDone(); lists
.Next()) {
416 // Iterate the child frames, and check each child frame to see if it has
418 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
419 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
420 ReparentFrameViewTo(childFrames
.get(), aViewManager
,
421 aNewParentView
, aOldParentView
);
430 nsContainerFrame::CreateViewForFrame(nsIFrame
* aFrame
,
433 if (aFrame
->HasView()) {
437 // If we don't yet have a view, see if we need a view
438 if (!aForce
&& !aFrame
->NeedsView()) {
443 nsView
* parentView
= aFrame
->GetParent()->GetClosestView();
444 NS_ASSERTION(parentView
, "no parent with view");
446 nsViewManager
* viewManager
= parentView
->GetViewManager();
447 NS_ASSERTION(viewManager
, "null view manager");
450 nsView
* view
= viewManager
->CreateView(aFrame
->GetRect(), parentView
);
452 SyncFrameViewProperties(aFrame
->PresContext(), aFrame
, nullptr, view
);
454 nsView
* insertBefore
= nsLayoutUtils::FindSiblingViewFor(parentView
, aFrame
);
455 // we insert this view 'above' the insertBefore view, unless insertBefore is null,
456 // in which case we want to call with aAbove == false to insert at the beginning
458 viewManager
->InsertChild(parentView
, view
, insertBefore
, insertBefore
!= nullptr);
460 // REVIEW: Don't create a widget for fixed-pos elements anymore.
461 // ComputeRepaintRegionForCopy will calculate the right area to repaint
463 // Reparent views on any child frames (or their descendants) to this
464 // view. We can just call ReparentFrameViewTo on this frame because
465 // we know this frame has no view, so it will crawl the children. Also,
466 // we know that any descendants with views must have 'parentView' as their
468 ReparentFrameViewTo(aFrame
, viewManager
, view
, parentView
);
471 aFrame
->SetView(view
);
473 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS
,
474 ("nsContainerFrame::CreateViewForFrame: frame=%p view=%p",
479 * Position the view associated with |aKidFrame|, if there is one. A
480 * container frame should call this method after positioning a frame,
481 * but before |Reflow|.
484 nsContainerFrame::PositionFrameView(nsIFrame
* aKidFrame
)
486 nsIFrame
* parentFrame
= aKidFrame
->GetParent();
487 if (!aKidFrame
->HasView() || !parentFrame
)
490 nsView
* view
= aKidFrame
->GetView();
491 nsViewManager
* vm
= view
->GetViewManager();
493 nsView
* ancestorView
= parentFrame
->GetClosestView(&pt
);
495 if (ancestorView
!= view
->GetParent()) {
496 NS_ASSERTION(ancestorView
== view
->GetParent()->GetParent(),
497 "Allowed only one anonymous view between frames");
498 // parentFrame is responsible for positioning aKidFrame's view
503 pt
+= aKidFrame
->GetPosition();
504 vm
->MoveViewTo(view
, pt
.x
, pt
.y
);
508 nsContainerFrame::ReparentFrameView(nsPresContext
* aPresContext
,
509 nsIFrame
* aChildFrame
,
510 nsIFrame
* aOldParentFrame
,
511 nsIFrame
* aNewParentFrame
)
513 NS_PRECONDITION(aChildFrame
, "null child frame pointer");
514 NS_PRECONDITION(aOldParentFrame
, "null old parent frame pointer");
515 NS_PRECONDITION(aNewParentFrame
, "null new parent frame pointer");
516 NS_PRECONDITION(aOldParentFrame
!= aNewParentFrame
, "same old and new parent frame");
518 // See if either the old parent frame or the new parent frame have a view
519 while (!aOldParentFrame
->HasView() && !aNewParentFrame
->HasView()) {
520 // Walk up both the old parent frame and the new parent frame nodes
521 // stopping when we either find a common parent or views for one
522 // or both of the frames.
524 // This works well in the common case where we push/pull and the old parent
525 // frame and the new parent frame are part of the same flow. They will
526 // typically be the same distance (height wise) from the
527 aOldParentFrame
= aOldParentFrame
->GetParent();
528 aNewParentFrame
= aNewParentFrame
->GetParent();
530 // We should never walk all the way to the root frame without finding
532 NS_ASSERTION(aOldParentFrame
&& aNewParentFrame
, "didn't find view");
534 // See if we reached a common ancestor
535 if (aOldParentFrame
== aNewParentFrame
) {
540 // See if we found a common parent frame
541 if (aOldParentFrame
== aNewParentFrame
) {
542 // We found a common parent and there are no views between the old parent
543 // and the common parent or the new parent frame and the common parent.
544 // Because neither the old parent frame nor the new parent frame have views,
545 // then any child views don't need reparenting
549 // We found views for one or both of the ancestor frames before we
550 // found a common ancestor.
551 nsView
* oldParentView
= aOldParentFrame
->GetClosestView();
552 nsView
* newParentView
= aNewParentFrame
->GetClosestView();
554 // See if the old parent frame and the new parent frame are in the
555 // same view sub-hierarchy. If they are then we don't have to do
557 if (oldParentView
!= newParentView
) {
558 // They're not so we need to reparent any child views
559 return ReparentFrameViewTo(aChildFrame
, oldParentView
->GetViewManager(), newParentView
,
567 nsContainerFrame::ReparentFrameViewList(nsPresContext
* aPresContext
,
568 const nsFrameList
& aChildFrameList
,
569 nsIFrame
* aOldParentFrame
,
570 nsIFrame
* aNewParentFrame
)
572 NS_PRECONDITION(aChildFrameList
.NotEmpty(), "empty child frame list");
573 NS_PRECONDITION(aOldParentFrame
, "null old parent frame pointer");
574 NS_PRECONDITION(aNewParentFrame
, "null new parent frame pointer");
575 NS_PRECONDITION(aOldParentFrame
!= aNewParentFrame
, "same old and new parent frame");
577 // See if either the old parent frame or the new parent frame have a view
578 while (!aOldParentFrame
->HasView() && !aNewParentFrame
->HasView()) {
579 // Walk up both the old parent frame and the new parent frame nodes
580 // stopping when we either find a common parent or views for one
581 // or both of the frames.
583 // This works well in the common case where we push/pull and the old parent
584 // frame and the new parent frame are part of the same flow. They will
585 // typically be the same distance (height wise) from the
586 aOldParentFrame
= aOldParentFrame
->GetParent();
587 aNewParentFrame
= aNewParentFrame
->GetParent();
589 // We should never walk all the way to the root frame without finding
591 NS_ASSERTION(aOldParentFrame
&& aNewParentFrame
, "didn't find view");
593 // See if we reached a common ancestor
594 if (aOldParentFrame
== aNewParentFrame
) {
600 // See if we found a common parent frame
601 if (aOldParentFrame
== aNewParentFrame
) {
602 // We found a common parent and there are no views between the old parent
603 // and the common parent or the new parent frame and the common parent.
604 // Because neither the old parent frame nor the new parent frame have views,
605 // then any child views don't need reparenting
609 // We found views for one or both of the ancestor frames before we
610 // found a common ancestor.
611 nsView
* oldParentView
= aOldParentFrame
->GetClosestView();
612 nsView
* newParentView
= aNewParentFrame
->GetClosestView();
614 // See if the old parent frame and the new parent frame are in the
615 // same view sub-hierarchy. If they are then we don't have to do
617 if (oldParentView
!= newParentView
) {
618 nsViewManager
* viewManager
= oldParentView
->GetViewManager();
620 // They're not so we need to reparent any child views
621 for (nsFrameList::Enumerator
e(aChildFrameList
); !e
.AtEnd(); e
.Next()) {
622 ReparentFrameViewTo(e
.get(), viewManager
, newParentView
, oldParentView
);
630 GetPresContextContainerWidget(nsPresContext
* aPresContext
)
632 nsCOMPtr
<nsISupports
> container
= aPresContext
->Document()->GetContainer();
633 nsCOMPtr
<nsIBaseWindow
> baseWindow
= do_QueryInterface(container
);
637 nsCOMPtr
<nsIWidget
> mainWidget
;
638 baseWindow
->GetMainWidget(getter_AddRefs(mainWidget
));
643 IsTopLevelWidget(nsIWidget
* aWidget
)
645 nsWindowType windowType
;
646 aWidget
->GetWindowType(windowType
);
647 return windowType
== eWindowType_toplevel
||
648 windowType
== eWindowType_dialog
||
649 windowType
== eWindowType_sheet
;
650 // popups aren't toplevel so they're not handled here
654 nsContainerFrame::SyncWindowProperties(nsPresContext
* aPresContext
,
657 nsRenderingContext
* aRC
)
660 if (!aView
|| !nsCSSRendering::IsCanvasFrame(aFrame
) || !aView
->HasWidget())
663 nsIWidget
* windowWidget
= GetPresContextContainerWidget(aPresContext
);
664 if (!windowWidget
|| !IsTopLevelWidget(windowWidget
))
667 nsViewManager
* vm
= aView
->GetViewManager();
668 nsView
* rootView
= vm
->GetRootView();
670 if (aView
!= rootView
)
673 Element
* rootElement
= aPresContext
->Document()->GetRootElement();
674 if (!rootElement
|| !rootElement
->IsXUL()) {
675 // Scrollframes use native widgets which don't work well with
676 // translucent windows, at least in Windows XP. So if the document
677 // has a root scrollrame it's useless to try to make it transparent,
678 // we'll just get something broken.
679 // nsCSSFrameConstructor::ConstructRootFrame constructs root
680 // scrollframes whenever the root element is not a XUL element, so
681 // we test for that here. We can't just call
682 // presShell->GetRootScrollFrame() since that might not have
683 // been constructed yet.
684 // We can change this to allow translucent toplevel HTML documents
685 // (e.g. to do something like Dashboard widgets), once we
686 // have broad support for translucent scrolled documents, but be
687 // careful because apparently some Firefox extensions expect
688 // openDialog("something.html") to produce an opaque window
689 // even if the HTML doesn't have a background-color set.
693 nsIFrame
*rootFrame
= aPresContext
->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
697 nsTransparencyMode mode
= nsLayoutUtils::GetFrameTransparency(aFrame
, rootFrame
);
698 nsIWidget
* viewWidget
= aView
->GetWidget();
699 viewWidget
->SetTransparencyMode(mode
);
700 windowWidget
->SetWindowShadowStyle(rootFrame
->StyleUIReset()->mWindowShadow
);
705 nsBoxLayoutState
aState(aPresContext
, aRC
);
706 nsSize minSize
= rootFrame
->GetMinSize(aState
);
707 nsSize maxSize
= rootFrame
->GetMaxSize(aState
);
709 SetSizeConstraints(aPresContext
, windowWidget
, minSize
, maxSize
);
713 void nsContainerFrame::SetSizeConstraints(nsPresContext
* aPresContext
,
715 const nsSize
& aMinSize
,
716 const nsSize
& aMaxSize
)
718 nsIntSize
devMinSize(aPresContext
->AppUnitsToDevPixels(aMinSize
.width
),
719 aPresContext
->AppUnitsToDevPixels(aMinSize
.height
));
720 nsIntSize
devMaxSize(aMaxSize
.width
== NS_INTRINSICSIZE
? NS_MAXSIZE
:
721 aPresContext
->AppUnitsToDevPixels(aMaxSize
.width
),
722 aMaxSize
.height
== NS_INTRINSICSIZE
? NS_MAXSIZE
:
723 aPresContext
->AppUnitsToDevPixels(aMaxSize
.height
));
724 widget::SizeConstraints
constraints(devMinSize
, devMaxSize
);
726 // The sizes are in inner window sizes, so convert them into outer window sizes.
727 // Use a size of (200, 200) as only the difference between the inner and outer
729 nsIntSize windowSize
= aWidget
->ClientToWindowSize(nsIntSize(200, 200));
730 if (constraints
.mMinSize
.width
)
731 constraints
.mMinSize
.width
+= windowSize
.width
- 200;
732 if (constraints
.mMinSize
.height
)
733 constraints
.mMinSize
.height
+= windowSize
.height
- 200;
734 if (constraints
.mMaxSize
.width
!= NS_MAXSIZE
)
735 constraints
.mMaxSize
.width
+= windowSize
.width
- 200;
736 if (constraints
.mMaxSize
.height
!= NS_MAXSIZE
)
737 constraints
.mMaxSize
.height
+= windowSize
.height
- 200;
739 aWidget
->SetSizeConstraints(constraints
);
743 nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext
* aPresContext
,
746 const nsRect
& aVisualOverflowArea
,
753 // Make sure the view is sized and positioned correctly
754 if (0 == (aFlags
& NS_FRAME_NO_MOVE_VIEW
)) {
755 PositionFrameView(aFrame
);
758 if (0 == (aFlags
& NS_FRAME_NO_SIZE_VIEW
)) {
759 nsViewManager
* vm
= aView
->GetViewManager();
761 vm
->ResizeView(aView
, aVisualOverflowArea
, true);
766 nsContainerFrame::SyncFrameViewProperties(nsPresContext
* aPresContext
,
768 nsStyleContext
* aStyleContext
,
772 NS_ASSERTION(!aStyleContext
|| aFrame
->StyleContext() == aStyleContext
,
773 "Wrong style context for frame?");
779 nsViewManager
* vm
= aView
->GetViewManager();
781 if (nullptr == aStyleContext
) {
782 aStyleContext
= aFrame
->StyleContext();
785 // Make sure visibility is correct. This only affects nsSubdocumentFrame.
786 if (0 == (aFlags
& NS_FRAME_NO_VISIBILITY
) &&
787 !aFrame
->SupportsVisibilityHidden()) {
788 // See if the view should be hidden or visible
789 vm
->SetViewVisibility(aView
,
790 aStyleContext
->StyleVisibility()->IsVisible()
791 ? nsViewVisibility_kShow
: nsViewVisibility_kHide
);
794 // See if the frame is being relatively positioned or absolutely
796 bool isPositioned
= aFrame
->IsPositioned();
799 bool autoZIndex
= false;
804 // Make sure z-index is correct
805 const nsStylePosition
* position
= aStyleContext
->StylePosition();
807 if (position
->mZIndex
.GetUnit() == eStyleUnit_Integer
) {
808 zIndex
= position
->mZIndex
.GetIntValue();
809 } else if (position
->mZIndex
.GetUnit() == eStyleUnit_Auto
) {
814 vm
->SetViewZIndex(aView
, autoZIndex
, zIndex
);
817 static nscoord
GetCoord(const nsStyleCoord
& aCoord
, nscoord aIfNotCoord
)
819 if (aCoord
.ConvertsToLength()) {
820 return nsRuleNode::ComputeCoordPercentCalc(aCoord
, 0);
826 nsContainerFrame::DoInlineIntrinsicWidth(nsRenderingContext
*aRenderingContext
,
827 InlineIntrinsicWidthData
*aData
,
828 nsLayoutUtils::IntrinsicWidthType aType
)
831 return; // Already added.
833 NS_PRECONDITION(aType
== nsLayoutUtils::MIN_WIDTH
||
834 aType
== nsLayoutUtils::PREF_WIDTH
, "bad type");
836 mozilla::css::Side startSide
, endSide
;
837 if (StyleVisibility()->mDirection
== NS_STYLE_DIRECTION_LTR
) {
838 startSide
= NS_SIDE_LEFT
;
839 endSide
= NS_SIDE_RIGHT
;
841 startSide
= NS_SIDE_RIGHT
;
842 endSide
= NS_SIDE_LEFT
;
845 const nsStylePadding
*stylePadding
= StylePadding();
846 const nsStyleBorder
*styleBorder
= StyleBorder();
847 const nsStyleMargin
*styleMargin
= StyleMargin();
849 // This goes at the beginning no matter how things are broken and how
850 // messy the bidi situations are, since per CSS2.1 section 8.6
851 // (implemented in bug 328168), the startSide border is always on the
853 // This frame is a first-in-flow, but it might have a previous bidi
854 // continuation, in which case that continuation should handle the startSide
856 if (!GetPrevContinuation()) {
857 aData
->currentLine
+=
858 // clamp negative calc() to 0
859 std::max(GetCoord(stylePadding
->mPadding
.Get(startSide
), 0), 0) +
860 styleBorder
->GetComputedBorderWidth(startSide
) +
861 GetCoord(styleMargin
->mMargin
.Get(startSide
), 0);
864 const nsLineList_iterator
* savedLine
= aData
->line
;
865 nsIFrame
* const savedLineContainer
= aData
->lineContainer
;
867 nsContainerFrame
*lastInFlow
;
868 for (nsContainerFrame
*nif
= this; nif
;
869 nif
= static_cast<nsContainerFrame
*>(nif
->GetNextInFlow())) {
870 for (nsIFrame
*kid
= nif
->mFrames
.FirstChild(); kid
;
871 kid
= kid
->GetNextSibling()) {
872 if (aType
== nsLayoutUtils::MIN_WIDTH
)
873 kid
->AddInlineMinWidth(aRenderingContext
,
874 static_cast<InlineMinWidthData
*>(aData
));
876 kid
->AddInlinePrefWidth(aRenderingContext
,
877 static_cast<InlinePrefWidthData
*>(aData
));
880 // After we advance to our next-in-flow, the stored line and line container
881 // may no longer be correct. Just forget them.
882 aData
->line
= nullptr;
883 aData
->lineContainer
= nullptr;
888 aData
->line
= savedLine
;
889 aData
->lineContainer
= savedLineContainer
;
891 // This goes at the end no matter how things are broken and how
892 // messy the bidi situations are, since per CSS2.1 section 8.6
893 // (implemented in bug 328168), the endSide border is always on the
895 // We reached the last-in-flow, but it might have a next bidi
896 // continuation, in which case that continuation should handle
897 // the endSide border.
898 if (!lastInFlow
->GetNextContinuation()) {
899 aData
->currentLine
+=
900 // clamp negative calc() to 0
901 std::max(GetCoord(stylePadding
->mPadding
.Get(endSide
), 0), 0) +
902 styleBorder
->GetComputedBorderWidth(endSide
) +
903 GetCoord(styleMargin
->mMargin
.Get(endSide
), 0);
908 nsContainerFrame::ComputeAutoSize(nsRenderingContext
*aRenderingContext
,
909 nsSize aCBSize
, nscoord aAvailableWidth
,
910 nsSize aMargin
, nsSize aBorder
,
911 nsSize aPadding
, bool aShrinkWrap
)
913 nsSize
result(0xdeadbeef, NS_UNCONSTRAINEDSIZE
);
914 nscoord availBased
= aAvailableWidth
- aMargin
.width
- aBorder
.width
-
916 // replaced elements always shrink-wrap
917 if (aShrinkWrap
|| IsFrameOfType(eReplaced
)) {
918 // don't bother setting it if the result won't be used
919 if (StylePosition()->mWidth
.GetUnit() == eStyleUnit_Auto
) {
920 result
.width
= ShrinkWidthToFit(aRenderingContext
, availBased
);
923 result
.width
= availBased
;
929 * Invokes the WillReflow() function, positions the frame and its view (if
930 * requested), and then calls Reflow(). If the reflow succeeds and the child
931 * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
934 nsContainerFrame::ReflowChild(nsIFrame
* aKidFrame
,
935 nsPresContext
* aPresContext
,
936 nsHTMLReflowMetrics
& aDesiredSize
,
937 const nsHTMLReflowState
& aReflowState
,
941 nsReflowStatus
& aStatus
,
942 nsOverflowContinuationTracker
* aTracker
)
944 NS_PRECONDITION(aReflowState
.frame
== aKidFrame
, "bad reflow state");
948 // Send the WillReflow() notification, and position the child frame
949 // and its view if requested
950 aKidFrame
->WillReflow(aPresContext
);
952 if (NS_FRAME_NO_MOVE_FRAME
!= (aFlags
& NS_FRAME_NO_MOVE_FRAME
)) {
953 aKidFrame
->SetPosition(nsPoint(aX
, aY
));
956 if (0 == (aFlags
& NS_FRAME_NO_MOVE_VIEW
)) {
957 PositionFrameView(aKidFrame
);
960 // Reflow the child frame
961 result
= aKidFrame
->Reflow(aPresContext
, aDesiredSize
, aReflowState
,
964 // If the reflow was successful and the child frame is complete, delete any
965 // next-in-flows, but only if the NO_DELETE_NEXT_IN_FLOW flag isn't set.
966 if (NS_SUCCEEDED(result
) && NS_FRAME_IS_FULLY_COMPLETE(aStatus
) &&
967 !(aFlags
& NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD
)) {
968 nsIFrame
* kidNextInFlow
= aKidFrame
->GetNextInFlow();
970 // Remove all of the childs next-in-flows. Make sure that we ask
971 // the right parent to do the removal (it's possible that the
972 // parent is not this because we are executing pullup code)
973 nsOverflowContinuationTracker::AutoFinish
fini(aTracker
, aKidFrame
);
974 static_cast<nsContainerFrame
*>(kidNextInFlow
->GetParent())
975 ->DeleteNextInFlowChild(aPresContext
, kidNextInFlow
, true);
983 * Position the views of |aFrame|'s descendants. A container frame
984 * should call this method if it moves a frame after |Reflow|.
987 nsContainerFrame::PositionChildViews(nsIFrame
* aFrame
)
989 if (!(aFrame
->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW
)) {
993 // Recursively walk aFrame's child frames.
994 // Process the additional child lists, but skip the popup list as the
995 // view for popups is managed by the parent. Currently only nsMenuFrame
996 // and nsPopupSetFrame have a popupList and during layout will adjust the
997 // view manually to position the popup.
998 ChildListIterator
lists(aFrame
);
999 for (; !lists
.IsDone(); lists
.Next()) {
1000 if (lists
.CurrentID() == kPopupList
) {
1003 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
1004 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
1005 // Position the frame's view (if it has one) otherwise recursively
1006 // process its children
1007 nsIFrame
* childFrame
= childFrames
.get();
1008 if (childFrame
->HasView()) {
1009 PositionFrameView(childFrame
);
1011 PositionChildViews(childFrame
);
1018 * The second half of frame reflow. Does the following:
1019 * - sets the frame's bounds
1020 * - sizes and positions (if requested) the frame's view. If the frame's final
1021 * position differs from the current position and the frame itself does not
1022 * have a view, then any child frames with views are positioned so they stay
1024 * - sets the view's visibility, opacity, content transparency, and clip
1025 * - invoked the DidReflow() function
1028 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
1029 * case. Also implies NS_FRAME_NO_MOVE_VIEW
1030 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
1031 * don't want to automatically sync the frame and view
1032 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
1035 nsContainerFrame::FinishReflowChild(nsIFrame
* aKidFrame
,
1036 nsPresContext
* aPresContext
,
1037 const nsHTMLReflowState
* aReflowState
,
1038 const nsHTMLReflowMetrics
& aDesiredSize
,
1043 nsPoint curOrigin
= aKidFrame
->GetPosition();
1045 if (NS_FRAME_NO_MOVE_FRAME
!= (aFlags
& NS_FRAME_NO_MOVE_FRAME
)) {
1046 aKidFrame
->SetRect(nsRect(aX
, aY
, aDesiredSize
.width
, aDesiredSize
.height
));
1048 aKidFrame
->SetSize(nsSize(aDesiredSize
.width
, aDesiredSize
.height
));
1051 if (aKidFrame
->HasView()) {
1052 nsView
* view
= aKidFrame
->GetView();
1053 // Make sure the frame's view is properly sized and positioned and has
1054 // things like opacity correct
1055 SyncFrameViewAfterReflow(aPresContext
, aKidFrame
, view
,
1056 aDesiredSize
.VisualOverflow(), aFlags
);
1059 if (!(aFlags
& NS_FRAME_NO_MOVE_VIEW
) &&
1060 (curOrigin
.x
!= aX
|| curOrigin
.y
!= aY
)) {
1061 if (!aKidFrame
->HasView()) {
1062 // If the frame has moved, then we need to make sure any child views are
1063 // correctly positioned
1064 PositionChildViews(aKidFrame
);
1068 return aKidFrame
->DidReflow(aPresContext
, aReflowState
, nsDidReflowStatus::FINISHED
);
1072 nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext
* aPresContext
,
1073 const nsHTMLReflowState
& aReflowState
,
1074 nsOverflowAreas
& aOverflowRects
,
1076 nsReflowStatus
& aStatus
)
1078 NS_PRECONDITION(aPresContext
, "null pointer");
1079 nsresult rv
= NS_OK
;
1081 nsFrameList
* overflowContainers
=
1082 GetPropTableFrames(aPresContext
,
1083 OverflowContainersProperty());
1085 NS_ASSERTION(!(overflowContainers
&& GetPrevInFlow()
1086 && static_cast<nsContainerFrame
*>(GetPrevInFlow())
1087 ->GetPropTableFrames(aPresContext
,
1088 ExcessOverflowContainersProperty())),
1089 "conflicting overflow containers lists");
1091 if (!overflowContainers
) {
1092 // Drain excess from previnflow
1093 nsContainerFrame
* prev
= (nsContainerFrame
*) GetPrevInFlow();
1095 nsFrameList
* excessFrames
=
1096 prev
->RemovePropTableFrames(aPresContext
,
1097 ExcessOverflowContainersProperty());
1099 excessFrames
->ApplySetParent(this);
1100 nsContainerFrame::ReparentFrameViewList(aPresContext
, *excessFrames
,
1102 overflowContainers
= excessFrames
;
1103 SetPropTableFrames(aPresContext
, overflowContainers
,
1104 OverflowContainersProperty());
1109 // Our own excess overflow containers from a previous reflow can still be
1110 // present if our next-in-flow hasn't been reflown yet.
1111 nsFrameList
* selfExcessOCFrames
=
1112 RemovePropTableFrames(aPresContext
, ExcessOverflowContainersProperty());
1113 if (selfExcessOCFrames
) {
1114 if (overflowContainers
) {
1115 overflowContainers
->AppendFrames(nullptr, *selfExcessOCFrames
);
1116 selfExcessOCFrames
->Delete(aPresContext
->PresShell());
1118 overflowContainers
= selfExcessOCFrames
;
1119 SetPropTableFrames(aPresContext
, overflowContainers
,
1120 OverflowContainersProperty());
1123 if (!overflowContainers
) {
1124 return NS_OK
; // nothing to reflow
1127 nsOverflowContinuationTracker
tracker(aPresContext
, this, false, false);
1128 bool shouldReflowAllKids
= aReflowState
.ShouldReflowAllKids();
1130 for (nsIFrame
* frame
= overflowContainers
->FirstChild(); frame
;
1131 frame
= frame
->GetNextSibling()) {
1132 if (frame
->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
1133 // frame's prevInFlow has moved, skip reflowing this frame;
1134 // it will get reflowed once it's been placed
1137 // If the available vertical height has changed, we need to reflow
1138 // even if the frame isn't dirty.
1139 if (shouldReflowAllKids
|| NS_SUBTREE_DIRTY(frame
)) {
1141 nsIFrame
* prevInFlow
= frame
->GetPrevInFlow();
1142 NS_ASSERTION(prevInFlow
,
1143 "overflow container frame must have a prev-in-flow");
1144 NS_ASSERTION(frame
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
,
1145 "overflow container frame must have overflow container bit set");
1146 nsRect prevRect
= prevInFlow
->GetRect();
1148 // Initialize reflow params
1149 nsSize
availSpace(prevRect
.width
, aReflowState
.availableHeight
);
1150 nsHTMLReflowMetrics desiredSize
;
1151 nsHTMLReflowState
frameState(aPresContext
, aReflowState
,
1153 nsReflowStatus frameStatus
;
1156 rv
= ReflowChild(frame
, aPresContext
, desiredSize
, frameState
,
1157 prevRect
.x
, 0, aFlags
, frameStatus
, &tracker
);
1158 NS_ENSURE_SUCCESS(rv
, rv
);
1159 //XXXfr Do we need to override any shrinkwrap effects here?
1160 // e.g. desiredSize.width = prevRect.width;
1161 rv
= FinishReflowChild(frame
, aPresContext
, &frameState
, desiredSize
,
1162 prevRect
.x
, 0, aFlags
);
1163 NS_ENSURE_SUCCESS(rv
, rv
);
1165 // Handle continuations
1166 if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus
)) {
1167 if (frame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
1168 // Abspos frames can't cause their parent to be incomplete,
1169 // only overflow incomplete.
1170 NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus
);
1173 NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus
),
1174 "overflow container frames can't be incomplete, only overflow-incomplete");
1177 // Acquire a next-in-flow, creating it if necessary
1178 nsIFrame
* nif
= frame
->GetNextInFlow();
1180 NS_ASSERTION(frameStatus
& NS_FRAME_REFLOW_NEXTINFLOW
,
1181 "Someone forgot a REFLOW_NEXTINFLOW flag");
1182 nif
= aPresContext
->PresShell()->FrameConstructor()->
1183 CreateContinuingFrame(aPresContext
, frame
, this);
1185 else if (!(nif
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1186 // used to be a normal next-in-flow; steal it from the child list
1187 rv
= static_cast<nsContainerFrame
*>(nif
->GetParent())
1188 ->StealFrame(aPresContext
, nif
);
1189 NS_ENSURE_SUCCESS(rv
, rv
);
1192 tracker
.Insert(nif
, frameStatus
);
1194 NS_MergeReflowStatusInto(&aStatus
, frameStatus
);
1195 // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
1196 // but we have some unsplittable frames that, when taller than
1197 // availableHeight will push zero-height content into a next-in-flow.
1200 tracker
.Skip(frame
, aStatus
);
1201 if (aReflowState
.mFloatManager
)
1202 nsBlockFrame::RecoverFloatsFor(frame
, *aReflowState
.mFloatManager
);
1204 ConsiderChildOverflow(aOverflowRects
, frame
);
1211 nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder
* aBuilder
,
1212 const nsRect
& aDirtyRect
,
1213 const nsDisplayListSet
& aLists
)
1215 nsFrameList
* overflowconts
=
1216 GetPropTableFrames(PresContext(), OverflowContainersProperty());
1217 if (overflowconts
) {
1218 for (nsIFrame
* frame
= overflowconts
->FirstChild(); frame
;
1219 frame
= frame
->GetNextSibling()) {
1220 BuildDisplayListForChild(aBuilder
, frame
, aDirtyRect
, aLists
);
1226 TryRemoveFrame(nsIFrame
* aFrame
, FramePropertyTable
* aPropTable
,
1227 const FramePropertyDescriptor
* aProp
, nsIFrame
* aChildToRemove
)
1229 nsFrameList
* list
= static_cast<nsFrameList
*>(aPropTable
->Get(aFrame
, aProp
));
1230 if (list
&& list
->StartRemoveFrame(aChildToRemove
)) {
1231 // aChildToRemove *may* have been removed from this list.
1232 if (list
->IsEmpty()) {
1233 aPropTable
->Remove(aFrame
, aProp
);
1234 list
->Delete(aFrame
->PresContext()->PresShell());
1242 nsContainerFrame::StealFrame(nsPresContext
* aPresContext
,
1247 if (!mFrames
.ContainsFrame(aChild
)) {
1248 nsFrameList
* list
= GetOverflowFrames();
1249 if (!list
|| !list
->ContainsFrame(aChild
)) {
1250 FramePropertyTable
* propTable
= aPresContext
->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
= aPresContext
->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(aPresContext
);
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 in aNextInFlowResult <b>if and only if</b> a new frame is
1335 * created; otherwise nullptr is returned in aNextInFlowResult.
1338 nsContainerFrame::CreateNextInFlow(nsPresContext
* aPresContext
,
1340 nsIFrame
*& aNextInFlowResult
)
1342 NS_PRECONDITION(GetType() != nsGkAtoms::blockFrame
,
1343 "you should have called nsBlockFrame::CreateContinuationFor instead");
1344 NS_PRECONDITION(mFrames
.ContainsFrame(aFrame
), "expected an in-flow child frame");
1346 aNextInFlowResult
= nullptr;
1348 nsIFrame
* nextInFlow
= aFrame
->GetNextInFlow();
1349 if (nullptr == nextInFlow
) {
1350 // Create a continuation frame for the child frame and insert it
1351 // into our child list.
1352 nextInFlow
= aPresContext
->PresShell()->FrameConstructor()->
1353 CreateContinuingFrame(aPresContext
, aFrame
, this);
1354 mFrames
.InsertFrame(nullptr, aFrame
, nextInFlow
);
1356 NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES
,
1357 ("nsContainerFrame::CreateNextInFlow: frame=%p nextInFlow=%p",
1358 aFrame
, nextInFlow
));
1360 aNextInFlowResult
= nextInFlow
;
1366 * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
1370 nsContainerFrame::DeleteNextInFlowChild(nsPresContext
* aPresContext
,
1371 nsIFrame
* aNextInFlow
,
1372 bool aDeletingEmptyFrames
)
1375 nsIFrame
* prevInFlow
= aNextInFlow
->GetPrevInFlow();
1377 NS_PRECONDITION(prevInFlow
, "bad prev-in-flow");
1379 // If the next-in-flow has a next-in-flow then delete it, too (and
1380 // delete it first).
1381 // Do this in a loop so we don't overflow the stack for frames
1382 // with very many next-in-flows
1383 nsIFrame
* nextNextInFlow
= aNextInFlow
->GetNextInFlow();
1384 if (nextNextInFlow
) {
1385 nsAutoTArray
<nsIFrame
*, 8> frames
;
1386 for (nsIFrame
* f
= nextNextInFlow
; f
; f
= f
->GetNextInFlow()) {
1387 frames
.AppendElement(f
);
1389 for (int32_t i
= frames
.Length() - 1; i
>= 0; --i
) {
1390 nsIFrame
* delFrame
= frames
.ElementAt(i
);
1391 static_cast<nsContainerFrame
*>(delFrame
->GetParent())
1392 ->DeleteNextInFlowChild(aPresContext
, delFrame
, aDeletingEmptyFrames
);
1396 // Take the next-in-flow out of the parent's child list
1397 DebugOnly
<nsresult
> rv
= StealFrame(aPresContext
, aNextInFlow
);
1398 NS_ASSERTION(NS_SUCCEEDED(rv
), "StealFrame failure");
1401 if (aDeletingEmptyFrames
) {
1402 nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow
);
1406 // Delete the next-in-flow frame and its descendants. This will also
1407 // remove it from its next-in-flow/prev-in-flow chain.
1408 aNextInFlow
->Destroy();
1410 NS_POSTCONDITION(!prevInFlow
->GetNextInFlow(), "non null next-in-flow");
1414 * Set the frames on the overflow list
1417 nsContainerFrame::SetOverflowFrames(nsPresContext
* aPresContext
,
1418 const nsFrameList
& aOverflowFrames
)
1420 NS_PRECONDITION(aOverflowFrames
.NotEmpty(), "Shouldn't be called");
1421 nsFrameList
* newList
= new (aPresContext
->PresShell()) nsFrameList(aOverflowFrames
);
1423 aPresContext
->PropertyTable()->Set(this, OverflowProperty(), newList
);
1427 nsContainerFrame::GetPropTableFrames(nsPresContext
* aPresContext
,
1428 const FramePropertyDescriptor
* aProperty
) const
1430 FramePropertyTable
* propTable
= aPresContext
->PropertyTable();
1431 return static_cast<nsFrameList
*>(propTable
->Get(this, aProperty
));
1435 nsContainerFrame::RemovePropTableFrames(nsPresContext
* aPresContext
,
1436 const FramePropertyDescriptor
* aProperty
)
1438 FramePropertyTable
* propTable
= aPresContext
->PropertyTable();
1439 return static_cast<nsFrameList
*>(propTable
->Remove(this, aProperty
));
1443 nsContainerFrame::SetPropTableFrames(nsPresContext
* aPresContext
,
1444 nsFrameList
* aFrameList
,
1445 const FramePropertyDescriptor
* aProperty
)
1447 NS_PRECONDITION(aPresContext
&& aProperty
&& aFrameList
, "null ptr");
1449 (aProperty
!= nsContainerFrame::OverflowContainersProperty() &&
1450 aProperty
!= nsContainerFrame::ExcessOverflowContainersProperty()) ||
1451 IsFrameOfType(nsIFrame::eCanContainOverflowContainers
),
1452 "this type of frame can't have overflow containers");
1453 MOZ_ASSERT(!GetPropTableFrames(aPresContext
, aProperty
));
1454 aPresContext
->PropertyTable()->Set(this, aProperty
, aFrameList
);
1458 * Push aFromChild and its next siblings to the next-in-flow. Change the
1459 * geometric parent of each frame that's pushed. If there is no next-in-flow
1460 * the frames are placed on the overflow list (and the geometric parent is
1463 * Updates the next-in-flow's child count. Does <b>not</b> update the
1464 * pusher's child count.
1466 * @param aFromChild the first child frame to push. It is disconnected from
1468 * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's
1469 * an error to push a parent's first child frame
1472 nsContainerFrame::PushChildren(nsPresContext
* aPresContext
,
1473 nsIFrame
* aFromChild
,
1474 nsIFrame
* aPrevSibling
)
1476 NS_PRECONDITION(aFromChild
, "null pointer");
1477 NS_PRECONDITION(aPrevSibling
, "pushing first child");
1478 NS_PRECONDITION(aPrevSibling
->GetNextSibling() == aFromChild
, "bad prev sibling");
1480 // Disconnect aFromChild from its previous sibling
1481 nsFrameList tail
= mFrames
.RemoveFramesAfter(aPrevSibling
);
1483 nsContainerFrame
* nextInFlow
=
1484 static_cast<nsContainerFrame
*>(GetNextInFlow());
1486 // XXX This is not a very good thing to do. If it gets removed
1487 // then remove the copy of this routine that doesn't do this from
1489 // When pushing and pulling frames we need to check for whether any
1490 // views need to be reparented.
1491 for (nsIFrame
* f
= aFromChild
; f
; f
= f
->GetNextSibling()) {
1492 nsContainerFrame::ReparentFrameView(aPresContext
, f
, this, nextInFlow
);
1494 nextInFlow
->mFrames
.InsertFrames(nextInFlow
, nullptr, tail
);
1497 // Add the frames to our overflow list
1498 SetOverflowFrames(aPresContext
, tail
);
1503 * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
1504 * the receiver's overflow list) to the child list.
1506 * Updates this frame's child count and content mapping.
1508 * @return true if any frames were moved and false otherwise
1511 nsContainerFrame::MoveOverflowToChildList(nsPresContext
* aPresContext
)
1513 bool result
= false;
1515 // Check for an overflow list with our prev-in-flow
1516 nsContainerFrame
* prevInFlow
= (nsContainerFrame
*)GetPrevInFlow();
1517 if (nullptr != prevInFlow
) {
1518 AutoFrameListPtr
prevOverflowFrames(aPresContext
,
1519 prevInFlow
->StealOverflowFrames());
1520 if (prevOverflowFrames
) {
1521 // Tables are special; they can have repeated header/footer
1522 // frames on mFrames at this point.
1523 NS_ASSERTION(mFrames
.IsEmpty() || GetType() == nsGkAtoms::tableFrame
,
1524 "bad overflow list");
1525 // When pushing and pulling frames we need to check for whether any
1526 // views need to be reparented.
1527 nsContainerFrame::ReparentFrameViewList(aPresContext
,
1528 *prevOverflowFrames
,
1530 mFrames
.AppendFrames(this, *prevOverflowFrames
);
1535 // It's also possible that we have an overflow list for ourselves.
1536 return DrainSelfOverflowList() || result
;
1540 nsContainerFrame::DrainSelfOverflowList()
1542 AutoFrameListPtr
overflowFrames(PresContext(), StealOverflowFrames());
1543 if (overflowFrames
) {
1544 NS_ASSERTION(mFrames
.NotEmpty(), "overflow list w/o frames");
1545 mFrames
.AppendFrames(nullptr, *overflowFrames
);
1551 nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsPresContext
* aPresContext
,
1552 nsContainerFrame
* aFrame
,
1553 bool aWalkOOFFrames
,
1554 bool aSkipOverflowContainerChildren
)
1555 : mOverflowContList(nullptr),
1556 mPrevOverflowCont(nullptr),
1559 mSkipOverflowContainerChildren(aSkipOverflowContainerChildren
),
1560 mWalkOOFFrames(aWalkOOFFrames
)
1562 NS_PRECONDITION(aFrame
, "null frame pointer");
1563 SetupOverflowContList();
1567 nsOverflowContinuationTracker::SetupOverflowContList()
1569 NS_PRECONDITION(mParent
, "null frame pointer");
1570 NS_PRECONDITION(!mOverflowContList
, "already have list");
1571 nsPresContext
* pc
= mParent
->PresContext();
1572 nsContainerFrame
* nif
=
1573 static_cast<nsContainerFrame
*>(mParent
->GetNextInFlow());
1575 mOverflowContList
= nif
->GetPropTableFrames(pc
,
1576 nsContainerFrame::OverflowContainersProperty());
1577 if (mOverflowContList
) {
1582 if (!mOverflowContList
) {
1583 mOverflowContList
= mParent
->GetPropTableFrames(pc
,
1584 nsContainerFrame::ExcessOverflowContainersProperty());
1585 if (mOverflowContList
) {
1592 * Helper function to walk past overflow continuations whose prev-in-flow
1593 * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
1596 nsOverflowContinuationTracker::SetUpListWalker()
1598 NS_ASSERTION(!mSentry
&& !mPrevOverflowCont
,
1599 "forgot to reset mSentry or mPrevOverflowCont");
1600 if (mOverflowContList
) {
1601 nsIFrame
* cur
= mOverflowContList
->FirstChild();
1602 if (mSkipOverflowContainerChildren
) {
1603 while (cur
&& (cur
->GetPrevInFlow()->GetStateBits()
1604 & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1605 mPrevOverflowCont
= cur
;
1606 cur
= cur
->GetNextSibling();
1608 while (cur
&& (!(cur
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
1609 == mWalkOOFFrames
)) {
1610 mPrevOverflowCont
= cur
;
1611 cur
= cur
->GetNextSibling();
1615 mSentry
= cur
->GetPrevInFlow();
1621 * Helper function to step forward through the overflow continuations list.
1622 * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
1623 * as appropriate. May only be called when we have already set up an
1624 * mOverflowContList; mOverflowContList cannot be null.
1627 nsOverflowContinuationTracker::StepForward()
1629 NS_PRECONDITION(mOverflowContList
, "null list");
1632 if (mPrevOverflowCont
) {
1633 mPrevOverflowCont
= mPrevOverflowCont
->GetNextSibling();
1636 mPrevOverflowCont
= mOverflowContList
->FirstChild();
1639 // Skip over oof or non-oof frames as appropriate
1640 if (mSkipOverflowContainerChildren
) {
1641 nsIFrame
* cur
= mPrevOverflowCont
->GetNextSibling();
1642 while (cur
&& (!(cur
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
1643 == mWalkOOFFrames
)) {
1644 mPrevOverflowCont
= cur
;
1645 cur
= cur
->GetNextSibling();
1649 // Set up the sentry
1650 mSentry
= (mPrevOverflowCont
->GetNextSibling())
1651 ? mPrevOverflowCont
->GetNextSibling()->GetPrevInFlow()
1656 nsOverflowContinuationTracker::Insert(nsIFrame
* aOverflowCont
,
1657 nsReflowStatus
& aReflowStatus
)
1659 NS_PRECONDITION(aOverflowCont
, "null frame pointer");
1660 NS_PRECONDITION(!mSkipOverflowContainerChildren
|| mWalkOOFFrames
==
1661 !!(aOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
),
1662 "shouldn't insert frame that doesn't match walker type");
1663 NS_PRECONDITION(aOverflowCont
->GetPrevInFlow(),
1664 "overflow containers must have a prev-in-flow");
1665 nsresult rv
= NS_OK
;
1666 bool reparented
= false;
1667 nsPresContext
* presContext
= aOverflowCont
->PresContext();
1668 bool addToList
= !mSentry
|| aOverflowCont
!= mSentry
->GetNextInFlow();
1670 // If we have a list and aOverflowCont is already in it then don't try to
1672 if (addToList
&& aOverflowCont
->GetParent() == mParent
&&
1673 (aOverflowCont
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) &&
1674 mOverflowContList
&& mOverflowContList
->ContainsFrame(aOverflowCont
)) {
1676 mPrevOverflowCont
= aOverflowCont
->GetPrevSibling();
1680 if (aOverflowCont
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) {
1681 // aOverflowCont is in some other overflow container list,
1683 NS_ASSERTION(!(mOverflowContList
&&
1684 mOverflowContList
->ContainsFrame(aOverflowCont
)),
1685 "overflow containers out of order");
1686 rv
= static_cast<nsContainerFrame
*>(aOverflowCont
->GetParent())
1687 ->StealFrame(presContext
, aOverflowCont
);
1688 NS_ENSURE_SUCCESS(rv
, rv
);
1691 aOverflowCont
->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER
);
1693 if (!mOverflowContList
) {
1694 mOverflowContList
= new (presContext
->PresShell()) nsFrameList();
1695 mParent
->SetPropTableFrames(presContext
, mOverflowContList
,
1696 nsContainerFrame::ExcessOverflowContainersProperty());
1699 if (aOverflowCont
->GetParent() != mParent
) {
1700 nsContainerFrame::ReparentFrameView(presContext
, aOverflowCont
,
1701 aOverflowCont
->GetParent(),
1706 // If aOverflowCont has a prev/next-in-flow that might be in
1707 // mOverflowContList we need to find it and insert after/before it to
1708 // maintain the order amongst next-in-flows in this list.
1709 nsIFrame
* pif
= aOverflowCont
->GetPrevInFlow();
1710 nsIFrame
* nif
= aOverflowCont
->GetNextInFlow();
1711 if ((pif
&& pif
->GetParent() == mParent
&& pif
!= mPrevOverflowCont
) ||
1712 (nif
&& nif
->GetParent() == mParent
&& mPrevOverflowCont
)) {
1713 for (nsFrameList::Enumerator
e(*mOverflowContList
); !e
.AtEnd(); e
.Next()) {
1714 nsIFrame
* f
= e
.get();
1716 mPrevOverflowCont
= pif
;
1720 mPrevOverflowCont
= f
->GetPrevSibling();
1726 mOverflowContList
->InsertFrame(mParent
, mPrevOverflowCont
, aOverflowCont
);
1727 aReflowStatus
|= NS_FRAME_REFLOW_NEXTINFLOW
;
1730 // If we need to reflow it, mark it dirty
1731 if (aReflowStatus
& NS_FRAME_REFLOW_NEXTINFLOW
)
1732 aOverflowCont
->AddStateBits(NS_FRAME_IS_DIRTY
);
1734 // It's in our list, just step forward
1736 NS_ASSERTION(mPrevOverflowCont
== aOverflowCont
||
1737 (mSkipOverflowContainerChildren
&&
1738 (mPrevOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) !=
1739 (aOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)),
1740 "OverflowContTracker in unexpected state");
1743 // Convert all non-overflow-container continuations of aOverflowCont
1744 // into overflow containers and move them to our overflow
1745 // tracker. This preserves the invariant that the next-continuations
1746 // of an overflow container are also overflow containers.
1747 nsIFrame
* f
= aOverflowCont
->GetNextContinuation();
1748 if (f
&& (!(f
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) ||
1749 (!reparented
&& f
->GetParent() == mParent
) ||
1750 (reparented
&& f
->GetParent() != mParent
))) {
1751 if (!(f
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1752 nsContainerFrame
* parent
= static_cast<nsContainerFrame
*>(f
->GetParent());
1753 rv
= parent
->StealFrame(presContext
, f
);
1754 NS_ENSURE_SUCCESS(rv
, rv
);
1756 Insert(f
, aReflowStatus
);
1763 nsOverflowContinuationTracker::BeginFinish(nsIFrame
* aChild
)
1765 NS_PRECONDITION(aChild
, "null ptr");
1766 NS_PRECONDITION(aChild
->GetNextInFlow(),
1767 "supposed to call Finish *before* deleting next-in-flow!");
1768 for (nsIFrame
* f
= aChild
; f
; f
= f
->GetNextInFlow()) {
1769 // We'll update these in EndFinish after the next-in-flows are gone.
1770 if (f
== mPrevOverflowCont
) {
1772 mPrevOverflowCont
= nullptr;
1783 nsOverflowContinuationTracker::EndFinish(nsIFrame
* aChild
)
1785 if (!mOverflowContList
) {
1788 // Forget mOverflowContList if it was deleted.
1789 nsPresContext
* pc
= aChild
->PresContext();
1790 FramePropertyTable
* propTable
= pc
->PropertyTable();
1791 nsFrameList
* eoc
= static_cast<nsFrameList
*>(propTable
->Get(mParent
,
1792 nsContainerFrame::ExcessOverflowContainersProperty()));
1793 if (eoc
!= mOverflowContList
) {
1794 nsFrameList
* oc
= static_cast<nsFrameList
*>(propTable
->Get(mParent
,
1795 nsContainerFrame::OverflowContainersProperty()));
1796 if (oc
!= mOverflowContList
) {
1797 // mOverflowContList was deleted
1798 mPrevOverflowCont
= nullptr;
1800 mParent
= static_cast<nsContainerFrame
*>(aChild
->GetParent());
1801 mOverflowContList
= nullptr;
1802 SetupOverflowContList();
1806 // The list survived, update mSentry if needed.
1808 if (!mPrevOverflowCont
) {
1811 mozilla::AutoRestore
<nsIFrame
*> saved(mPrevOverflowCont
);
1812 // step backward to make StepForward() use our current mPrevOverflowCont
1813 mPrevOverflowCont
= mPrevOverflowCont
->GetPrevSibling();
1819 /////////////////////////////////////////////////////////////////////////////
1824 nsContainerFrame::List(FILE* out
, int32_t aIndent
, uint32_t aFlags
) const
1826 ListGeneric(out
, aIndent
, aFlags
);
1828 // Output the children
1829 bool outputOneList
= false;
1830 ChildListIterator
lists(this);
1831 for (; !lists
.IsDone(); lists
.Next()) {
1832 if (outputOneList
) {
1833 IndentBy(out
, aIndent
);
1835 if (lists
.CurrentID() != kPrincipalList
) {
1836 if (!outputOneList
) {
1838 IndentBy(out
, aIndent
);
1840 fputs(mozilla::layout::ChildListName(lists
.CurrentID()), out
);
1841 fprintf(out
, " %p ", &GetChildList(lists
.CurrentID()));
1844 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
1845 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
1846 nsIFrame
* kid
= childFrames
.get();
1847 // Verify the child frame's parent frame pointer is correct
1848 NS_ASSERTION(kid
->GetParent() == this, "bad parent frame pointer");
1850 // Have the child frame list
1851 kid
->List(out
, aIndent
+ 1, aFlags
);
1853 IndentBy(out
, aIndent
);
1855 outputOneList
= true;
1858 if (!outputOneList
) {