layout/generic/nsContainerFrame.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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"
    14 #include "nsRect.h"
    15 #include "nsPoint.h"
    16 #include "nsStyleConsts.h"
    17 #include "nsView.h"
    18 #include "nsIPresShell.h"
    19 #include "nsCOMPtr.h"
    20 #include "nsGkAtoms.h"
    21 #include "nsViewManager.h"
    22 #include "nsIWidget.h"
    23 #include "nsCSSRendering.h"
    24 #include "nsError.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"
    33 #include <algorithm>
    35 #ifdef DEBUG
    36 #undef NOISY
    37 #else
    38 #undef NOISY
    39 #endif
    41 using namespace mozilla;
    42 using namespace mozilla::dom;
    43 using namespace mozilla::layout;
    45 NS_IMPL_FRAMEARENA_HELPERS(nsContainerFrame)
    47 nsContainerFrame::~nsContainerFrame()
    48 {
    49 }
    51 NS_QUERYFRAME_HEAD(nsContainerFrame)
    52   NS_QUERYFRAME_ENTRY(nsContainerFrame)
    53 NS_QUERYFRAME_TAIL_INHERITING(nsSplittableFrame)
    55 void
    56 nsContainerFrame::Init(nsIContent* aContent,
    57                        nsIFrame*   aParent,
    58                        nsIFrame*   aPrevInFlow)
    59 {
    60   nsSplittableFrame::Init(aContent, aParent, aPrevInFlow);
    61   if (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);
    67   }
    68 }
    70 nsresult
    71 nsContainerFrame::SetInitialChildList(ChildListID  aListID,
    72                                       nsFrameList& aChildList)
    73 {
    74   nsresult  result;
    75   if (mFrames.NotEmpty()) {
    76     // We already have child frames which means we've already been
    77     // initialized
    78     NS_NOTREACHED("unexpected second call to SetInitialChildList");
    79     result = NS_ERROR_UNEXPECTED;
    80   } else if (aListID != kPrincipalList) {
    81     // All we know about is the principal child list.
    82     NS_NOTREACHED("unknown frame list");
    83     result = NS_ERROR_INVALID_ARG;
    84   } else {
    85 #ifdef DEBUG
    86     nsFrame::VerifyDirtyBitSet(aChildList);
    87 #endif
    88     mFrames.SetFrames(aChildList);
    89     result = NS_OK;
    90   }
    91   return result;
    92 }
    94 nsresult
    95 nsContainerFrame::AppendFrames(ChildListID  aListID,
    96                                nsFrameList& aFrameList)
    97 {
    98   if (aListID != kPrincipalList) {
    99     if (aListID != kNoReflowPrincipalList)
   100     {
   101       NS_ERROR("unexpected child list");
   102       return NS_ERROR_INVALID_ARG;
   103     }
   104   }
   105   if (aFrameList.NotEmpty()) {
   106     mFrames.AppendFrames(this, aFrameList);
   108     // Ask the parent frame to reflow me.
   109     if (aListID == kPrincipalList)
   110     {
   111       PresContext()->PresShell()->
   112         FrameNeedsReflow(this, nsIPresShell::eTreeChange,
   113                          NS_FRAME_HAS_DIRTY_CHILDREN);
   114     }
   115   }
   116   return NS_OK;
   117 }
   119 nsresult
   120 nsContainerFrame::InsertFrames(ChildListID aListID,
   121                                nsIFrame* aPrevFrame,
   122                                nsFrameList& aFrameList)
   123 {
   124   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
   125                "inserting after sibling frame with different parent");
   127   if (aListID != kPrincipalList) {
   128     if (aListID != kNoReflowPrincipalList)
   129     {
   130       NS_ERROR("unexpected child list");
   131       return NS_ERROR_INVALID_ARG;
   132     }
   133   }
   134   if (aFrameList.NotEmpty()) {
   135     // Insert frames after aPrevFrame
   136     mFrames.InsertFrames(this, aPrevFrame, aFrameList);
   138     if (aListID == kPrincipalList)
   139     {
   140       PresContext()->PresShell()->
   141         FrameNeedsReflow(this, nsIPresShell::eTreeChange,
   142                          NS_FRAME_HAS_DIRTY_CHILDREN);
   143     }
   144   }
   145   return NS_OK;
   146 }
   148 nsresult
   149 nsContainerFrame::RemoveFrame(ChildListID aListID,
   150                               nsIFrame* aOldFrame)
   151 {
   152   if (aListID != kPrincipalList) {
   153     if (kNoReflowPrincipalList != aListID)
   154     {
   155       NS_ERROR("unexpected child list");
   156       return NS_ERROR_INVALID_ARG;
   157     }
   158   }
   160   // Loop and destroy aOldFrame and all of its continuations.
   161   // Request a reflow on the parent frames involved unless we were explicitly
   162   // told not to (kNoReflowPrincipalList).
   163   bool generateReflowCommand = true;
   164   if (kNoReflowPrincipalList == aListID) {
   165     generateReflowCommand = false;
   166   }
   167   nsIPresShell* shell = PresContext()->PresShell();
   168   nsContainerFrame* lastParent = nullptr;
   169   while (aOldFrame) {
   170     //XXXfr probably should use StealFrame here. I'm not sure if we need to
   171     //      check the overflow lists atm, but we'll need a prescontext lookup
   172     //      for overflow containers once we can split abspos elements with
   173     //      inline containing blocks.
   174     nsIFrame* oldFrameNextContinuation = aOldFrame->GetNextContinuation();
   175     nsContainerFrame* parent =
   176       static_cast<nsContainerFrame*>(aOldFrame->GetParent());
   177     parent->StealFrame(aOldFrame, true);
   178     aOldFrame->Destroy();
   179     aOldFrame = oldFrameNextContinuation;
   180     if (parent != lastParent && generateReflowCommand) {
   181       shell->FrameNeedsReflow(parent, nsIPresShell::eTreeChange,
   182                               NS_FRAME_HAS_DIRTY_CHILDREN);
   183       lastParent = parent;
   184     }
   185   }
   186   return NS_OK;
   187 }
   189 void
   190 nsContainerFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot)
   191 {
   192   if (IsAbsoluteContainer()) {
   193     GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot);
   194     MarkAsNotAbsoluteContainingBlock();
   195   }
   196 }
   198 void
   199 nsContainerFrame::SafelyDestroyFrameListProp(nsIFrame* aDestructRoot,
   200                                              nsIPresShell* aPresShell,
   201                                              FramePropertyTable* aPropTable,
   202                                              const FramePropertyDescriptor* aProp)
   203 {
   204   // Note that the last frame can be removed through another route and thus
   205   // delete the property -- that's why we fetch the property again before
   206   // removing each frame rather than fetching it once and iterating the list.
   207   while (nsFrameList* frameList =
   208            static_cast<nsFrameList*>(aPropTable->Get(this, aProp))) {
   209     nsIFrame* frame = frameList->RemoveFirstChild();
   210     if (MOZ_LIKELY(frame)) {
   211       frame->DestroyFrom(aDestructRoot);
   212     } else {
   213       aPropTable->Remove(this, aProp);
   214       frameList->Delete(aPresShell);
   215       return;
   216     }
   217   }
   218 }
   220 void
   221 nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot)
   222 {
   223   // Prevent event dispatch during destruction.
   224   if (HasView()) {
   225     GetView()->SetFrame(nullptr);
   226   }
   228   DestroyAbsoluteFrames(aDestructRoot);
   230   // Destroy frames on the principal child list.
   231   mFrames.DestroyFramesFrom(aDestructRoot);
   233   // Destroy frames on the auxiliary frame lists and delete the lists.
   234   nsPresContext* pc = PresContext();
   235   nsIPresShell* shell = pc->PresShell();
   236   FramePropertyTable* props = pc->PropertyTable();
   237   SafelyDestroyFrameListProp(aDestructRoot, shell, props, OverflowProperty());
   239   MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers) ||
   240              !(props->Get(this, nsContainerFrame::OverflowContainersProperty()) ||
   241                props->Get(this, nsContainerFrame::ExcessOverflowContainersProperty())),
   242              "this type of frame should't have overflow containers");
   244   SafelyDestroyFrameListProp(aDestructRoot, shell, props,
   245                              OverflowContainersProperty());
   246   SafelyDestroyFrameListProp(aDestructRoot, shell, props,
   247                              ExcessOverflowContainersProperty());
   249   nsSplittableFrame::DestroyFrom(aDestructRoot);
   250 }
   252 /////////////////////////////////////////////////////////////////////////////
   253 // Child frame enumeration
   255 const nsFrameList&
   256 nsContainerFrame::GetChildList(ChildListID aListID) const
   257 {
   258   // We only know about the principal child list and the overflow lists.
   259   switch (aListID) {
   260     case kPrincipalList:
   261       return mFrames;
   262     case kOverflowList: {
   263       nsFrameList* list = GetOverflowFrames();
   264       return list ? *list : nsFrameList::EmptyList();
   265     }
   266     case kOverflowContainersList: {
   267       nsFrameList* list = GetPropTableFrames(OverflowContainersProperty());
   268       return list ? *list : nsFrameList::EmptyList();
   269     }
   270     case kExcessOverflowContainersList: {
   271       nsFrameList* list =
   272         GetPropTableFrames(ExcessOverflowContainersProperty());
   273       return list ? *list : nsFrameList::EmptyList();
   274     }
   275     default:
   276       return nsSplittableFrame::GetChildList(aListID);
   277   }
   278 }
   280 static void AppendIfNonempty(const nsIFrame* aFrame,
   281                             FramePropertyTable* aPropTable,
   282                             const FramePropertyDescriptor* aProperty,
   283                             nsTArray<nsIFrame::ChildList>* aLists,
   284                             nsIFrame::ChildListID aListID)
   285 {
   286   nsFrameList* list = static_cast<nsFrameList*>(
   287     aPropTable->Get(aFrame, aProperty));
   288   if (list) {
   289     list->AppendIfNonempty(aLists, aListID);
   290   }
   291 }
   293 void
   294 nsContainerFrame::GetChildLists(nsTArray<ChildList>* aLists) const
   295 {
   296   mFrames.AppendIfNonempty(aLists, kPrincipalList);
   297   FramePropertyTable* propTable = PresContext()->PropertyTable();
   298   ::AppendIfNonempty(this, propTable, OverflowProperty(),
   299                      aLists, kOverflowList);
   300   if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
   301     ::AppendIfNonempty(this, propTable, OverflowContainersProperty(),
   302                        aLists, kOverflowContainersList);
   303     ::AppendIfNonempty(this, propTable, ExcessOverflowContainersProperty(),
   304                        aLists, kExcessOverflowContainersList);
   305   }
   306   nsSplittableFrame::GetChildLists(aLists);
   307 }
   309 /////////////////////////////////////////////////////////////////////////////
   310 // Painting/Events
   312 void
   313 nsContainerFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   314                                    const nsRect&           aDirtyRect,
   315                                    const nsDisplayListSet& aLists)
   316 {
   317   DisplayBorderBackgroundOutline(aBuilder, aLists);
   319   BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
   320 }
   322 void
   323 nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder*   aBuilder,
   324                                                       const nsRect&           aDirtyRect,
   325                                                       const nsDisplayListSet& aLists,
   326                                                       uint32_t                aFlags)
   327 {
   328   nsIFrame* kid = mFrames.FirstChild();
   329   // Put each child's background directly onto the content list
   330   nsDisplayListSet set(aLists, aLists.Content());
   331   // The children should be in content order
   332   while (kid) {
   333     BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, aFlags);
   334     kid = kid->GetNextSibling();
   335   }
   336 }
   338 /* virtual */ void
   339 nsContainerFrame::ChildIsDirty(nsIFrame* aChild)
   340 {
   341   NS_ASSERTION(NS_SUBTREE_DIRTY(aChild), "child isn't actually dirty");
   343   AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   344 }
   346 bool
   347 nsContainerFrame::IsLeaf() const
   348 {
   349   return false;
   350 }
   352 nsIFrame::FrameSearchResult
   353 nsContainerFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
   354 {
   355   NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
   356   // Don't allow the caret to stay in an empty (leaf) container frame.
   357   return CONTINUE_EMPTY;
   358 }
   360 nsIFrame::FrameSearchResult
   361 nsContainerFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
   362                                       bool aRespectClusters)
   363 {
   364   NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
   365   // Don't allow the caret to stay in an empty (leaf) container frame.
   366   return CONTINUE_EMPTY;
   367 }
   369 /////////////////////////////////////////////////////////////////////////////
   370 // Helper member functions
   372 static nsresult
   373 ReparentFrameViewTo(nsIFrame*       aFrame,
   374                     nsViewManager* aViewManager,
   375                     nsView*        aNewParentView,
   376                     nsView*        aOldParentView)
   377 {
   379   // XXX What to do about placeholder views for "position: fixed" elements?
   380   // They should be reparented too.
   382   // Does aFrame have a view?
   383   if (aFrame->HasView()) {
   384 #ifdef MOZ_XUL
   385     if (aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
   386       // This view must be parented by the root view, don't reparent it.
   387       return NS_OK;
   388     }
   389 #endif
   390     nsView* view = aFrame->GetView();
   391     // Verify that the current parent view is what we think it is
   392     //nsView*  parentView;
   393     //NS_ASSERTION(parentView == aOldParentView, "unexpected parent view");
   395     aViewManager->RemoveChild(view);
   397     // The view will remember the Z-order and other attributes that have been set on it.
   398     nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(aNewParentView, aFrame);
   399     aViewManager->InsertChild(aNewParentView, view, insertBefore, insertBefore != nullptr);
   400   } else {
   401     nsIFrame::ChildListIterator lists(aFrame);
   402     for (; !lists.IsDone(); lists.Next()) {
   403       // Iterate the child frames, and check each child frame to see if it has
   404       // a view
   405       nsFrameList::Enumerator childFrames(lists.CurrentList());
   406       for (; !childFrames.AtEnd(); childFrames.Next()) {
   407         ReparentFrameViewTo(childFrames.get(), aViewManager,
   408                             aNewParentView, aOldParentView);
   409       }
   410     }
   411   }
   413   return NS_OK;
   414 }
   416 void
   417 nsContainerFrame::CreateViewForFrame(nsIFrame* aFrame,
   418                                      bool aForce)
   419 {
   420   if (aFrame->HasView()) {
   421     return;
   422   }
   424   // If we don't yet have a view, see if we need a view
   425   if (!aForce && !aFrame->NeedsView()) {
   426     // don't need a view
   427     return;
   428   }
   430   nsView* parentView = aFrame->GetParent()->GetClosestView();
   431   NS_ASSERTION(parentView, "no parent with view");
   433   nsViewManager* viewManager = parentView->GetViewManager();
   434   NS_ASSERTION(viewManager, "null view manager");
   436   // Create a view
   437   nsView* view = viewManager->CreateView(aFrame->GetRect(), parentView);
   439   SyncFrameViewProperties(aFrame->PresContext(), aFrame, nullptr, view);
   441   nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(parentView, aFrame);
   442   // we insert this view 'above' the insertBefore view, unless insertBefore is null,
   443   // in which case we want to call with aAbove == false to insert at the beginning
   444   // in document order
   445   viewManager->InsertChild(parentView, view, insertBefore, insertBefore != nullptr);
   447   // REVIEW: Don't create a widget for fixed-pos elements anymore.
   448   // ComputeRepaintRegionForCopy will calculate the right area to repaint
   449   // when we scroll.
   450   // Reparent views on any child frames (or their descendants) to this
   451   // view. We can just call ReparentFrameViewTo on this frame because
   452   // we know this frame has no view, so it will crawl the children. Also,
   453   // we know that any descendants with views must have 'parentView' as their
   454   // parent view.
   455   ReparentFrameViewTo(aFrame, viewManager, view, parentView);
   457   // Remember our view
   458   aFrame->SetView(view);
   460   NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
   461                ("nsContainerFrame::CreateViewForFrame: frame=%p view=%p",
   462                 aFrame));
   463 }
   465 /**
   466  * Position the view associated with |aKidFrame|, if there is one. A
   467  * container frame should call this method after positioning a frame,
   468  * but before |Reflow|.
   469  */
   470 void
   471 nsContainerFrame::PositionFrameView(nsIFrame* aKidFrame)
   472 {
   473   nsIFrame* parentFrame = aKidFrame->GetParent();
   474   if (!aKidFrame->HasView() || !parentFrame)
   475     return;
   477   nsView* view = aKidFrame->GetView();
   478   nsViewManager* vm = view->GetViewManager();
   479   nsPoint pt;
   480   nsView* ancestorView = parentFrame->GetClosestView(&pt);
   482   if (ancestorView != view->GetParent()) {
   483     NS_ASSERTION(ancestorView == view->GetParent()->GetParent(),
   484                  "Allowed only one anonymous view between frames");
   485     // parentFrame is responsible for positioning aKidFrame's view
   486     // explicitly
   487     return;
   488   }
   490   pt += aKidFrame->GetPosition();
   491   vm->MoveViewTo(view, pt.x, pt.y);
   492 }
   494 nsresult
   495 nsContainerFrame::ReparentFrameView(nsIFrame* aChildFrame,
   496                                     nsIFrame* aOldParentFrame,
   497                                     nsIFrame* aNewParentFrame)
   498 {
   499   NS_PRECONDITION(aChildFrame, "null child frame pointer");
   500   NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
   501   NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
   502   NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
   504   // See if either the old parent frame or the new parent frame have a view
   505   while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
   506     // Walk up both the old parent frame and the new parent frame nodes
   507     // stopping when we either find a common parent or views for one
   508     // or both of the frames.
   509     //
   510     // This works well in the common case where we push/pull and the old parent
   511     // frame and the new parent frame are part of the same flow. They will
   512     // typically be the same distance (height wise) from the
   513     aOldParentFrame = aOldParentFrame->GetParent();
   514     aNewParentFrame = aNewParentFrame->GetParent();
   516     // We should never walk all the way to the root frame without finding
   517     // a view
   518     NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
   520     // See if we reached a common ancestor
   521     if (aOldParentFrame == aNewParentFrame) {
   522       break;
   523     }
   524   }
   526   // See if we found a common parent frame
   527   if (aOldParentFrame == aNewParentFrame) {
   528     // We found a common parent and there are no views between the old parent
   529     // and the common parent or the new parent frame and the common parent.
   530     // Because neither the old parent frame nor the new parent frame have views,
   531     // then any child views don't need reparenting
   532     return NS_OK;
   533   }
   535   // We found views for one or both of the ancestor frames before we
   536   // found a common ancestor.
   537   nsView* oldParentView = aOldParentFrame->GetClosestView();
   538   nsView* newParentView = aNewParentFrame->GetClosestView();
   540   // See if the old parent frame and the new parent frame are in the
   541   // same view sub-hierarchy. If they are then we don't have to do
   542   // anything
   543   if (oldParentView != newParentView) {
   544     // They're not so we need to reparent any child views
   545     return ReparentFrameViewTo(aChildFrame, oldParentView->GetViewManager(), newParentView,
   546                                oldParentView);
   547   }
   549   return NS_OK;
   550 }
   552 nsresult
   553 nsContainerFrame::ReparentFrameViewList(const nsFrameList& aChildFrameList,
   554                                         nsIFrame*          aOldParentFrame,
   555                                         nsIFrame*          aNewParentFrame)
   556 {
   557   NS_PRECONDITION(aChildFrameList.NotEmpty(), "empty child frame list");
   558   NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
   559   NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
   560   NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
   562   // See if either the old parent frame or the new parent frame have a view
   563   while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
   564     // Walk up both the old parent frame and the new parent frame nodes
   565     // stopping when we either find a common parent or views for one
   566     // or both of the frames.
   567     //
   568     // This works well in the common case where we push/pull and the old parent
   569     // frame and the new parent frame are part of the same flow. They will
   570     // typically be the same distance (height wise) from the
   571     aOldParentFrame = aOldParentFrame->GetParent();
   572     aNewParentFrame = aNewParentFrame->GetParent();
   574     // We should never walk all the way to the root frame without finding
   575     // a view
   576     NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
   578     // See if we reached a common ancestor
   579     if (aOldParentFrame == aNewParentFrame) {
   580       break;
   581     }
   582   }
   585   // See if we found a common parent frame
   586   if (aOldParentFrame == aNewParentFrame) {
   587     // We found a common parent and there are no views between the old parent
   588     // and the common parent or the new parent frame and the common parent.
   589     // Because neither the old parent frame nor the new parent frame have views,
   590     // then any child views don't need reparenting
   591     return NS_OK;
   592   }
   594   // We found views for one or both of the ancestor frames before we
   595   // found a common ancestor.
   596   nsView* oldParentView = aOldParentFrame->GetClosestView();
   597   nsView* newParentView = aNewParentFrame->GetClosestView();
   599   // See if the old parent frame and the new parent frame are in the
   600   // same view sub-hierarchy. If they are then we don't have to do
   601   // anything
   602   if (oldParentView != newParentView) {
   603     nsViewManager* viewManager = oldParentView->GetViewManager();
   605     // They're not so we need to reparent any child views
   606     for (nsFrameList::Enumerator e(aChildFrameList); !e.AtEnd(); e.Next()) {
   607       ReparentFrameViewTo(e.get(), viewManager, newParentView, oldParentView);
   608     }
   609   }
   611   return NS_OK;
   612 }
   614 static nsIWidget*
   615 GetPresContextContainerWidget(nsPresContext* aPresContext)
   616 {
   617   nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
   618   nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
   619   if (!baseWindow)
   620     return nullptr;
   622   nsCOMPtr<nsIWidget> mainWidget;
   623   baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
   624   return mainWidget;
   625 }
   627 static bool
   628 IsTopLevelWidget(nsIWidget* aWidget)
   629 {
   630   nsWindowType windowType = aWidget->WindowType();
   631   return windowType == eWindowType_toplevel ||
   632          windowType == eWindowType_dialog ||
   633          windowType == eWindowType_sheet;
   634   // popups aren't toplevel so they're not handled here
   635 }
   637 void
   638 nsContainerFrame::SyncWindowProperties(nsPresContext*       aPresContext,
   639                                        nsIFrame*            aFrame,
   640                                        nsView*             aView,
   641                                        nsRenderingContext*  aRC)
   642 {
   643 #ifdef MOZ_XUL
   644   if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget())
   645     return;
   647   nsIWidget* windowWidget = GetPresContextContainerWidget(aPresContext);
   648   if (!windowWidget || !IsTopLevelWidget(windowWidget))
   649     return;
   651   nsViewManager* vm = aView->GetViewManager();
   652   nsView* rootView = vm->GetRootView();
   654   if (aView != rootView)
   655     return;
   657   Element* rootElement = aPresContext->Document()->GetRootElement();
   658   if (!rootElement || !rootElement->IsXUL()) {
   659     // Scrollframes use native widgets which don't work well with
   660     // translucent windows, at least in Windows XP. So if the document
   661     // has a root scrollrame it's useless to try to make it transparent,
   662     // we'll just get something broken.
   663     // nsCSSFrameConstructor::ConstructRootFrame constructs root
   664     // scrollframes whenever the root element is not a XUL element, so
   665     // we test for that here. We can't just call
   666     // presShell->GetRootScrollFrame() since that might not have
   667     // been constructed yet.
   668     // We can change this to allow translucent toplevel HTML documents
   669     // (e.g. to do something like Dashboard widgets), once we
   670     // have broad support for translucent scrolled documents, but be
   671     // careful because apparently some Firefox extensions expect
   672     // openDialog("something.html") to produce an opaque window
   673     // even if the HTML doesn't have a background-color set.
   674     return;
   675   }
   677   nsIFrame *rootFrame = aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
   678   if (!rootFrame)
   679     return;
   681   nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(aFrame, rootFrame);
   682   nsIWidget* viewWidget = aView->GetWidget();
   683   viewWidget->SetTransparencyMode(mode);
   684   windowWidget->SetWindowShadowStyle(rootFrame->StyleUIReset()->mWindowShadow);
   686   if (!aRC)
   687     return;
   689   nsBoxLayoutState aState(aPresContext, aRC);
   690   nsSize minSize = rootFrame->GetMinSize(aState);
   691   nsSize maxSize = rootFrame->GetMaxSize(aState);
   693   SetSizeConstraints(aPresContext, windowWidget, minSize, maxSize);
   694 #endif
   695 }
   697 void nsContainerFrame::SetSizeConstraints(nsPresContext* aPresContext,
   698                                           nsIWidget* aWidget,
   699                                           const nsSize& aMinSize,
   700                                           const nsSize& aMaxSize)
   701 {
   702   nsIntSize devMinSize(aPresContext->AppUnitsToDevPixels(aMinSize.width),
   703                        aPresContext->AppUnitsToDevPixels(aMinSize.height));
   704   nsIntSize devMaxSize(aMaxSize.width == NS_INTRINSICSIZE ? NS_MAXSIZE :
   705                          aPresContext->AppUnitsToDevPixels(aMaxSize.width),
   706                        aMaxSize.height == NS_INTRINSICSIZE ? NS_MAXSIZE :
   707                          aPresContext->AppUnitsToDevPixels(aMaxSize.height));
   708   widget::SizeConstraints constraints(devMinSize, devMaxSize);
   710   // The sizes are in inner window sizes, so convert them into outer window sizes.
   711   // Use a size of (200, 200) as only the difference between the inner and outer
   712   // size is needed.
   713   nsIntSize windowSize = aWidget->ClientToWindowSize(nsIntSize(200, 200));
   714   if (constraints.mMinSize.width)
   715     constraints.mMinSize.width += windowSize.width - 200;
   716   if (constraints.mMinSize.height)
   717     constraints.mMinSize.height += windowSize.height - 200;
   718   if (constraints.mMaxSize.width != NS_MAXSIZE)
   719     constraints.mMaxSize.width += windowSize.width - 200;
   720   if (constraints.mMaxSize.height != NS_MAXSIZE)
   721     constraints.mMaxSize.height += windowSize.height - 200;
   723   aWidget->SetSizeConstraints(constraints);
   724 }
   726 void
   727 nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
   728                                            nsIFrame*       aFrame,
   729                                            nsView*        aView,
   730                                            const nsRect&   aVisualOverflowArea,
   731                                            uint32_t        aFlags)
   732 {
   733   if (!aView) {
   734     return;
   735   }
   737   // Make sure the view is sized and positioned correctly
   738   if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
   739     PositionFrameView(aFrame);
   740   }
   742   if (0 == (aFlags & NS_FRAME_NO_SIZE_VIEW)) {
   743     nsViewManager* vm = aView->GetViewManager();
   745     vm->ResizeView(aView, aVisualOverflowArea, true);
   746   }
   747 }
   749 void
   750 nsContainerFrame::SyncFrameViewProperties(nsPresContext*  aPresContext,
   751                                           nsIFrame*        aFrame,
   752                                           nsStyleContext*  aStyleContext,
   753                                           nsView*         aView,
   754                                           uint32_t         aFlags)
   755 {
   756   NS_ASSERTION(!aStyleContext || aFrame->StyleContext() == aStyleContext,
   757                "Wrong style context for frame?");
   759   if (!aView) {
   760     return;
   761   }
   763   nsViewManager* vm = aView->GetViewManager();
   765   if (nullptr == aStyleContext) {
   766     aStyleContext = aFrame->StyleContext();
   767   }
   769   // Make sure visibility is correct. This only affects nsSubdocumentFrame.
   770   if (0 == (aFlags & NS_FRAME_NO_VISIBILITY) &&
   771       !aFrame->SupportsVisibilityHidden()) {
   772     // See if the view should be hidden or visible
   773     vm->SetViewVisibility(aView,
   774         aStyleContext->StyleVisibility()->IsVisible()
   775             ? nsViewVisibility_kShow : nsViewVisibility_kHide);
   776   }
   778   // See if the frame is being relatively positioned or absolutely
   779   // positioned
   780   bool isPositioned = aFrame->IsPositioned();
   782   int32_t zIndex = 0;
   783   bool    autoZIndex = false;
   785   if (!isPositioned) {
   786     autoZIndex = true;
   787   } else {
   788     // Make sure z-index is correct
   789     const nsStylePosition* position = aStyleContext->StylePosition();
   791     if (position->mZIndex.GetUnit() == eStyleUnit_Integer) {
   792       zIndex = position->mZIndex.GetIntValue();
   793     } else if (position->mZIndex.GetUnit() == eStyleUnit_Auto) {
   794       autoZIndex = true;
   795     }
   796   }
   798   vm->SetViewZIndex(aView, autoZIndex, zIndex);
   799 }
   801 static nscoord GetCoord(const nsStyleCoord& aCoord, nscoord aIfNotCoord)
   802 {
   803   if (aCoord.ConvertsToLength()) {
   804     return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
   805   }
   806   return aIfNotCoord;
   807 }
   809 void
   810 nsContainerFrame::DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
   811                                          InlineIntrinsicWidthData *aData,
   812                                          nsLayoutUtils::IntrinsicWidthType aType)
   813 {
   814   if (GetPrevInFlow())
   815     return; // Already added.
   817   NS_PRECONDITION(aType == nsLayoutUtils::MIN_WIDTH ||
   818                   aType == nsLayoutUtils::PREF_WIDTH, "bad type");
   820   mozilla::css::Side startSide, endSide;
   821   if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR) {
   822     startSide = NS_SIDE_LEFT;
   823     endSide = NS_SIDE_RIGHT;
   824   } else {
   825     startSide = NS_SIDE_RIGHT;
   826     endSide = NS_SIDE_LEFT;
   827   }
   829   const nsStylePadding *stylePadding = StylePadding();
   830   const nsStyleBorder *styleBorder = StyleBorder();
   831   const nsStyleMargin *styleMargin = StyleMargin();
   833   // This goes at the beginning no matter how things are broken and how
   834   // messy the bidi situations are, since per CSS2.1 section 8.6
   835   // (implemented in bug 328168), the startSide border is always on the
   836   // first line.
   837   // This frame is a first-in-flow, but it might have a previous bidi
   838   // continuation, in which case that continuation should handle the startSide
   839   // border.
   840   if (!GetPrevContinuation()) {
   841     aData->currentLine +=
   842       // clamp negative calc() to 0
   843       std::max(GetCoord(stylePadding->mPadding.Get(startSide), 0), 0) +
   844       styleBorder->GetComputedBorderWidth(startSide) +
   845       GetCoord(styleMargin->mMargin.Get(startSide), 0);
   846   }
   848   const nsLineList_iterator* savedLine = aData->line;
   849   nsIFrame* const savedLineContainer = aData->lineContainer;
   851   nsContainerFrame *lastInFlow;
   852   for (nsContainerFrame *nif = this; nif;
   853        nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) {
   854     for (nsIFrame *kid = nif->mFrames.FirstChild(); kid;
   855          kid = kid->GetNextSibling()) {
   856       if (aType == nsLayoutUtils::MIN_WIDTH)
   857         kid->AddInlineMinWidth(aRenderingContext,
   858                                static_cast<InlineMinWidthData*>(aData));
   859       else
   860         kid->AddInlinePrefWidth(aRenderingContext,
   861                                 static_cast<InlinePrefWidthData*>(aData));
   862     }
   864     // After we advance to our next-in-flow, the stored line and line container
   865     // may no longer be correct. Just forget them.
   866     aData->line = nullptr;
   867     aData->lineContainer = nullptr;
   869     lastInFlow = nif;
   870   }
   872   aData->line = savedLine;
   873   aData->lineContainer = savedLineContainer;
   875   // This goes at the end no matter how things are broken and how
   876   // messy the bidi situations are, since per CSS2.1 section 8.6
   877   // (implemented in bug 328168), the endSide border is always on the
   878   // last line.
   879   // We reached the last-in-flow, but it might have a next bidi
   880   // continuation, in which case that continuation should handle
   881   // the endSide border.
   882   if (!lastInFlow->GetNextContinuation()) {
   883     aData->currentLine +=
   884       // clamp negative calc() to 0
   885       std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
   886       styleBorder->GetComputedBorderWidth(endSide) +
   887       GetCoord(styleMargin->mMargin.Get(endSide), 0);
   888   }
   889 }
   891 /* virtual */ nsSize
   892 nsContainerFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
   893                                   nsSize aCBSize, nscoord aAvailableWidth,
   894                                   nsSize aMargin, nsSize aBorder,
   895                                   nsSize aPadding, bool aShrinkWrap)
   896 {
   897   nsSize result(0xdeadbeef, NS_UNCONSTRAINEDSIZE);
   898   nscoord availBased = aAvailableWidth - aMargin.width - aBorder.width -
   899                        aPadding.width;
   900   // replaced elements always shrink-wrap
   901   if (aShrinkWrap || IsFrameOfType(eReplaced)) {
   902     // don't bother setting it if the result won't be used
   903     if (StylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) {
   904       result.width = ShrinkWidthToFit(aRenderingContext, availBased);
   905     }
   906   } else {
   907     result.width = availBased;
   908   }
   909   return result;
   910 }
   912 /**
   913  * Invokes the WillReflow() function, positions the frame and its view (if
   914  * requested), and then calls Reflow(). If the reflow succeeds and the child
   915  * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
   916  */
   917 nsresult
   918 nsContainerFrame::ReflowChild(nsIFrame*                aKidFrame,
   919                               nsPresContext*           aPresContext,
   920                               nsHTMLReflowMetrics&     aDesiredSize,
   921                               const nsHTMLReflowState& aReflowState,
   922                               nscoord                  aX,
   923                               nscoord                  aY,
   924                               uint32_t                 aFlags,
   925                               nsReflowStatus&          aStatus,
   926                               nsOverflowContinuationTracker* aTracker)
   927 {
   928   NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state");
   930   nsresult  result;
   932   // Send the WillReflow() notification, and position the child frame
   933   // and its view if requested
   934   aKidFrame->WillReflow(aPresContext);
   936   if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
   937     aKidFrame->SetPosition(nsPoint(aX, aY));
   938   }
   940   if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
   941     PositionFrameView(aKidFrame);
   942   }
   944   // Reflow the child frame
   945   result = aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState,
   946                              aStatus);
   948   // If the reflow was successful and the child frame is complete, delete any
   949   // next-in-flows, but only if the NO_DELETE_NEXT_IN_FLOW flag isn't set.
   950   if (NS_SUCCEEDED(result) && NS_FRAME_IS_FULLY_COMPLETE(aStatus) &&
   951       !(aFlags & NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD)) {
   952     nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
   953     if (kidNextInFlow) {
   954       // Remove all of the childs next-in-flows. Make sure that we ask
   955       // the right parent to do the removal (it's possible that the
   956       // parent is not this because we are executing pullup code)
   957       nsOverflowContinuationTracker::AutoFinish fini(aTracker, aKidFrame);
   958       static_cast<nsContainerFrame*>(kidNextInFlow->GetParent())
   959         ->DeleteNextInFlowChild(kidNextInFlow, true);
   960     }
   961   }
   962   return result;
   963 }
   966 /**
   967  * Position the views of |aFrame|'s descendants. A container frame
   968  * should call this method if it moves a frame after |Reflow|.
   969  */
   970 void
   971 nsContainerFrame::PositionChildViews(nsIFrame* aFrame)
   972 {
   973   if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
   974     return;
   975   }
   977   // Recursively walk aFrame's child frames.
   978   // Process the additional child lists, but skip the popup list as the
   979   // view for popups is managed by the parent. Currently only nsMenuFrame
   980   // and nsPopupSetFrame have a popupList and during layout will adjust the
   981   // view manually to position the popup.
   982   ChildListIterator lists(aFrame);
   983   for (; !lists.IsDone(); lists.Next()) {
   984     if (lists.CurrentID() == kPopupList) {
   985       continue;
   986     }
   987     nsFrameList::Enumerator childFrames(lists.CurrentList());
   988     for (; !childFrames.AtEnd(); childFrames.Next()) {
   989       // Position the frame's view (if it has one) otherwise recursively
   990       // process its children
   991       nsIFrame* childFrame = childFrames.get();
   992       if (childFrame->HasView()) {
   993         PositionFrameView(childFrame);
   994       } else {
   995         PositionChildViews(childFrame);
   996       }
   997     }
   998   }
   999 }
  1001 /**
  1002  * The second half of frame reflow. Does the following:
  1003  * - sets the frame's bounds
  1004  * - sizes and positions (if requested) the frame's view. If the frame's final
  1005  *   position differs from the current position and the frame itself does not
  1006  *   have a view, then any child frames with views are positioned so they stay
  1007  *   in sync
  1008  * - sets the view's visibility, opacity, content transparency, and clip
  1009  * - invoked the DidReflow() function
  1011  * Flags:
  1012  * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
  1013  *    case. Also implies NS_FRAME_NO_MOVE_VIEW
  1014  * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
  1015  *    don't want to automatically sync the frame and view
  1016  * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
  1017  */
  1018 nsresult
  1019 nsContainerFrame::FinishReflowChild(nsIFrame*                  aKidFrame,
  1020                                     nsPresContext*             aPresContext,
  1021                                     const nsHTMLReflowMetrics& aDesiredSize,
  1022                                     const nsHTMLReflowState*   aReflowState,
  1023                                     nscoord                    aX,
  1024                                     nscoord                    aY,
  1025                                     uint32_t                   aFlags)
  1027   nsPoint curOrigin = aKidFrame->GetPosition();
  1029   if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
  1030     aKidFrame->SetRect(nsRect(aX, aY, aDesiredSize.Width(), aDesiredSize.Height()));
  1031   } else {
  1032     aKidFrame->SetSize(nsSize(aDesiredSize.Width(), aDesiredSize.Height()));
  1035   if (aKidFrame->HasView()) {
  1036     nsView* view = aKidFrame->GetView();
  1037     // Make sure the frame's view is properly sized and positioned and has
  1038     // things like opacity correct
  1039     SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
  1040                              aDesiredSize.VisualOverflow(), aFlags);
  1043   if (!(aFlags & NS_FRAME_NO_MOVE_VIEW) &&
  1044       (curOrigin.x != aX || curOrigin.y != aY)) {
  1045     if (!aKidFrame->HasView()) {
  1046       // If the frame has moved, then we need to make sure any child views are
  1047       // correctly positioned
  1048       PositionChildViews(aKidFrame);
  1052   return aKidFrame->DidReflow(aPresContext, aReflowState, nsDidReflowStatus::FINISHED);
  1055 nsresult
  1056 nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext*           aPresContext,
  1057                                                   const nsHTMLReflowState& aReflowState,
  1058                                                   nsOverflowAreas&         aOverflowRects,
  1059                                                   uint32_t                 aFlags,
  1060                                                   nsReflowStatus&          aStatus)
  1062   NS_PRECONDITION(aPresContext, "null pointer");
  1063   nsresult rv = NS_OK;
  1065   nsFrameList* overflowContainers =
  1066                GetPropTableFrames(OverflowContainersProperty());
  1068   NS_ASSERTION(!(overflowContainers && GetPrevInFlow()
  1069                  && static_cast<nsContainerFrame*>(GetPrevInFlow())
  1070                       ->GetPropTableFrames(ExcessOverflowContainersProperty())),
  1071                "conflicting overflow containers lists");
  1073   if (!overflowContainers) {
  1074     // Drain excess from previnflow
  1075     nsContainerFrame* prev = (nsContainerFrame*) GetPrevInFlow();
  1076     if (prev) {
  1077       nsFrameList* excessFrames =
  1078         prev->RemovePropTableFrames(ExcessOverflowContainersProperty());
  1079       if (excessFrames) {
  1080         excessFrames->ApplySetParent(this);
  1081         nsContainerFrame::ReparentFrameViewList(*excessFrames, prev, this);
  1082         overflowContainers = excessFrames;
  1083         SetPropTableFrames(overflowContainers, OverflowContainersProperty());
  1088   // Our own excess overflow containers from a previous reflow can still be
  1089   // present if our next-in-flow hasn't been reflown yet.
  1090   nsFrameList* selfExcessOCFrames =
  1091     RemovePropTableFrames(ExcessOverflowContainersProperty());
  1092   if (selfExcessOCFrames) {
  1093     if (overflowContainers) {
  1094       overflowContainers->AppendFrames(nullptr, *selfExcessOCFrames);
  1095       selfExcessOCFrames->Delete(aPresContext->PresShell());
  1096     } else {
  1097       overflowContainers = selfExcessOCFrames;
  1098       SetPropTableFrames(overflowContainers, OverflowContainersProperty());
  1101   if (!overflowContainers) {
  1102     return NS_OK; // nothing to reflow
  1105   nsOverflowContinuationTracker tracker(this, false, false);
  1106   bool shouldReflowAllKids = aReflowState.ShouldReflowAllKids();
  1108   for (nsIFrame* frame = overflowContainers->FirstChild(); frame;
  1109        frame = frame->GetNextSibling()) {
  1110     if (frame->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
  1111       // frame's prevInFlow has moved, skip reflowing this frame;
  1112       // it will get reflowed once it's been placed
  1113       continue;
  1115     // If the available vertical height has changed, we need to reflow
  1116     // even if the frame isn't dirty.
  1117     if (shouldReflowAllKids || NS_SUBTREE_DIRTY(frame)) {
  1118       // Get prev-in-flow
  1119       nsIFrame* prevInFlow = frame->GetPrevInFlow();
  1120       NS_ASSERTION(prevInFlow,
  1121                    "overflow container frame must have a prev-in-flow");
  1122       NS_ASSERTION(frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
  1123                    "overflow container frame must have overflow container bit set");
  1124       nsRect prevRect = prevInFlow->GetRect();
  1126       // Initialize reflow params
  1127       nsSize availSpace(prevRect.width, aReflowState.AvailableHeight());
  1128       nsHTMLReflowMetrics desiredSize(aReflowState);
  1129       nsHTMLReflowState frameState(aPresContext, aReflowState,
  1130                                    frame, availSpace);
  1131       nsReflowStatus frameStatus;
  1133       // Reflow
  1134       rv = ReflowChild(frame, aPresContext, desiredSize, frameState,
  1135                        prevRect.x, 0, aFlags, frameStatus, &tracker);
  1136       NS_ENSURE_SUCCESS(rv, rv);
  1137       //XXXfr Do we need to override any shrinkwrap effects here?
  1138       // e.g. desiredSize.Width() = prevRect.width;
  1139       rv = FinishReflowChild(frame, aPresContext, desiredSize, &frameState,
  1140                              prevRect.x, 0, aFlags);
  1141       NS_ENSURE_SUCCESS(rv, rv);
  1143       // Handle continuations
  1144       if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus)) {
  1145         if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
  1146           // Abspos frames can't cause their parent to be incomplete,
  1147           // only overflow incomplete.
  1148           NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus);
  1150         else {
  1151           NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus),
  1152                        "overflow container frames can't be incomplete, only overflow-incomplete");
  1155         // Acquire a next-in-flow, creating it if necessary
  1156         nsIFrame* nif = frame->GetNextInFlow();
  1157         if (!nif) {
  1158           NS_ASSERTION(frameStatus & NS_FRAME_REFLOW_NEXTINFLOW,
  1159                        "Someone forgot a REFLOW_NEXTINFLOW flag");
  1160           nif = aPresContext->PresShell()->FrameConstructor()->
  1161             CreateContinuingFrame(aPresContext, frame, this);
  1163         else if (!(nif->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
  1164           // used to be a normal next-in-flow; steal it from the child list
  1165           rv = static_cast<nsContainerFrame*>(nif->GetParent())
  1166                  ->StealFrame(nif);
  1167           NS_ENSURE_SUCCESS(rv, rv);
  1170         tracker.Insert(nif, frameStatus);
  1172       NS_MergeReflowStatusInto(&aStatus, frameStatus);
  1173       // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
  1174       // but we have some unsplittable frames that, when taller than
  1175       // availableHeight will push zero-height content into a next-in-flow.
  1177     else {
  1178       tracker.Skip(frame, aStatus);
  1179       if (aReflowState.mFloatManager)
  1180         nsBlockFrame::RecoverFloatsFor(frame, *aReflowState.mFloatManager);
  1182     ConsiderChildOverflow(aOverflowRects, frame);
  1185   return NS_OK;
  1188 void
  1189 nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder*   aBuilder,
  1190                                             const nsRect&           aDirtyRect,
  1191                                             const nsDisplayListSet& aLists)
  1193   nsFrameList* overflowconts = GetPropTableFrames(OverflowContainersProperty());
  1194   if (overflowconts) {
  1195     for (nsIFrame* frame = overflowconts->FirstChild(); frame;
  1196          frame = frame->GetNextSibling()) {
  1197       BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists);
  1202 static bool
  1203 TryRemoveFrame(nsIFrame* aFrame, FramePropertyTable* aPropTable,
  1204                const FramePropertyDescriptor* aProp, nsIFrame* aChildToRemove)
  1206   nsFrameList* list = static_cast<nsFrameList*>(aPropTable->Get(aFrame, aProp));
  1207   if (list && list->StartRemoveFrame(aChildToRemove)) {
  1208     // aChildToRemove *may* have been removed from this list.
  1209     if (list->IsEmpty()) {
  1210       aPropTable->Remove(aFrame, aProp);
  1211       list->Delete(aFrame->PresContext()->PresShell());
  1213     return true;
  1215   return false;
  1218 nsresult
  1219 nsContainerFrame::StealFrame(nsIFrame* aChild,
  1220                              bool      aForceNormal)
  1222 #ifdef DEBUG
  1223   if (!mFrames.ContainsFrame(aChild)) {
  1224     nsFrameList* list = GetOverflowFrames();
  1225     if (!list || !list->ContainsFrame(aChild)) {
  1226       FramePropertyTable* propTable = PresContext()->PropertyTable();
  1227       list = static_cast<nsFrameList*>(
  1228                propTable->Get(this, OverflowContainersProperty()));
  1229       if (!list || !list->ContainsFrame(aChild)) {
  1230         list = static_cast<nsFrameList*>(
  1231                  propTable->Get(this, ExcessOverflowContainersProperty()));
  1232         MOZ_ASSERT(list && list->ContainsFrame(aChild), "aChild isn't our child"
  1233                    " or on a frame list not supported by StealFrame");
  1237 #endif
  1239   bool removed;
  1240   if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
  1241       && !aForceNormal) {
  1242     FramePropertyTable* propTable = PresContext()->PropertyTable();
  1243     // Try removing from the overflow container list.
  1244     removed = ::TryRemoveFrame(this, propTable, OverflowContainersProperty(),
  1245                                aChild);
  1246     if (!removed) {
  1247       // It must be in the excess overflow container list.
  1248       removed = ::TryRemoveFrame(this, propTable,
  1249                                  ExcessOverflowContainersProperty(),
  1250                                  aChild);
  1252   } else {
  1253     removed = mFrames.StartRemoveFrame(aChild);
  1254     if (!removed) {
  1255       // We didn't find the child in our principal child list.
  1256       // Maybe it's on the overflow list?
  1257       nsFrameList* frameList = GetOverflowFrames();
  1258       if (frameList) {
  1259         removed = frameList->ContinueRemoveFrame(aChild);
  1260         if (frameList->IsEmpty()) {
  1261           DestroyOverflowList();
  1267   NS_POSTCONDITION(removed, "StealFrame: can't find aChild");
  1268   return removed ? NS_OK : NS_ERROR_UNEXPECTED;
  1271 nsFrameList
  1272 nsContainerFrame::StealFramesAfter(nsIFrame* aChild)
  1274   NS_ASSERTION(!aChild ||
  1275                !(aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER),
  1276                "StealFramesAfter doesn't handle overflow containers");
  1277   NS_ASSERTION(GetType() != nsGkAtoms::blockFrame, "unexpected call");
  1279   if (!aChild) {
  1280     nsFrameList copy(mFrames);
  1281     mFrames.Clear();
  1282     return copy;
  1285   for (nsFrameList::FrameLinkEnumerator iter(mFrames); !iter.AtEnd();
  1286        iter.Next()) {
  1287     if (iter.PrevFrame() == aChild) {
  1288       return mFrames.ExtractTail(iter);
  1292   // We didn't find the child in the principal child list.
  1293   // Maybe it's on the overflow list?
  1294   nsFrameList* overflowFrames = GetOverflowFrames();
  1295   if (overflowFrames) {
  1296     for (nsFrameList::FrameLinkEnumerator iter(*overflowFrames); !iter.AtEnd();
  1297          iter.Next()) {
  1298       if (iter.PrevFrame() == aChild) {
  1299         return overflowFrames->ExtractTail(iter);
  1304   NS_ERROR("StealFramesAfter: can't find aChild");
  1305   return nsFrameList::EmptyList();
  1308 /*
  1309  * Create a next-in-flow for aFrame. Will return the newly created
  1310  * frame in aNextInFlowResult <b>if and only if</b> a new frame is
  1311  * created; otherwise nullptr is returned in aNextInFlowResult.
  1312  */
  1313 nsresult
  1314 nsContainerFrame::CreateNextInFlow(nsIFrame*  aFrame,
  1315                                    nsIFrame*& aNextInFlowResult)
  1317   NS_PRECONDITION(GetType() != nsGkAtoms::blockFrame,
  1318                   "you should have called nsBlockFrame::CreateContinuationFor instead");
  1319   NS_PRECONDITION(mFrames.ContainsFrame(aFrame), "expected an in-flow child frame");
  1321   nsPresContext* pc = PresContext();
  1322   aNextInFlowResult = nullptr;
  1324   nsIFrame* nextInFlow = aFrame->GetNextInFlow();
  1325   if (nullptr == nextInFlow) {
  1326     // Create a continuation frame for the child frame and insert it
  1327     // into our child list.
  1328     nextInFlow = pc->PresShell()->FrameConstructor()->
  1329       CreateContinuingFrame(pc, aFrame, this);
  1330     mFrames.InsertFrame(nullptr, aFrame, nextInFlow);
  1332     NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES,
  1333        ("nsContainerFrame::CreateNextInFlow: frame=%p nextInFlow=%p",
  1334         aFrame, nextInFlow));
  1336     aNextInFlowResult = nextInFlow;
  1338   return NS_OK;
  1341 /**
  1342  * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
  1343  * pointers
  1344  */
  1345 void
  1346 nsContainerFrame::DeleteNextInFlowChild(nsIFrame* aNextInFlow,
  1347                                         bool      aDeletingEmptyFrames)
  1349 #ifdef DEBUG
  1350   nsIFrame* prevInFlow = aNextInFlow->GetPrevInFlow();
  1351 #endif
  1352   NS_PRECONDITION(prevInFlow, "bad prev-in-flow");
  1354   // If the next-in-flow has a next-in-flow then delete it, too (and
  1355   // delete it first).
  1356   // Do this in a loop so we don't overflow the stack for frames
  1357   // with very many next-in-flows
  1358   nsIFrame* nextNextInFlow = aNextInFlow->GetNextInFlow();
  1359   if (nextNextInFlow) {
  1360     nsAutoTArray<nsIFrame*, 8> frames;
  1361     for (nsIFrame* f = nextNextInFlow; f; f = f->GetNextInFlow()) {
  1362       frames.AppendElement(f);
  1364     for (int32_t i = frames.Length() - 1; i >= 0; --i) {
  1365       nsIFrame* delFrame = frames.ElementAt(i);
  1366       static_cast<nsContainerFrame*>(delFrame->GetParent())
  1367         ->DeleteNextInFlowChild(delFrame, aDeletingEmptyFrames);
  1371   // Take the next-in-flow out of the parent's child list
  1372   DebugOnly<nsresult> rv = StealFrame(aNextInFlow);
  1373   NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
  1375 #ifdef DEBUG
  1376   if (aDeletingEmptyFrames) {
  1377     nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow);
  1379 #endif
  1381   // Delete the next-in-flow frame and its descendants. This will also
  1382   // remove it from its next-in-flow/prev-in-flow chain.
  1383   aNextInFlow->Destroy();
  1385   NS_POSTCONDITION(!prevInFlow->GetNextInFlow(), "non null next-in-flow");
  1388 /**
  1389  * Set the frames on the overflow list
  1390  */
  1391 void
  1392 nsContainerFrame::SetOverflowFrames(const nsFrameList& aOverflowFrames)
  1394   NS_PRECONDITION(aOverflowFrames.NotEmpty(), "Shouldn't be called");
  1396   nsPresContext* pc = PresContext();
  1397   nsFrameList* newList = new (pc->PresShell()) nsFrameList(aOverflowFrames);
  1399   pc->PropertyTable()->Set(this, OverflowProperty(), newList);
  1402 nsFrameList*
  1403 nsContainerFrame::GetPropTableFrames(const FramePropertyDescriptor* aProperty) const
  1405   FramePropertyTable* propTable = PresContext()->PropertyTable();
  1406   return static_cast<nsFrameList*>(propTable->Get(this, aProperty));
  1409 nsFrameList*
  1410 nsContainerFrame::RemovePropTableFrames(const FramePropertyDescriptor* aProperty)
  1412   FramePropertyTable* propTable = PresContext()->PropertyTable();
  1413   return static_cast<nsFrameList*>(propTable->Remove(this, aProperty));
  1416 void
  1417 nsContainerFrame::SetPropTableFrames(nsFrameList*                   aFrameList,
  1418                                      const FramePropertyDescriptor* aProperty)
  1420   NS_PRECONDITION(aProperty && aFrameList, "null ptr");
  1421   NS_PRECONDITION(
  1422     (aProperty != nsContainerFrame::OverflowContainersProperty() &&
  1423      aProperty != nsContainerFrame::ExcessOverflowContainersProperty()) ||
  1424     IsFrameOfType(nsIFrame::eCanContainOverflowContainers),
  1425     "this type of frame can't have overflow containers");
  1426   MOZ_ASSERT(!GetPropTableFrames(aProperty));
  1427   PresContext()->PropertyTable()->Set(this, aProperty, aFrameList);
  1430 /**
  1431  * Push aFromChild and its next siblings to the next-in-flow. Change the
  1432  * geometric parent of each frame that's pushed. If there is no next-in-flow
  1433  * the frames are placed on the overflow list (and the geometric parent is
  1434  * left unchanged).
  1436  * Updates the next-in-flow's child count. Does <b>not</b> update the
  1437  * pusher's child count.
  1439  * @param   aFromChild the first child frame to push. It is disconnected from
  1440  *            aPrevSibling
  1441  * @param   aPrevSibling aFromChild's previous sibling. Must not be null. It's
  1442  *            an error to push a parent's first child frame
  1443  */
  1444 void
  1445 nsContainerFrame::PushChildren(nsIFrame* aFromChild,
  1446                                nsIFrame* aPrevSibling)
  1448   NS_PRECONDITION(aFromChild, "null pointer");
  1449   NS_PRECONDITION(aPrevSibling, "pushing first child");
  1450   NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
  1452   // Disconnect aFromChild from its previous sibling
  1453   nsFrameList tail = mFrames.RemoveFramesAfter(aPrevSibling);
  1455   nsContainerFrame* nextInFlow =
  1456     static_cast<nsContainerFrame*>(GetNextInFlow());
  1457   if (nextInFlow) {
  1458     // XXX This is not a very good thing to do. If it gets removed
  1459     // then remove the copy of this routine that doesn't do this from
  1460     // nsInlineFrame.
  1461     // When pushing and pulling frames we need to check for whether any
  1462     // views need to be reparented.
  1463     for (nsIFrame* f = aFromChild; f; f = f->GetNextSibling()) {
  1464       nsContainerFrame::ReparentFrameView(f, this, nextInFlow);
  1466     nextInFlow->mFrames.InsertFrames(nextInFlow, nullptr, tail);
  1468   else {
  1469     // Add the frames to our overflow list
  1470     SetOverflowFrames(tail);
  1474 /**
  1475  * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
  1476  * the receiver's overflow list) to the child list.
  1478  * Updates this frame's child count and content mapping.
  1480  * @return  true if any frames were moved and false otherwise
  1481  */
  1482 bool
  1483 nsContainerFrame::MoveOverflowToChildList()
  1485   bool result = false;
  1487   // Check for an overflow list with our prev-in-flow
  1488   nsContainerFrame* prevInFlow = (nsContainerFrame*)GetPrevInFlow();
  1489   if (nullptr != prevInFlow) {
  1490     AutoFrameListPtr prevOverflowFrames(PresContext(),
  1491                                         prevInFlow->StealOverflowFrames());
  1492     if (prevOverflowFrames) {
  1493       // Tables are special; they can have repeated header/footer
  1494       // frames on mFrames at this point.
  1495       NS_ASSERTION(mFrames.IsEmpty() || GetType() == nsGkAtoms::tableFrame,
  1496                    "bad overflow list");
  1497       // When pushing and pulling frames we need to check for whether any
  1498       // views need to be reparented.
  1499       nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames,
  1500                                               prevInFlow, this);
  1501       mFrames.AppendFrames(this, *prevOverflowFrames);
  1502       result = true;
  1506   // It's also possible that we have an overflow list for ourselves.
  1507   return DrainSelfOverflowList() || result;
  1510 bool
  1511 nsContainerFrame::DrainSelfOverflowList()
  1513   AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
  1514   if (overflowFrames) {
  1515     NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
  1516     mFrames.AppendFrames(nullptr, *overflowFrames);
  1517     return true;
  1519   return false;
  1522 nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsContainerFrame* aFrame,
  1523                                                              bool              aWalkOOFFrames,
  1524                                                              bool              aSkipOverflowContainerChildren)
  1525   : mOverflowContList(nullptr),
  1526     mPrevOverflowCont(nullptr),
  1527     mSentry(nullptr),
  1528     mParent(aFrame),
  1529     mSkipOverflowContainerChildren(aSkipOverflowContainerChildren),
  1530     mWalkOOFFrames(aWalkOOFFrames)
  1532   NS_PRECONDITION(aFrame, "null frame pointer");
  1533   SetupOverflowContList();
  1536 void
  1537 nsOverflowContinuationTracker::SetupOverflowContList()
  1539   NS_PRECONDITION(mParent, "null frame pointer");
  1540   NS_PRECONDITION(!mOverflowContList, "already have list");
  1541   nsContainerFrame* nif =
  1542     static_cast<nsContainerFrame*>(mParent->GetNextInFlow());
  1543   if (nif) {
  1544     mOverflowContList = nif->GetPropTableFrames(
  1545       nsContainerFrame::OverflowContainersProperty());
  1546     if (mOverflowContList) {
  1547       mParent = nif;
  1548       SetUpListWalker();
  1551   if (!mOverflowContList) {
  1552     mOverflowContList = mParent->GetPropTableFrames(
  1553       nsContainerFrame::ExcessOverflowContainersProperty());
  1554     if (mOverflowContList) {
  1555       SetUpListWalker();
  1560 /**
  1561  * Helper function to walk past overflow continuations whose prev-in-flow
  1562  * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
  1563  */
  1564 void
  1565 nsOverflowContinuationTracker::SetUpListWalker()
  1567   NS_ASSERTION(!mSentry && !mPrevOverflowCont,
  1568                "forgot to reset mSentry or mPrevOverflowCont");
  1569   if (mOverflowContList) {
  1570     nsIFrame* cur = mOverflowContList->FirstChild();
  1571     if (mSkipOverflowContainerChildren) {
  1572       while (cur && (cur->GetPrevInFlow()->GetStateBits()
  1573                      & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
  1574         mPrevOverflowCont = cur;
  1575         cur = cur->GetNextSibling();
  1577       while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
  1578                      == mWalkOOFFrames)) {
  1579         mPrevOverflowCont = cur;
  1580         cur = cur->GetNextSibling();
  1583     if (cur) {
  1584       mSentry = cur->GetPrevInFlow();
  1589 /**
  1590  * Helper function to step forward through the overflow continuations list.
  1591  * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
  1592  * as appropriate. May only be called when we have already set up an
  1593  * mOverflowContList; mOverflowContList cannot be null.
  1594  */
  1595 void
  1596 nsOverflowContinuationTracker::StepForward()
  1598   NS_PRECONDITION(mOverflowContList, "null list");
  1600   // Step forward
  1601   if (mPrevOverflowCont) {
  1602     mPrevOverflowCont = mPrevOverflowCont->GetNextSibling();
  1604   else {
  1605     mPrevOverflowCont = mOverflowContList->FirstChild();
  1608   // Skip over oof or non-oof frames as appropriate
  1609   if (mSkipOverflowContainerChildren) {
  1610     nsIFrame* cur = mPrevOverflowCont->GetNextSibling();
  1611     while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
  1612                    == mWalkOOFFrames)) {
  1613       mPrevOverflowCont = cur;
  1614       cur = cur->GetNextSibling();
  1618   // Set up the sentry
  1619   mSentry = (mPrevOverflowCont->GetNextSibling())
  1620             ? mPrevOverflowCont->GetNextSibling()->GetPrevInFlow()
  1621             : nullptr;
  1624 nsresult
  1625 nsOverflowContinuationTracker::Insert(nsIFrame*       aOverflowCont,
  1626                                       nsReflowStatus& aReflowStatus)
  1628   NS_PRECONDITION(aOverflowCont, "null frame pointer");
  1629   NS_PRECONDITION(!mSkipOverflowContainerChildren || mWalkOOFFrames ==
  1630                   !!(aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
  1631                   "shouldn't insert frame that doesn't match walker type");
  1632   NS_PRECONDITION(aOverflowCont->GetPrevInFlow(),
  1633                   "overflow containers must have a prev-in-flow");
  1634   nsresult rv = NS_OK;
  1635   bool reparented = false;
  1636   nsPresContext* presContext = aOverflowCont->PresContext();
  1637   bool addToList = !mSentry || aOverflowCont != mSentry->GetNextInFlow();
  1639   // If we have a list and aOverflowCont is already in it then don't try to
  1640   // add it again.
  1641   if (addToList && aOverflowCont->GetParent() == mParent &&
  1642       (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) &&
  1643       mOverflowContList && mOverflowContList->ContainsFrame(aOverflowCont)) {
  1644     addToList = false;
  1645     mPrevOverflowCont = aOverflowCont->GetPrevSibling();
  1648   if (addToList) {
  1649     if (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
  1650       // aOverflowCont is in some other overflow container list,
  1651       // steal it first
  1652       NS_ASSERTION(!(mOverflowContList &&
  1653                      mOverflowContList->ContainsFrame(aOverflowCont)),
  1654                    "overflow containers out of order");
  1655       rv = static_cast<nsContainerFrame*>(aOverflowCont->GetParent())
  1656              ->StealFrame(aOverflowCont);
  1657       NS_ENSURE_SUCCESS(rv, rv);
  1659     else {
  1660       aOverflowCont->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
  1662     if (!mOverflowContList) {
  1663       mOverflowContList = new (presContext->PresShell()) nsFrameList();
  1664       mParent->SetPropTableFrames(mOverflowContList,
  1665         nsContainerFrame::ExcessOverflowContainersProperty());
  1666       SetUpListWalker();
  1668     if (aOverflowCont->GetParent() != mParent) {
  1669       nsContainerFrame::ReparentFrameView(aOverflowCont,
  1670                                           aOverflowCont->GetParent(),
  1671                                           mParent);
  1672       reparented = true;
  1675     // If aOverflowCont has a prev/next-in-flow that might be in
  1676     // mOverflowContList we need to find it and insert after/before it to
  1677     // maintain the order amongst next-in-flows in this list.
  1678     nsIFrame* pif = aOverflowCont->GetPrevInFlow();
  1679     nsIFrame* nif = aOverflowCont->GetNextInFlow();
  1680     if ((pif && pif->GetParent() == mParent && pif != mPrevOverflowCont) ||
  1681         (nif && nif->GetParent() == mParent && mPrevOverflowCont)) {
  1682       for (nsFrameList::Enumerator e(*mOverflowContList); !e.AtEnd(); e.Next()) {
  1683         nsIFrame* f = e.get();
  1684         if (f == pif) {
  1685           mPrevOverflowCont = pif;
  1686           break;
  1688         if (f == nif) {
  1689           mPrevOverflowCont = f->GetPrevSibling();
  1690           break;
  1695     mOverflowContList->InsertFrame(mParent, mPrevOverflowCont, aOverflowCont);
  1696     aReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
  1699   // If we need to reflow it, mark it dirty
  1700   if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW)
  1701     aOverflowCont->AddStateBits(NS_FRAME_IS_DIRTY);
  1703   // It's in our list, just step forward
  1704   StepForward();
  1705   NS_ASSERTION(mPrevOverflowCont == aOverflowCont ||
  1706                (mSkipOverflowContainerChildren &&
  1707                 (mPrevOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW) !=
  1708                 (aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW)),
  1709               "OverflowContTracker in unexpected state");
  1711   if (addToList) {
  1712     // Convert all non-overflow-container continuations of aOverflowCont
  1713     // into overflow containers and move them to our overflow
  1714     // tracker. This preserves the invariant that the next-continuations
  1715     // of an overflow container are also overflow containers.
  1716     nsIFrame* f = aOverflowCont->GetNextContinuation();
  1717     if (f && (!(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) ||
  1718               (!reparented && f->GetParent() == mParent) ||
  1719               (reparented && f->GetParent() != mParent))) {
  1720       if (!(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
  1721         nsContainerFrame* parent = static_cast<nsContainerFrame*>(f->GetParent());
  1722         rv = parent->StealFrame(f);
  1723         NS_ENSURE_SUCCESS(rv, rv);
  1725       Insert(f, aReflowStatus);
  1728   return rv;
  1731 void
  1732 nsOverflowContinuationTracker::BeginFinish(nsIFrame* aChild)
  1734   NS_PRECONDITION(aChild, "null ptr");
  1735   NS_PRECONDITION(aChild->GetNextInFlow(),
  1736                   "supposed to call Finish *before* deleting next-in-flow!");
  1737   for (nsIFrame* f = aChild; f; f = f->GetNextInFlow()) {
  1738     // We'll update these in EndFinish after the next-in-flows are gone.
  1739     if (f == mPrevOverflowCont) {
  1740       mSentry = nullptr;
  1741       mPrevOverflowCont = nullptr;
  1742       break;
  1744     if (f == mSentry) {
  1745       mSentry = nullptr;
  1746       break;
  1751 void
  1752 nsOverflowContinuationTracker::EndFinish(nsIFrame* aChild)
  1754   if (!mOverflowContList) {
  1755     return;
  1757   // Forget mOverflowContList if it was deleted.
  1758   nsPresContext* pc = aChild->PresContext();
  1759   FramePropertyTable* propTable = pc->PropertyTable();
  1760   nsFrameList* eoc = static_cast<nsFrameList*>(propTable->Get(mParent,
  1761                        nsContainerFrame::ExcessOverflowContainersProperty()));
  1762   if (eoc != mOverflowContList) {
  1763     nsFrameList* oc = static_cast<nsFrameList*>(propTable->Get(mParent,
  1764                         nsContainerFrame::OverflowContainersProperty()));
  1765     if (oc != mOverflowContList) {
  1766       // mOverflowContList was deleted
  1767       mPrevOverflowCont = nullptr;
  1768       mSentry = nullptr;
  1769       mParent = static_cast<nsContainerFrame*>(aChild->GetParent());
  1770       mOverflowContList = nullptr;
  1771       SetupOverflowContList();
  1772       return;
  1775   // The list survived, update mSentry if needed.
  1776   if (!mSentry) {
  1777     if (!mPrevOverflowCont) {
  1778       SetUpListWalker();
  1779     } else {
  1780       mozilla::AutoRestore<nsIFrame*> saved(mPrevOverflowCont);
  1781       // step backward to make StepForward() use our current mPrevOverflowCont
  1782       mPrevOverflowCont = mPrevOverflowCont->GetPrevSibling();
  1783       StepForward();
  1788 /////////////////////////////////////////////////////////////////////////////
  1789 // Debugging
  1791 #ifdef DEBUG_FRAME_DUMP
  1792 void
  1793 nsContainerFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
  1795   nsCString str;
  1796   ListGeneric(str, aPrefix, aFlags);
  1798   // Output the children
  1799   bool outputOneList = false;
  1800   ChildListIterator lists(this);
  1801   for (; !lists.IsDone(); lists.Next()) {
  1802     if (outputOneList) {
  1803       str += aPrefix;
  1805     if (lists.CurrentID() != kPrincipalList) {
  1806       if (!outputOneList) {
  1807         str += "\n";
  1808         str += aPrefix;
  1810       str += nsPrintfCString("%s %p ", mozilla::layout::ChildListName(lists.CurrentID()),
  1811                              &GetChildList(lists.CurrentID()));
  1813     fprintf_stderr(out, "%s<\n", str.get());
  1814     str = "";
  1815     nsFrameList::Enumerator childFrames(lists.CurrentList());
  1816     for (; !childFrames.AtEnd(); childFrames.Next()) {
  1817       nsIFrame* kid = childFrames.get();
  1818       // Verify the child frame's parent frame pointer is correct
  1819       NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");
  1821       // Have the child frame list
  1822       nsCString pfx(aPrefix);
  1823       pfx += "  ";
  1824       kid->List(out, pfx.get(), aFlags);
  1826     fprintf_stderr(out, "%s>\n", aPrefix);
  1827     outputOneList = true;
  1830   if (!outputOneList) {
  1831     fprintf_stderr(out, "%s<>\n", str.get());
  1834 #endif

mercurial