layout/generic/nsContainerFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/generic/nsContainerFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1834 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/* base class #1 for rendering objects that have child lists */
    1.10 +
    1.11 +#include "nsContainerFrame.h"
    1.12 +
    1.13 +#include "nsAbsoluteContainingBlock.h"
    1.14 +#include "nsIDocument.h"
    1.15 +#include "nsPresContext.h"
    1.16 +#include "nsStyleContext.h"
    1.17 +#include "nsRect.h"
    1.18 +#include "nsPoint.h"
    1.19 +#include "nsStyleConsts.h"
    1.20 +#include "nsView.h"
    1.21 +#include "nsIPresShell.h"
    1.22 +#include "nsCOMPtr.h"
    1.23 +#include "nsGkAtoms.h"
    1.24 +#include "nsViewManager.h"
    1.25 +#include "nsIWidget.h"
    1.26 +#include "nsCSSRendering.h"
    1.27 +#include "nsError.h"
    1.28 +#include "nsDisplayList.h"
    1.29 +#include "nsIBaseWindow.h"
    1.30 +#include "nsBoxLayoutState.h"
    1.31 +#include "nsCSSFrameConstructor.h"
    1.32 +#include "nsBlockFrame.h"
    1.33 +#include "mozilla/AutoRestore.h"
    1.34 +#include "nsIFrameInlines.h"
    1.35 +#include "nsPrintfCString.h"
    1.36 +#include <algorithm>
    1.37 +
    1.38 +#ifdef DEBUG
    1.39 +#undef NOISY
    1.40 +#else
    1.41 +#undef NOISY
    1.42 +#endif
    1.43 +
    1.44 +using namespace mozilla;
    1.45 +using namespace mozilla::dom;
    1.46 +using namespace mozilla::layout;
    1.47 +
    1.48 +NS_IMPL_FRAMEARENA_HELPERS(nsContainerFrame)
    1.49 +
    1.50 +nsContainerFrame::~nsContainerFrame()
    1.51 +{
    1.52 +}
    1.53 +
    1.54 +NS_QUERYFRAME_HEAD(nsContainerFrame)
    1.55 +  NS_QUERYFRAME_ENTRY(nsContainerFrame)
    1.56 +NS_QUERYFRAME_TAIL_INHERITING(nsSplittableFrame)
    1.57 +
    1.58 +void
    1.59 +nsContainerFrame::Init(nsIContent* aContent,
    1.60 +                       nsIFrame*   aParent,
    1.61 +                       nsIFrame*   aPrevInFlow)
    1.62 +{
    1.63 +  nsSplittableFrame::Init(aContent, aParent, aPrevInFlow);
    1.64 +  if (aPrevInFlow) {
    1.65 +    // Make sure we copy bits from our prev-in-flow that will affect
    1.66 +    // us. A continuation for a container frame needs to know if it
    1.67 +    // has a child with a view so that we'll properly reposition it.
    1.68 +    if (aPrevInFlow->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)
    1.69 +      AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
    1.70 +  }
    1.71 +}
    1.72 +
    1.73 +nsresult
    1.74 +nsContainerFrame::SetInitialChildList(ChildListID  aListID,
    1.75 +                                      nsFrameList& aChildList)
    1.76 +{
    1.77 +  nsresult  result;
    1.78 +  if (mFrames.NotEmpty()) {
    1.79 +    // We already have child frames which means we've already been
    1.80 +    // initialized
    1.81 +    NS_NOTREACHED("unexpected second call to SetInitialChildList");
    1.82 +    result = NS_ERROR_UNEXPECTED;
    1.83 +  } else if (aListID != kPrincipalList) {
    1.84 +    // All we know about is the principal child list.
    1.85 +    NS_NOTREACHED("unknown frame list");
    1.86 +    result = NS_ERROR_INVALID_ARG;
    1.87 +  } else {
    1.88 +#ifdef DEBUG
    1.89 +    nsFrame::VerifyDirtyBitSet(aChildList);
    1.90 +#endif
    1.91 +    mFrames.SetFrames(aChildList);
    1.92 +    result = NS_OK;
    1.93 +  }
    1.94 +  return result;
    1.95 +}
    1.96 +
    1.97 +nsresult
    1.98 +nsContainerFrame::AppendFrames(ChildListID  aListID,
    1.99 +                               nsFrameList& aFrameList)
   1.100 +{
   1.101 +  if (aListID != kPrincipalList) {
   1.102 +    if (aListID != kNoReflowPrincipalList)
   1.103 +    {
   1.104 +      NS_ERROR("unexpected child list");
   1.105 +      return NS_ERROR_INVALID_ARG;
   1.106 +    }
   1.107 +  }
   1.108 +  if (aFrameList.NotEmpty()) {
   1.109 +    mFrames.AppendFrames(this, aFrameList);
   1.110 +
   1.111 +    // Ask the parent frame to reflow me.
   1.112 +    if (aListID == kPrincipalList)
   1.113 +    {
   1.114 +      PresContext()->PresShell()->
   1.115 +        FrameNeedsReflow(this, nsIPresShell::eTreeChange,
   1.116 +                         NS_FRAME_HAS_DIRTY_CHILDREN);
   1.117 +    }
   1.118 +  }
   1.119 +  return NS_OK;
   1.120 +}
   1.121 +
   1.122 +nsresult
   1.123 +nsContainerFrame::InsertFrames(ChildListID aListID,
   1.124 +                               nsIFrame* aPrevFrame,
   1.125 +                               nsFrameList& aFrameList)
   1.126 +{
   1.127 +  NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
   1.128 +               "inserting after sibling frame with different parent");
   1.129 +
   1.130 +  if (aListID != kPrincipalList) {
   1.131 +    if (aListID != kNoReflowPrincipalList)
   1.132 +    {
   1.133 +      NS_ERROR("unexpected child list");
   1.134 +      return NS_ERROR_INVALID_ARG;
   1.135 +    }
   1.136 +  }
   1.137 +  if (aFrameList.NotEmpty()) {
   1.138 +    // Insert frames after aPrevFrame
   1.139 +    mFrames.InsertFrames(this, aPrevFrame, aFrameList);
   1.140 +
   1.141 +    if (aListID == kPrincipalList)
   1.142 +    {
   1.143 +      PresContext()->PresShell()->
   1.144 +        FrameNeedsReflow(this, nsIPresShell::eTreeChange,
   1.145 +                         NS_FRAME_HAS_DIRTY_CHILDREN);
   1.146 +    }
   1.147 +  }
   1.148 +  return NS_OK;
   1.149 +}
   1.150 +
   1.151 +nsresult
   1.152 +nsContainerFrame::RemoveFrame(ChildListID aListID,
   1.153 +                              nsIFrame* aOldFrame)
   1.154 +{
   1.155 +  if (aListID != kPrincipalList) {
   1.156 +    if (kNoReflowPrincipalList != aListID)
   1.157 +    {
   1.158 +      NS_ERROR("unexpected child list");
   1.159 +      return NS_ERROR_INVALID_ARG;
   1.160 +    }
   1.161 +  }
   1.162 +
   1.163 +  // Loop and destroy aOldFrame and all of its continuations.
   1.164 +  // Request a reflow on the parent frames involved unless we were explicitly
   1.165 +  // told not to (kNoReflowPrincipalList).
   1.166 +  bool generateReflowCommand = true;
   1.167 +  if (kNoReflowPrincipalList == aListID) {
   1.168 +    generateReflowCommand = false;
   1.169 +  }
   1.170 +  nsIPresShell* shell = PresContext()->PresShell();
   1.171 +  nsContainerFrame* lastParent = nullptr;
   1.172 +  while (aOldFrame) {
   1.173 +    //XXXfr probably should use StealFrame here. I'm not sure if we need to
   1.174 +    //      check the overflow lists atm, but we'll need a prescontext lookup
   1.175 +    //      for overflow containers once we can split abspos elements with
   1.176 +    //      inline containing blocks.
   1.177 +    nsIFrame* oldFrameNextContinuation = aOldFrame->GetNextContinuation();
   1.178 +    nsContainerFrame* parent =
   1.179 +      static_cast<nsContainerFrame*>(aOldFrame->GetParent());
   1.180 +    parent->StealFrame(aOldFrame, true);
   1.181 +    aOldFrame->Destroy();
   1.182 +    aOldFrame = oldFrameNextContinuation;
   1.183 +    if (parent != lastParent && generateReflowCommand) {
   1.184 +      shell->FrameNeedsReflow(parent, nsIPresShell::eTreeChange,
   1.185 +                              NS_FRAME_HAS_DIRTY_CHILDREN);
   1.186 +      lastParent = parent;
   1.187 +    }
   1.188 +  }
   1.189 +  return NS_OK;
   1.190 +}
   1.191 +
   1.192 +void
   1.193 +nsContainerFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot)
   1.194 +{
   1.195 +  if (IsAbsoluteContainer()) {
   1.196 +    GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot);
   1.197 +    MarkAsNotAbsoluteContainingBlock();
   1.198 +  }
   1.199 +}
   1.200 +
   1.201 +void
   1.202 +nsContainerFrame::SafelyDestroyFrameListProp(nsIFrame* aDestructRoot,
   1.203 +                                             nsIPresShell* aPresShell,
   1.204 +                                             FramePropertyTable* aPropTable,
   1.205 +                                             const FramePropertyDescriptor* aProp)
   1.206 +{
   1.207 +  // Note that the last frame can be removed through another route and thus
   1.208 +  // delete the property -- that's why we fetch the property again before
   1.209 +  // removing each frame rather than fetching it once and iterating the list.
   1.210 +  while (nsFrameList* frameList =
   1.211 +           static_cast<nsFrameList*>(aPropTable->Get(this, aProp))) {
   1.212 +    nsIFrame* frame = frameList->RemoveFirstChild();
   1.213 +    if (MOZ_LIKELY(frame)) {
   1.214 +      frame->DestroyFrom(aDestructRoot);
   1.215 +    } else {
   1.216 +      aPropTable->Remove(this, aProp);
   1.217 +      frameList->Delete(aPresShell);
   1.218 +      return;
   1.219 +    }
   1.220 +  }
   1.221 +}
   1.222 +
   1.223 +void
   1.224 +nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot)
   1.225 +{
   1.226 +  // Prevent event dispatch during destruction.
   1.227 +  if (HasView()) {
   1.228 +    GetView()->SetFrame(nullptr);
   1.229 +  }
   1.230 +
   1.231 +  DestroyAbsoluteFrames(aDestructRoot);
   1.232 +
   1.233 +  // Destroy frames on the principal child list.
   1.234 +  mFrames.DestroyFramesFrom(aDestructRoot);
   1.235 +
   1.236 +  // Destroy frames on the auxiliary frame lists and delete the lists.
   1.237 +  nsPresContext* pc = PresContext();
   1.238 +  nsIPresShell* shell = pc->PresShell();
   1.239 +  FramePropertyTable* props = pc->PropertyTable();
   1.240 +  SafelyDestroyFrameListProp(aDestructRoot, shell, props, OverflowProperty());
   1.241 +
   1.242 +  MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers) ||
   1.243 +             !(props->Get(this, nsContainerFrame::OverflowContainersProperty()) ||
   1.244 +               props->Get(this, nsContainerFrame::ExcessOverflowContainersProperty())),
   1.245 +             "this type of frame should't have overflow containers");
   1.246 +
   1.247 +  SafelyDestroyFrameListProp(aDestructRoot, shell, props,
   1.248 +                             OverflowContainersProperty());
   1.249 +  SafelyDestroyFrameListProp(aDestructRoot, shell, props,
   1.250 +                             ExcessOverflowContainersProperty());
   1.251 +
   1.252 +  nsSplittableFrame::DestroyFrom(aDestructRoot);
   1.253 +}
   1.254 +
   1.255 +/////////////////////////////////////////////////////////////////////////////
   1.256 +// Child frame enumeration
   1.257 +
   1.258 +const nsFrameList&
   1.259 +nsContainerFrame::GetChildList(ChildListID aListID) const
   1.260 +{
   1.261 +  // We only know about the principal child list and the overflow lists.
   1.262 +  switch (aListID) {
   1.263 +    case kPrincipalList:
   1.264 +      return mFrames;
   1.265 +    case kOverflowList: {
   1.266 +      nsFrameList* list = GetOverflowFrames();
   1.267 +      return list ? *list : nsFrameList::EmptyList();
   1.268 +    }
   1.269 +    case kOverflowContainersList: {
   1.270 +      nsFrameList* list = GetPropTableFrames(OverflowContainersProperty());
   1.271 +      return list ? *list : nsFrameList::EmptyList();
   1.272 +    }
   1.273 +    case kExcessOverflowContainersList: {
   1.274 +      nsFrameList* list =
   1.275 +        GetPropTableFrames(ExcessOverflowContainersProperty());
   1.276 +      return list ? *list : nsFrameList::EmptyList();
   1.277 +    }
   1.278 +    default:
   1.279 +      return nsSplittableFrame::GetChildList(aListID);
   1.280 +  }
   1.281 +}
   1.282 +
   1.283 +static void AppendIfNonempty(const nsIFrame* aFrame,
   1.284 +                            FramePropertyTable* aPropTable,
   1.285 +                            const FramePropertyDescriptor* aProperty,
   1.286 +                            nsTArray<nsIFrame::ChildList>* aLists,
   1.287 +                            nsIFrame::ChildListID aListID)
   1.288 +{
   1.289 +  nsFrameList* list = static_cast<nsFrameList*>(
   1.290 +    aPropTable->Get(aFrame, aProperty));
   1.291 +  if (list) {
   1.292 +    list->AppendIfNonempty(aLists, aListID);
   1.293 +  }
   1.294 +}
   1.295 +
   1.296 +void
   1.297 +nsContainerFrame::GetChildLists(nsTArray<ChildList>* aLists) const
   1.298 +{
   1.299 +  mFrames.AppendIfNonempty(aLists, kPrincipalList);
   1.300 +  FramePropertyTable* propTable = PresContext()->PropertyTable();
   1.301 +  ::AppendIfNonempty(this, propTable, OverflowProperty(),
   1.302 +                     aLists, kOverflowList);
   1.303 +  if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
   1.304 +    ::AppendIfNonempty(this, propTable, OverflowContainersProperty(),
   1.305 +                       aLists, kOverflowContainersList);
   1.306 +    ::AppendIfNonempty(this, propTable, ExcessOverflowContainersProperty(),
   1.307 +                       aLists, kExcessOverflowContainersList);
   1.308 +  }
   1.309 +  nsSplittableFrame::GetChildLists(aLists);
   1.310 +}
   1.311 +
   1.312 +/////////////////////////////////////////////////////////////////////////////
   1.313 +// Painting/Events
   1.314 +
   1.315 +void
   1.316 +nsContainerFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   1.317 +                                   const nsRect&           aDirtyRect,
   1.318 +                                   const nsDisplayListSet& aLists)
   1.319 +{
   1.320 +  DisplayBorderBackgroundOutline(aBuilder, aLists);
   1.321 +
   1.322 +  BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
   1.323 +}
   1.324 +
   1.325 +void
   1.326 +nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder*   aBuilder,
   1.327 +                                                      const nsRect&           aDirtyRect,
   1.328 +                                                      const nsDisplayListSet& aLists,
   1.329 +                                                      uint32_t                aFlags)
   1.330 +{
   1.331 +  nsIFrame* kid = mFrames.FirstChild();
   1.332 +  // Put each child's background directly onto the content list
   1.333 +  nsDisplayListSet set(aLists, aLists.Content());
   1.334 +  // The children should be in content order
   1.335 +  while (kid) {
   1.336 +    BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, aFlags);
   1.337 +    kid = kid->GetNextSibling();
   1.338 +  }
   1.339 +}
   1.340 +
   1.341 +/* virtual */ void
   1.342 +nsContainerFrame::ChildIsDirty(nsIFrame* aChild)
   1.343 +{
   1.344 +  NS_ASSERTION(NS_SUBTREE_DIRTY(aChild), "child isn't actually dirty");
   1.345 +
   1.346 +  AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   1.347 +}
   1.348 +
   1.349 +bool
   1.350 +nsContainerFrame::IsLeaf() const
   1.351 +{
   1.352 +  return false;
   1.353 +}
   1.354 +
   1.355 +nsIFrame::FrameSearchResult
   1.356 +nsContainerFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
   1.357 +{
   1.358 +  NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
   1.359 +  // Don't allow the caret to stay in an empty (leaf) container frame.
   1.360 +  return CONTINUE_EMPTY;
   1.361 +}
   1.362 +
   1.363 +nsIFrame::FrameSearchResult
   1.364 +nsContainerFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
   1.365 +                                      bool aRespectClusters)
   1.366 +{
   1.367 +  NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
   1.368 +  // Don't allow the caret to stay in an empty (leaf) container frame.
   1.369 +  return CONTINUE_EMPTY;
   1.370 +}
   1.371 +
   1.372 +/////////////////////////////////////////////////////////////////////////////
   1.373 +// Helper member functions
   1.374 +
   1.375 +static nsresult
   1.376 +ReparentFrameViewTo(nsIFrame*       aFrame,
   1.377 +                    nsViewManager* aViewManager,
   1.378 +                    nsView*        aNewParentView,
   1.379 +                    nsView*        aOldParentView)
   1.380 +{
   1.381 +
   1.382 +  // XXX What to do about placeholder views for "position: fixed" elements?
   1.383 +  // They should be reparented too.
   1.384 +
   1.385 +  // Does aFrame have a view?
   1.386 +  if (aFrame->HasView()) {
   1.387 +#ifdef MOZ_XUL
   1.388 +    if (aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
   1.389 +      // This view must be parented by the root view, don't reparent it.
   1.390 +      return NS_OK;
   1.391 +    }
   1.392 +#endif
   1.393 +    nsView* view = aFrame->GetView();
   1.394 +    // Verify that the current parent view is what we think it is
   1.395 +    //nsView*  parentView;
   1.396 +    //NS_ASSERTION(parentView == aOldParentView, "unexpected parent view");
   1.397 +
   1.398 +    aViewManager->RemoveChild(view);
   1.399 +    
   1.400 +    // The view will remember the Z-order and other attributes that have been set on it.
   1.401 +    nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(aNewParentView, aFrame);
   1.402 +    aViewManager->InsertChild(aNewParentView, view, insertBefore, insertBefore != nullptr);
   1.403 +  } else {
   1.404 +    nsIFrame::ChildListIterator lists(aFrame);
   1.405 +    for (; !lists.IsDone(); lists.Next()) {
   1.406 +      // Iterate the child frames, and check each child frame to see if it has
   1.407 +      // a view
   1.408 +      nsFrameList::Enumerator childFrames(lists.CurrentList());
   1.409 +      for (; !childFrames.AtEnd(); childFrames.Next()) {
   1.410 +        ReparentFrameViewTo(childFrames.get(), aViewManager,
   1.411 +                            aNewParentView, aOldParentView);
   1.412 +      }
   1.413 +    }
   1.414 +  }
   1.415 +
   1.416 +  return NS_OK;
   1.417 +}
   1.418 +
   1.419 +void
   1.420 +nsContainerFrame::CreateViewForFrame(nsIFrame* aFrame,
   1.421 +                                     bool aForce)
   1.422 +{
   1.423 +  if (aFrame->HasView()) {
   1.424 +    return;
   1.425 +  }
   1.426 +
   1.427 +  // If we don't yet have a view, see if we need a view
   1.428 +  if (!aForce && !aFrame->NeedsView()) {
   1.429 +    // don't need a view
   1.430 +    return;
   1.431 +  }
   1.432 +
   1.433 +  nsView* parentView = aFrame->GetParent()->GetClosestView();
   1.434 +  NS_ASSERTION(parentView, "no parent with view");
   1.435 +
   1.436 +  nsViewManager* viewManager = parentView->GetViewManager();
   1.437 +  NS_ASSERTION(viewManager, "null view manager");
   1.438 +
   1.439 +  // Create a view
   1.440 +  nsView* view = viewManager->CreateView(aFrame->GetRect(), parentView);
   1.441 +
   1.442 +  SyncFrameViewProperties(aFrame->PresContext(), aFrame, nullptr, view);
   1.443 +
   1.444 +  nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(parentView, aFrame);
   1.445 +  // we insert this view 'above' the insertBefore view, unless insertBefore is null,
   1.446 +  // in which case we want to call with aAbove == false to insert at the beginning
   1.447 +  // in document order
   1.448 +  viewManager->InsertChild(parentView, view, insertBefore, insertBefore != nullptr);
   1.449 +
   1.450 +  // REVIEW: Don't create a widget for fixed-pos elements anymore.
   1.451 +  // ComputeRepaintRegionForCopy will calculate the right area to repaint
   1.452 +  // when we scroll.
   1.453 +  // Reparent views on any child frames (or their descendants) to this
   1.454 +  // view. We can just call ReparentFrameViewTo on this frame because
   1.455 +  // we know this frame has no view, so it will crawl the children. Also,
   1.456 +  // we know that any descendants with views must have 'parentView' as their
   1.457 +  // parent view.
   1.458 +  ReparentFrameViewTo(aFrame, viewManager, view, parentView);
   1.459 +
   1.460 +  // Remember our view
   1.461 +  aFrame->SetView(view);
   1.462 +
   1.463 +  NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
   1.464 +               ("nsContainerFrame::CreateViewForFrame: frame=%p view=%p",
   1.465 +                aFrame));
   1.466 +}
   1.467 +
   1.468 +/**
   1.469 + * Position the view associated with |aKidFrame|, if there is one. A
   1.470 + * container frame should call this method after positioning a frame,
   1.471 + * but before |Reflow|.
   1.472 + */
   1.473 +void
   1.474 +nsContainerFrame::PositionFrameView(nsIFrame* aKidFrame)
   1.475 +{
   1.476 +  nsIFrame* parentFrame = aKidFrame->GetParent();
   1.477 +  if (!aKidFrame->HasView() || !parentFrame)
   1.478 +    return;
   1.479 +
   1.480 +  nsView* view = aKidFrame->GetView();
   1.481 +  nsViewManager* vm = view->GetViewManager();
   1.482 +  nsPoint pt;
   1.483 +  nsView* ancestorView = parentFrame->GetClosestView(&pt);
   1.484 +
   1.485 +  if (ancestorView != view->GetParent()) {
   1.486 +    NS_ASSERTION(ancestorView == view->GetParent()->GetParent(),
   1.487 +                 "Allowed only one anonymous view between frames");
   1.488 +    // parentFrame is responsible for positioning aKidFrame's view
   1.489 +    // explicitly
   1.490 +    return;
   1.491 +  }
   1.492 +
   1.493 +  pt += aKidFrame->GetPosition();
   1.494 +  vm->MoveViewTo(view, pt.x, pt.y);
   1.495 +}
   1.496 +
   1.497 +nsresult
   1.498 +nsContainerFrame::ReparentFrameView(nsIFrame* aChildFrame,
   1.499 +                                    nsIFrame* aOldParentFrame,
   1.500 +                                    nsIFrame* aNewParentFrame)
   1.501 +{
   1.502 +  NS_PRECONDITION(aChildFrame, "null child frame pointer");
   1.503 +  NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
   1.504 +  NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
   1.505 +  NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
   1.506 +
   1.507 +  // See if either the old parent frame or the new parent frame have a view
   1.508 +  while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
   1.509 +    // Walk up both the old parent frame and the new parent frame nodes
   1.510 +    // stopping when we either find a common parent or views for one
   1.511 +    // or both of the frames.
   1.512 +    //
   1.513 +    // This works well in the common case where we push/pull and the old parent
   1.514 +    // frame and the new parent frame are part of the same flow. They will
   1.515 +    // typically be the same distance (height wise) from the
   1.516 +    aOldParentFrame = aOldParentFrame->GetParent();
   1.517 +    aNewParentFrame = aNewParentFrame->GetParent();
   1.518 +    
   1.519 +    // We should never walk all the way to the root frame without finding
   1.520 +    // a view
   1.521 +    NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
   1.522 +
   1.523 +    // See if we reached a common ancestor
   1.524 +    if (aOldParentFrame == aNewParentFrame) {
   1.525 +      break;
   1.526 +    }
   1.527 +  }
   1.528 +
   1.529 +  // See if we found a common parent frame
   1.530 +  if (aOldParentFrame == aNewParentFrame) {
   1.531 +    // We found a common parent and there are no views between the old parent
   1.532 +    // and the common parent or the new parent frame and the common parent.
   1.533 +    // Because neither the old parent frame nor the new parent frame have views,
   1.534 +    // then any child views don't need reparenting
   1.535 +    return NS_OK;
   1.536 +  }
   1.537 +
   1.538 +  // We found views for one or both of the ancestor frames before we
   1.539 +  // found a common ancestor.
   1.540 +  nsView* oldParentView = aOldParentFrame->GetClosestView();
   1.541 +  nsView* newParentView = aNewParentFrame->GetClosestView();
   1.542 +  
   1.543 +  // See if the old parent frame and the new parent frame are in the
   1.544 +  // same view sub-hierarchy. If they are then we don't have to do
   1.545 +  // anything
   1.546 +  if (oldParentView != newParentView) {
   1.547 +    // They're not so we need to reparent any child views
   1.548 +    return ReparentFrameViewTo(aChildFrame, oldParentView->GetViewManager(), newParentView,
   1.549 +                               oldParentView);
   1.550 +  }
   1.551 +
   1.552 +  return NS_OK;
   1.553 +}
   1.554 +
   1.555 +nsresult
   1.556 +nsContainerFrame::ReparentFrameViewList(const nsFrameList& aChildFrameList,
   1.557 +                                        nsIFrame*          aOldParentFrame,
   1.558 +                                        nsIFrame*          aNewParentFrame)
   1.559 +{
   1.560 +  NS_PRECONDITION(aChildFrameList.NotEmpty(), "empty child frame list");
   1.561 +  NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
   1.562 +  NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
   1.563 +  NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
   1.564 +
   1.565 +  // See if either the old parent frame or the new parent frame have a view
   1.566 +  while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
   1.567 +    // Walk up both the old parent frame and the new parent frame nodes
   1.568 +    // stopping when we either find a common parent or views for one
   1.569 +    // or both of the frames.
   1.570 +    //
   1.571 +    // This works well in the common case where we push/pull and the old parent
   1.572 +    // frame and the new parent frame are part of the same flow. They will
   1.573 +    // typically be the same distance (height wise) from the
   1.574 +    aOldParentFrame = aOldParentFrame->GetParent();
   1.575 +    aNewParentFrame = aNewParentFrame->GetParent();
   1.576 +    
   1.577 +    // We should never walk all the way to the root frame without finding
   1.578 +    // a view
   1.579 +    NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
   1.580 +
   1.581 +    // See if we reached a common ancestor
   1.582 +    if (aOldParentFrame == aNewParentFrame) {
   1.583 +      break;
   1.584 +    }
   1.585 +  }
   1.586 +
   1.587 +
   1.588 +  // See if we found a common parent frame
   1.589 +  if (aOldParentFrame == aNewParentFrame) {
   1.590 +    // We found a common parent and there are no views between the old parent
   1.591 +    // and the common parent or the new parent frame and the common parent.
   1.592 +    // Because neither the old parent frame nor the new parent frame have views,
   1.593 +    // then any child views don't need reparenting
   1.594 +    return NS_OK;
   1.595 +  }
   1.596 +
   1.597 +  // We found views for one or both of the ancestor frames before we
   1.598 +  // found a common ancestor.
   1.599 +  nsView* oldParentView = aOldParentFrame->GetClosestView();
   1.600 +  nsView* newParentView = aNewParentFrame->GetClosestView();
   1.601 +  
   1.602 +  // See if the old parent frame and the new parent frame are in the
   1.603 +  // same view sub-hierarchy. If they are then we don't have to do
   1.604 +  // anything
   1.605 +  if (oldParentView != newParentView) {
   1.606 +    nsViewManager* viewManager = oldParentView->GetViewManager();
   1.607 +
   1.608 +    // They're not so we need to reparent any child views
   1.609 +    for (nsFrameList::Enumerator e(aChildFrameList); !e.AtEnd(); e.Next()) {
   1.610 +      ReparentFrameViewTo(e.get(), viewManager, newParentView, oldParentView);
   1.611 +    }
   1.612 +  }
   1.613 +
   1.614 +  return NS_OK;
   1.615 +}
   1.616 +
   1.617 +static nsIWidget*
   1.618 +GetPresContextContainerWidget(nsPresContext* aPresContext)
   1.619 +{
   1.620 +  nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
   1.621 +  nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
   1.622 +  if (!baseWindow)
   1.623 +    return nullptr;
   1.624 +
   1.625 +  nsCOMPtr<nsIWidget> mainWidget;
   1.626 +  baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
   1.627 +  return mainWidget;
   1.628 +}
   1.629 +
   1.630 +static bool
   1.631 +IsTopLevelWidget(nsIWidget* aWidget)
   1.632 +{
   1.633 +  nsWindowType windowType = aWidget->WindowType();
   1.634 +  return windowType == eWindowType_toplevel ||
   1.635 +         windowType == eWindowType_dialog ||
   1.636 +         windowType == eWindowType_sheet;
   1.637 +  // popups aren't toplevel so they're not handled here
   1.638 +}
   1.639 +
   1.640 +void
   1.641 +nsContainerFrame::SyncWindowProperties(nsPresContext*       aPresContext,
   1.642 +                                       nsIFrame*            aFrame,
   1.643 +                                       nsView*             aView,
   1.644 +                                       nsRenderingContext*  aRC)
   1.645 +{
   1.646 +#ifdef MOZ_XUL
   1.647 +  if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget())
   1.648 +    return;
   1.649 +
   1.650 +  nsIWidget* windowWidget = GetPresContextContainerWidget(aPresContext);
   1.651 +  if (!windowWidget || !IsTopLevelWidget(windowWidget))
   1.652 +    return;
   1.653 +
   1.654 +  nsViewManager* vm = aView->GetViewManager();
   1.655 +  nsView* rootView = vm->GetRootView();
   1.656 +
   1.657 +  if (aView != rootView)
   1.658 +    return;
   1.659 +
   1.660 +  Element* rootElement = aPresContext->Document()->GetRootElement();
   1.661 +  if (!rootElement || !rootElement->IsXUL()) {
   1.662 +    // Scrollframes use native widgets which don't work well with
   1.663 +    // translucent windows, at least in Windows XP. So if the document
   1.664 +    // has a root scrollrame it's useless to try to make it transparent,
   1.665 +    // we'll just get something broken.
   1.666 +    // nsCSSFrameConstructor::ConstructRootFrame constructs root
   1.667 +    // scrollframes whenever the root element is not a XUL element, so
   1.668 +    // we test for that here. We can't just call
   1.669 +    // presShell->GetRootScrollFrame() since that might not have
   1.670 +    // been constructed yet.
   1.671 +    // We can change this to allow translucent toplevel HTML documents
   1.672 +    // (e.g. to do something like Dashboard widgets), once we
   1.673 +    // have broad support for translucent scrolled documents, but be
   1.674 +    // careful because apparently some Firefox extensions expect
   1.675 +    // openDialog("something.html") to produce an opaque window
   1.676 +    // even if the HTML doesn't have a background-color set.
   1.677 +    return;
   1.678 +  }
   1.679 +
   1.680 +  nsIFrame *rootFrame = aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
   1.681 +  if (!rootFrame)
   1.682 +    return;
   1.683 +
   1.684 +  nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(aFrame, rootFrame);
   1.685 +  nsIWidget* viewWidget = aView->GetWidget();
   1.686 +  viewWidget->SetTransparencyMode(mode);
   1.687 +  windowWidget->SetWindowShadowStyle(rootFrame->StyleUIReset()->mWindowShadow);
   1.688 +
   1.689 +  if (!aRC)
   1.690 +    return;
   1.691 +  
   1.692 +  nsBoxLayoutState aState(aPresContext, aRC);
   1.693 +  nsSize minSize = rootFrame->GetMinSize(aState);
   1.694 +  nsSize maxSize = rootFrame->GetMaxSize(aState);
   1.695 +
   1.696 +  SetSizeConstraints(aPresContext, windowWidget, minSize, maxSize);
   1.697 +#endif
   1.698 +}
   1.699 +
   1.700 +void nsContainerFrame::SetSizeConstraints(nsPresContext* aPresContext,
   1.701 +                                          nsIWidget* aWidget,
   1.702 +                                          const nsSize& aMinSize,
   1.703 +                                          const nsSize& aMaxSize)
   1.704 +{
   1.705 +  nsIntSize devMinSize(aPresContext->AppUnitsToDevPixels(aMinSize.width),
   1.706 +                       aPresContext->AppUnitsToDevPixels(aMinSize.height));
   1.707 +  nsIntSize devMaxSize(aMaxSize.width == NS_INTRINSICSIZE ? NS_MAXSIZE :
   1.708 +                         aPresContext->AppUnitsToDevPixels(aMaxSize.width),
   1.709 +                       aMaxSize.height == NS_INTRINSICSIZE ? NS_MAXSIZE :
   1.710 +                         aPresContext->AppUnitsToDevPixels(aMaxSize.height));
   1.711 +  widget::SizeConstraints constraints(devMinSize, devMaxSize);
   1.712 +
   1.713 +  // The sizes are in inner window sizes, so convert them into outer window sizes.
   1.714 +  // Use a size of (200, 200) as only the difference between the inner and outer
   1.715 +  // size is needed.
   1.716 +  nsIntSize windowSize = aWidget->ClientToWindowSize(nsIntSize(200, 200));
   1.717 +  if (constraints.mMinSize.width)
   1.718 +    constraints.mMinSize.width += windowSize.width - 200;
   1.719 +  if (constraints.mMinSize.height)
   1.720 +    constraints.mMinSize.height += windowSize.height - 200;
   1.721 +  if (constraints.mMaxSize.width != NS_MAXSIZE)
   1.722 +    constraints.mMaxSize.width += windowSize.width - 200;
   1.723 +  if (constraints.mMaxSize.height != NS_MAXSIZE)
   1.724 +    constraints.mMaxSize.height += windowSize.height - 200;
   1.725 +
   1.726 +  aWidget->SetSizeConstraints(constraints);
   1.727 +}
   1.728 +
   1.729 +void
   1.730 +nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
   1.731 +                                           nsIFrame*       aFrame,
   1.732 +                                           nsView*        aView,
   1.733 +                                           const nsRect&   aVisualOverflowArea,
   1.734 +                                           uint32_t        aFlags)
   1.735 +{
   1.736 +  if (!aView) {
   1.737 +    return;
   1.738 +  }
   1.739 +
   1.740 +  // Make sure the view is sized and positioned correctly
   1.741 +  if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
   1.742 +    PositionFrameView(aFrame);
   1.743 +  }
   1.744 +
   1.745 +  if (0 == (aFlags & NS_FRAME_NO_SIZE_VIEW)) {
   1.746 +    nsViewManager* vm = aView->GetViewManager();
   1.747 +
   1.748 +    vm->ResizeView(aView, aVisualOverflowArea, true);
   1.749 +  }
   1.750 +}
   1.751 +
   1.752 +void
   1.753 +nsContainerFrame::SyncFrameViewProperties(nsPresContext*  aPresContext,
   1.754 +                                          nsIFrame*        aFrame,
   1.755 +                                          nsStyleContext*  aStyleContext,
   1.756 +                                          nsView*         aView,
   1.757 +                                          uint32_t         aFlags)
   1.758 +{
   1.759 +  NS_ASSERTION(!aStyleContext || aFrame->StyleContext() == aStyleContext,
   1.760 +               "Wrong style context for frame?");
   1.761 +
   1.762 +  if (!aView) {
   1.763 +    return;
   1.764 +  }
   1.765 +
   1.766 +  nsViewManager* vm = aView->GetViewManager();
   1.767 +
   1.768 +  if (nullptr == aStyleContext) {
   1.769 +    aStyleContext = aFrame->StyleContext();
   1.770 +  }
   1.771 +
   1.772 +  // Make sure visibility is correct. This only affects nsSubdocumentFrame.
   1.773 +  if (0 == (aFlags & NS_FRAME_NO_VISIBILITY) &&
   1.774 +      !aFrame->SupportsVisibilityHidden()) {
   1.775 +    // See if the view should be hidden or visible
   1.776 +    vm->SetViewVisibility(aView,
   1.777 +        aStyleContext->StyleVisibility()->IsVisible()
   1.778 +            ? nsViewVisibility_kShow : nsViewVisibility_kHide);
   1.779 +  }
   1.780 +
   1.781 +  // See if the frame is being relatively positioned or absolutely
   1.782 +  // positioned
   1.783 +  bool isPositioned = aFrame->IsPositioned();
   1.784 +
   1.785 +  int32_t zIndex = 0;
   1.786 +  bool    autoZIndex = false;
   1.787 +
   1.788 +  if (!isPositioned) {
   1.789 +    autoZIndex = true;
   1.790 +  } else {
   1.791 +    // Make sure z-index is correct
   1.792 +    const nsStylePosition* position = aStyleContext->StylePosition();
   1.793 +
   1.794 +    if (position->mZIndex.GetUnit() == eStyleUnit_Integer) {
   1.795 +      zIndex = position->mZIndex.GetIntValue();
   1.796 +    } else if (position->mZIndex.GetUnit() == eStyleUnit_Auto) {
   1.797 +      autoZIndex = true;
   1.798 +    }
   1.799 +  }
   1.800 +
   1.801 +  vm->SetViewZIndex(aView, autoZIndex, zIndex);
   1.802 +}
   1.803 +
   1.804 +static nscoord GetCoord(const nsStyleCoord& aCoord, nscoord aIfNotCoord)
   1.805 +{
   1.806 +  if (aCoord.ConvertsToLength()) {
   1.807 +    return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
   1.808 +  }
   1.809 +  return aIfNotCoord;
   1.810 +}
   1.811 +
   1.812 +void
   1.813 +nsContainerFrame::DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
   1.814 +                                         InlineIntrinsicWidthData *aData,
   1.815 +                                         nsLayoutUtils::IntrinsicWidthType aType)
   1.816 +{
   1.817 +  if (GetPrevInFlow())
   1.818 +    return; // Already added.
   1.819 +
   1.820 +  NS_PRECONDITION(aType == nsLayoutUtils::MIN_WIDTH ||
   1.821 +                  aType == nsLayoutUtils::PREF_WIDTH, "bad type");
   1.822 +
   1.823 +  mozilla::css::Side startSide, endSide;
   1.824 +  if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR) {
   1.825 +    startSide = NS_SIDE_LEFT;
   1.826 +    endSide = NS_SIDE_RIGHT;
   1.827 +  } else {
   1.828 +    startSide = NS_SIDE_RIGHT;
   1.829 +    endSide = NS_SIDE_LEFT;
   1.830 +  }
   1.831 +
   1.832 +  const nsStylePadding *stylePadding = StylePadding();
   1.833 +  const nsStyleBorder *styleBorder = StyleBorder();
   1.834 +  const nsStyleMargin *styleMargin = StyleMargin();
   1.835 +
   1.836 +  // This goes at the beginning no matter how things are broken and how
   1.837 +  // messy the bidi situations are, since per CSS2.1 section 8.6
   1.838 +  // (implemented in bug 328168), the startSide border is always on the
   1.839 +  // first line.
   1.840 +  // This frame is a first-in-flow, but it might have a previous bidi
   1.841 +  // continuation, in which case that continuation should handle the startSide
   1.842 +  // border.
   1.843 +  if (!GetPrevContinuation()) {
   1.844 +    aData->currentLine +=
   1.845 +      // clamp negative calc() to 0
   1.846 +      std::max(GetCoord(stylePadding->mPadding.Get(startSide), 0), 0) +
   1.847 +      styleBorder->GetComputedBorderWidth(startSide) +
   1.848 +      GetCoord(styleMargin->mMargin.Get(startSide), 0);
   1.849 +  }
   1.850 +
   1.851 +  const nsLineList_iterator* savedLine = aData->line;
   1.852 +  nsIFrame* const savedLineContainer = aData->lineContainer;
   1.853 +
   1.854 +  nsContainerFrame *lastInFlow;
   1.855 +  for (nsContainerFrame *nif = this; nif;
   1.856 +       nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) {
   1.857 +    for (nsIFrame *kid = nif->mFrames.FirstChild(); kid;
   1.858 +         kid = kid->GetNextSibling()) {
   1.859 +      if (aType == nsLayoutUtils::MIN_WIDTH)
   1.860 +        kid->AddInlineMinWidth(aRenderingContext,
   1.861 +                               static_cast<InlineMinWidthData*>(aData));
   1.862 +      else
   1.863 +        kid->AddInlinePrefWidth(aRenderingContext,
   1.864 +                                static_cast<InlinePrefWidthData*>(aData));
   1.865 +    }
   1.866 +
   1.867 +    // After we advance to our next-in-flow, the stored line and line container
   1.868 +    // may no longer be correct. Just forget them.
   1.869 +    aData->line = nullptr;
   1.870 +    aData->lineContainer = nullptr;
   1.871 +
   1.872 +    lastInFlow = nif;
   1.873 +  }
   1.874 +
   1.875 +  aData->line = savedLine;
   1.876 +  aData->lineContainer = savedLineContainer;
   1.877 +
   1.878 +  // This goes at the end no matter how things are broken and how
   1.879 +  // messy the bidi situations are, since per CSS2.1 section 8.6
   1.880 +  // (implemented in bug 328168), the endSide border is always on the
   1.881 +  // last line.
   1.882 +  // We reached the last-in-flow, but it might have a next bidi
   1.883 +  // continuation, in which case that continuation should handle
   1.884 +  // the endSide border.
   1.885 +  if (!lastInFlow->GetNextContinuation()) {
   1.886 +    aData->currentLine +=
   1.887 +      // clamp negative calc() to 0
   1.888 +      std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
   1.889 +      styleBorder->GetComputedBorderWidth(endSide) +
   1.890 +      GetCoord(styleMargin->mMargin.Get(endSide), 0);
   1.891 +  }
   1.892 +}
   1.893 +
   1.894 +/* virtual */ nsSize
   1.895 +nsContainerFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
   1.896 +                                  nsSize aCBSize, nscoord aAvailableWidth,
   1.897 +                                  nsSize aMargin, nsSize aBorder,
   1.898 +                                  nsSize aPadding, bool aShrinkWrap)
   1.899 +{
   1.900 +  nsSize result(0xdeadbeef, NS_UNCONSTRAINEDSIZE);
   1.901 +  nscoord availBased = aAvailableWidth - aMargin.width - aBorder.width -
   1.902 +                       aPadding.width;
   1.903 +  // replaced elements always shrink-wrap
   1.904 +  if (aShrinkWrap || IsFrameOfType(eReplaced)) {
   1.905 +    // don't bother setting it if the result won't be used
   1.906 +    if (StylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) {
   1.907 +      result.width = ShrinkWidthToFit(aRenderingContext, availBased);
   1.908 +    }
   1.909 +  } else {
   1.910 +    result.width = availBased;
   1.911 +  }
   1.912 +  return result;
   1.913 +}
   1.914 +
   1.915 +/**
   1.916 + * Invokes the WillReflow() function, positions the frame and its view (if
   1.917 + * requested), and then calls Reflow(). If the reflow succeeds and the child
   1.918 + * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
   1.919 + */
   1.920 +nsresult
   1.921 +nsContainerFrame::ReflowChild(nsIFrame*                aKidFrame,
   1.922 +                              nsPresContext*           aPresContext,
   1.923 +                              nsHTMLReflowMetrics&     aDesiredSize,
   1.924 +                              const nsHTMLReflowState& aReflowState,
   1.925 +                              nscoord                  aX,
   1.926 +                              nscoord                  aY,
   1.927 +                              uint32_t                 aFlags,
   1.928 +                              nsReflowStatus&          aStatus,
   1.929 +                              nsOverflowContinuationTracker* aTracker)
   1.930 +{
   1.931 +  NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state");
   1.932 +
   1.933 +  nsresult  result;
   1.934 +
   1.935 +  // Send the WillReflow() notification, and position the child frame
   1.936 +  // and its view if requested
   1.937 +  aKidFrame->WillReflow(aPresContext);
   1.938 +
   1.939 +  if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
   1.940 +    aKidFrame->SetPosition(nsPoint(aX, aY));
   1.941 +  }
   1.942 +
   1.943 +  if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
   1.944 +    PositionFrameView(aKidFrame);
   1.945 +  }
   1.946 +
   1.947 +  // Reflow the child frame
   1.948 +  result = aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState,
   1.949 +                             aStatus);
   1.950 +
   1.951 +  // If the reflow was successful and the child frame is complete, delete any
   1.952 +  // next-in-flows, but only if the NO_DELETE_NEXT_IN_FLOW flag isn't set.
   1.953 +  if (NS_SUCCEEDED(result) && NS_FRAME_IS_FULLY_COMPLETE(aStatus) &&
   1.954 +      !(aFlags & NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD)) {
   1.955 +    nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
   1.956 +    if (kidNextInFlow) {
   1.957 +      // Remove all of the childs next-in-flows. Make sure that we ask
   1.958 +      // the right parent to do the removal (it's possible that the
   1.959 +      // parent is not this because we are executing pullup code)
   1.960 +      nsOverflowContinuationTracker::AutoFinish fini(aTracker, aKidFrame);
   1.961 +      static_cast<nsContainerFrame*>(kidNextInFlow->GetParent())
   1.962 +        ->DeleteNextInFlowChild(kidNextInFlow, true);
   1.963 +    }
   1.964 +  }
   1.965 +  return result;
   1.966 +}
   1.967 +
   1.968 +
   1.969 +/**
   1.970 + * Position the views of |aFrame|'s descendants. A container frame
   1.971 + * should call this method if it moves a frame after |Reflow|.
   1.972 + */
   1.973 +void
   1.974 +nsContainerFrame::PositionChildViews(nsIFrame* aFrame)
   1.975 +{
   1.976 +  if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
   1.977 +    return;
   1.978 +  }
   1.979 +
   1.980 +  // Recursively walk aFrame's child frames.
   1.981 +  // Process the additional child lists, but skip the popup list as the
   1.982 +  // view for popups is managed by the parent. Currently only nsMenuFrame
   1.983 +  // and nsPopupSetFrame have a popupList and during layout will adjust the
   1.984 +  // view manually to position the popup.
   1.985 +  ChildListIterator lists(aFrame);
   1.986 +  for (; !lists.IsDone(); lists.Next()) {
   1.987 +    if (lists.CurrentID() == kPopupList) {
   1.988 +      continue;
   1.989 +    }
   1.990 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
   1.991 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
   1.992 +      // Position the frame's view (if it has one) otherwise recursively
   1.993 +      // process its children
   1.994 +      nsIFrame* childFrame = childFrames.get();
   1.995 +      if (childFrame->HasView()) {
   1.996 +        PositionFrameView(childFrame);
   1.997 +      } else {
   1.998 +        PositionChildViews(childFrame);
   1.999 +      }
  1.1000 +    }
  1.1001 +  }
  1.1002 +}
  1.1003 +
  1.1004 +/**
  1.1005 + * The second half of frame reflow. Does the following:
  1.1006 + * - sets the frame's bounds
  1.1007 + * - sizes and positions (if requested) the frame's view. If the frame's final
  1.1008 + *   position differs from the current position and the frame itself does not
  1.1009 + *   have a view, then any child frames with views are positioned so they stay
  1.1010 + *   in sync
  1.1011 + * - sets the view's visibility, opacity, content transparency, and clip
  1.1012 + * - invoked the DidReflow() function
  1.1013 + *
  1.1014 + * Flags:
  1.1015 + * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
  1.1016 + *    case. Also implies NS_FRAME_NO_MOVE_VIEW
  1.1017 + * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
  1.1018 + *    don't want to automatically sync the frame and view
  1.1019 + * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
  1.1020 + */
  1.1021 +nsresult
  1.1022 +nsContainerFrame::FinishReflowChild(nsIFrame*                  aKidFrame,
  1.1023 +                                    nsPresContext*             aPresContext,
  1.1024 +                                    const nsHTMLReflowMetrics& aDesiredSize,
  1.1025 +                                    const nsHTMLReflowState*   aReflowState,
  1.1026 +                                    nscoord                    aX,
  1.1027 +                                    nscoord                    aY,
  1.1028 +                                    uint32_t                   aFlags)
  1.1029 +{
  1.1030 +  nsPoint curOrigin = aKidFrame->GetPosition();
  1.1031 +
  1.1032 +  if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
  1.1033 +    aKidFrame->SetRect(nsRect(aX, aY, aDesiredSize.Width(), aDesiredSize.Height()));
  1.1034 +  } else {
  1.1035 +    aKidFrame->SetSize(nsSize(aDesiredSize.Width(), aDesiredSize.Height()));
  1.1036 +  }
  1.1037 +
  1.1038 +  if (aKidFrame->HasView()) {
  1.1039 +    nsView* view = aKidFrame->GetView();
  1.1040 +    // Make sure the frame's view is properly sized and positioned and has
  1.1041 +    // things like opacity correct
  1.1042 +    SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
  1.1043 +                             aDesiredSize.VisualOverflow(), aFlags);
  1.1044 +  }
  1.1045 +
  1.1046 +  if (!(aFlags & NS_FRAME_NO_MOVE_VIEW) &&
  1.1047 +      (curOrigin.x != aX || curOrigin.y != aY)) {
  1.1048 +    if (!aKidFrame->HasView()) {
  1.1049 +      // If the frame has moved, then we need to make sure any child views are
  1.1050 +      // correctly positioned
  1.1051 +      PositionChildViews(aKidFrame);
  1.1052 +    }
  1.1053 +  }
  1.1054 +
  1.1055 +  return aKidFrame->DidReflow(aPresContext, aReflowState, nsDidReflowStatus::FINISHED);
  1.1056 +}
  1.1057 +
  1.1058 +nsresult
  1.1059 +nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext*           aPresContext,
  1.1060 +                                                  const nsHTMLReflowState& aReflowState,
  1.1061 +                                                  nsOverflowAreas&         aOverflowRects,
  1.1062 +                                                  uint32_t                 aFlags,
  1.1063 +                                                  nsReflowStatus&          aStatus)
  1.1064 +{
  1.1065 +  NS_PRECONDITION(aPresContext, "null pointer");
  1.1066 +  nsresult rv = NS_OK;
  1.1067 +
  1.1068 +  nsFrameList* overflowContainers =
  1.1069 +               GetPropTableFrames(OverflowContainersProperty());
  1.1070 +
  1.1071 +  NS_ASSERTION(!(overflowContainers && GetPrevInFlow()
  1.1072 +                 && static_cast<nsContainerFrame*>(GetPrevInFlow())
  1.1073 +                      ->GetPropTableFrames(ExcessOverflowContainersProperty())),
  1.1074 +               "conflicting overflow containers lists");
  1.1075 +
  1.1076 +  if (!overflowContainers) {
  1.1077 +    // Drain excess from previnflow
  1.1078 +    nsContainerFrame* prev = (nsContainerFrame*) GetPrevInFlow();
  1.1079 +    if (prev) {
  1.1080 +      nsFrameList* excessFrames =
  1.1081 +        prev->RemovePropTableFrames(ExcessOverflowContainersProperty());
  1.1082 +      if (excessFrames) {
  1.1083 +        excessFrames->ApplySetParent(this);
  1.1084 +        nsContainerFrame::ReparentFrameViewList(*excessFrames, prev, this);
  1.1085 +        overflowContainers = excessFrames;
  1.1086 +        SetPropTableFrames(overflowContainers, OverflowContainersProperty());
  1.1087 +      }
  1.1088 +    }
  1.1089 +  }
  1.1090 +
  1.1091 +  // Our own excess overflow containers from a previous reflow can still be
  1.1092 +  // present if our next-in-flow hasn't been reflown yet.
  1.1093 +  nsFrameList* selfExcessOCFrames =
  1.1094 +    RemovePropTableFrames(ExcessOverflowContainersProperty());
  1.1095 +  if (selfExcessOCFrames) {
  1.1096 +    if (overflowContainers) {
  1.1097 +      overflowContainers->AppendFrames(nullptr, *selfExcessOCFrames);
  1.1098 +      selfExcessOCFrames->Delete(aPresContext->PresShell());
  1.1099 +    } else {
  1.1100 +      overflowContainers = selfExcessOCFrames;
  1.1101 +      SetPropTableFrames(overflowContainers, OverflowContainersProperty());
  1.1102 +    }
  1.1103 +  }
  1.1104 +  if (!overflowContainers) {
  1.1105 +    return NS_OK; // nothing to reflow
  1.1106 +  }
  1.1107 +
  1.1108 +  nsOverflowContinuationTracker tracker(this, false, false);
  1.1109 +  bool shouldReflowAllKids = aReflowState.ShouldReflowAllKids();
  1.1110 +
  1.1111 +  for (nsIFrame* frame = overflowContainers->FirstChild(); frame;
  1.1112 +       frame = frame->GetNextSibling()) {
  1.1113 +    if (frame->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
  1.1114 +      // frame's prevInFlow has moved, skip reflowing this frame;
  1.1115 +      // it will get reflowed once it's been placed
  1.1116 +      continue;
  1.1117 +    }
  1.1118 +    // If the available vertical height has changed, we need to reflow
  1.1119 +    // even if the frame isn't dirty.
  1.1120 +    if (shouldReflowAllKids || NS_SUBTREE_DIRTY(frame)) {
  1.1121 +      // Get prev-in-flow
  1.1122 +      nsIFrame* prevInFlow = frame->GetPrevInFlow();
  1.1123 +      NS_ASSERTION(prevInFlow,
  1.1124 +                   "overflow container frame must have a prev-in-flow");
  1.1125 +      NS_ASSERTION(frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
  1.1126 +                   "overflow container frame must have overflow container bit set");
  1.1127 +      nsRect prevRect = prevInFlow->GetRect();
  1.1128 +
  1.1129 +      // Initialize reflow params
  1.1130 +      nsSize availSpace(prevRect.width, aReflowState.AvailableHeight());
  1.1131 +      nsHTMLReflowMetrics desiredSize(aReflowState);
  1.1132 +      nsHTMLReflowState frameState(aPresContext, aReflowState,
  1.1133 +                                   frame, availSpace);
  1.1134 +      nsReflowStatus frameStatus;
  1.1135 +
  1.1136 +      // Reflow
  1.1137 +      rv = ReflowChild(frame, aPresContext, desiredSize, frameState,
  1.1138 +                       prevRect.x, 0, aFlags, frameStatus, &tracker);
  1.1139 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1140 +      //XXXfr Do we need to override any shrinkwrap effects here?
  1.1141 +      // e.g. desiredSize.Width() = prevRect.width;
  1.1142 +      rv = FinishReflowChild(frame, aPresContext, desiredSize, &frameState,
  1.1143 +                             prevRect.x, 0, aFlags);
  1.1144 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1145 +
  1.1146 +      // Handle continuations
  1.1147 +      if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus)) {
  1.1148 +        if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
  1.1149 +          // Abspos frames can't cause their parent to be incomplete,
  1.1150 +          // only overflow incomplete.
  1.1151 +          NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus);
  1.1152 +        }
  1.1153 +        else {
  1.1154 +          NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus),
  1.1155 +                       "overflow container frames can't be incomplete, only overflow-incomplete");
  1.1156 +        }
  1.1157 +
  1.1158 +        // Acquire a next-in-flow, creating it if necessary
  1.1159 +        nsIFrame* nif = frame->GetNextInFlow();
  1.1160 +        if (!nif) {
  1.1161 +          NS_ASSERTION(frameStatus & NS_FRAME_REFLOW_NEXTINFLOW,
  1.1162 +                       "Someone forgot a REFLOW_NEXTINFLOW flag");
  1.1163 +          nif = aPresContext->PresShell()->FrameConstructor()->
  1.1164 +            CreateContinuingFrame(aPresContext, frame, this);
  1.1165 +        }
  1.1166 +        else if (!(nif->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
  1.1167 +          // used to be a normal next-in-flow; steal it from the child list
  1.1168 +          rv = static_cast<nsContainerFrame*>(nif->GetParent())
  1.1169 +                 ->StealFrame(nif);
  1.1170 +          NS_ENSURE_SUCCESS(rv, rv);
  1.1171 +        }
  1.1172 +
  1.1173 +        tracker.Insert(nif, frameStatus);
  1.1174 +      }
  1.1175 +      NS_MergeReflowStatusInto(&aStatus, frameStatus);
  1.1176 +      // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
  1.1177 +      // but we have some unsplittable frames that, when taller than
  1.1178 +      // availableHeight will push zero-height content into a next-in-flow.
  1.1179 +    }
  1.1180 +    else {
  1.1181 +      tracker.Skip(frame, aStatus);
  1.1182 +      if (aReflowState.mFloatManager)
  1.1183 +        nsBlockFrame::RecoverFloatsFor(frame, *aReflowState.mFloatManager);
  1.1184 +    }
  1.1185 +    ConsiderChildOverflow(aOverflowRects, frame);
  1.1186 +  }
  1.1187 +
  1.1188 +  return NS_OK;
  1.1189 +}
  1.1190 +
  1.1191 +void
  1.1192 +nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder*   aBuilder,
  1.1193 +                                            const nsRect&           aDirtyRect,
  1.1194 +                                            const nsDisplayListSet& aLists)
  1.1195 +{
  1.1196 +  nsFrameList* overflowconts = GetPropTableFrames(OverflowContainersProperty());
  1.1197 +  if (overflowconts) {
  1.1198 +    for (nsIFrame* frame = overflowconts->FirstChild(); frame;
  1.1199 +         frame = frame->GetNextSibling()) {
  1.1200 +      BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists);
  1.1201 +    }
  1.1202 +  }
  1.1203 +}
  1.1204 +
  1.1205 +static bool
  1.1206 +TryRemoveFrame(nsIFrame* aFrame, FramePropertyTable* aPropTable,
  1.1207 +               const FramePropertyDescriptor* aProp, nsIFrame* aChildToRemove)
  1.1208 +{
  1.1209 +  nsFrameList* list = static_cast<nsFrameList*>(aPropTable->Get(aFrame, aProp));
  1.1210 +  if (list && list->StartRemoveFrame(aChildToRemove)) {
  1.1211 +    // aChildToRemove *may* have been removed from this list.
  1.1212 +    if (list->IsEmpty()) {
  1.1213 +      aPropTable->Remove(aFrame, aProp);
  1.1214 +      list->Delete(aFrame->PresContext()->PresShell());
  1.1215 +    }
  1.1216 +    return true;
  1.1217 +  }
  1.1218 +  return false;
  1.1219 +}
  1.1220 +
  1.1221 +nsresult
  1.1222 +nsContainerFrame::StealFrame(nsIFrame* aChild,
  1.1223 +                             bool      aForceNormal)
  1.1224 +{
  1.1225 +#ifdef DEBUG
  1.1226 +  if (!mFrames.ContainsFrame(aChild)) {
  1.1227 +    nsFrameList* list = GetOverflowFrames();
  1.1228 +    if (!list || !list->ContainsFrame(aChild)) {
  1.1229 +      FramePropertyTable* propTable = PresContext()->PropertyTable();
  1.1230 +      list = static_cast<nsFrameList*>(
  1.1231 +               propTable->Get(this, OverflowContainersProperty()));
  1.1232 +      if (!list || !list->ContainsFrame(aChild)) {
  1.1233 +        list = static_cast<nsFrameList*>(
  1.1234 +                 propTable->Get(this, ExcessOverflowContainersProperty()));
  1.1235 +        MOZ_ASSERT(list && list->ContainsFrame(aChild), "aChild isn't our child"
  1.1236 +                   " or on a frame list not supported by StealFrame");
  1.1237 +      }
  1.1238 +    }
  1.1239 +  }
  1.1240 +#endif
  1.1241 +
  1.1242 +  bool removed;
  1.1243 +  if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
  1.1244 +      && !aForceNormal) {
  1.1245 +    FramePropertyTable* propTable = PresContext()->PropertyTable();
  1.1246 +    // Try removing from the overflow container list.
  1.1247 +    removed = ::TryRemoveFrame(this, propTable, OverflowContainersProperty(),
  1.1248 +                               aChild);
  1.1249 +    if (!removed) {
  1.1250 +      // It must be in the excess overflow container list.
  1.1251 +      removed = ::TryRemoveFrame(this, propTable,
  1.1252 +                                 ExcessOverflowContainersProperty(),
  1.1253 +                                 aChild);
  1.1254 +    }
  1.1255 +  } else {
  1.1256 +    removed = mFrames.StartRemoveFrame(aChild);
  1.1257 +    if (!removed) {
  1.1258 +      // We didn't find the child in our principal child list.
  1.1259 +      // Maybe it's on the overflow list?
  1.1260 +      nsFrameList* frameList = GetOverflowFrames();
  1.1261 +      if (frameList) {
  1.1262 +        removed = frameList->ContinueRemoveFrame(aChild);
  1.1263 +        if (frameList->IsEmpty()) {
  1.1264 +          DestroyOverflowList();
  1.1265 +        }
  1.1266 +      }
  1.1267 +    }
  1.1268 +  }
  1.1269 +
  1.1270 +  NS_POSTCONDITION(removed, "StealFrame: can't find aChild");
  1.1271 +  return removed ? NS_OK : NS_ERROR_UNEXPECTED;
  1.1272 +}
  1.1273 +
  1.1274 +nsFrameList
  1.1275 +nsContainerFrame::StealFramesAfter(nsIFrame* aChild)
  1.1276 +{
  1.1277 +  NS_ASSERTION(!aChild ||
  1.1278 +               !(aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER),
  1.1279 +               "StealFramesAfter doesn't handle overflow containers");
  1.1280 +  NS_ASSERTION(GetType() != nsGkAtoms::blockFrame, "unexpected call");
  1.1281 +
  1.1282 +  if (!aChild) {
  1.1283 +    nsFrameList copy(mFrames);
  1.1284 +    mFrames.Clear();
  1.1285 +    return copy;
  1.1286 +  }
  1.1287 +
  1.1288 +  for (nsFrameList::FrameLinkEnumerator iter(mFrames); !iter.AtEnd();
  1.1289 +       iter.Next()) {
  1.1290 +    if (iter.PrevFrame() == aChild) {
  1.1291 +      return mFrames.ExtractTail(iter);
  1.1292 +    }
  1.1293 +  }
  1.1294 +
  1.1295 +  // We didn't find the child in the principal child list.
  1.1296 +  // Maybe it's on the overflow list?
  1.1297 +  nsFrameList* overflowFrames = GetOverflowFrames();
  1.1298 +  if (overflowFrames) {
  1.1299 +    for (nsFrameList::FrameLinkEnumerator iter(*overflowFrames); !iter.AtEnd();
  1.1300 +         iter.Next()) {
  1.1301 +      if (iter.PrevFrame() == aChild) {
  1.1302 +        return overflowFrames->ExtractTail(iter);
  1.1303 +      }
  1.1304 +    }
  1.1305 +  }
  1.1306 +
  1.1307 +  NS_ERROR("StealFramesAfter: can't find aChild");
  1.1308 +  return nsFrameList::EmptyList();
  1.1309 +}
  1.1310 +
  1.1311 +/*
  1.1312 + * Create a next-in-flow for aFrame. Will return the newly created
  1.1313 + * frame in aNextInFlowResult <b>if and only if</b> a new frame is
  1.1314 + * created; otherwise nullptr is returned in aNextInFlowResult.
  1.1315 + */
  1.1316 +nsresult
  1.1317 +nsContainerFrame::CreateNextInFlow(nsIFrame*  aFrame,
  1.1318 +                                   nsIFrame*& aNextInFlowResult)
  1.1319 +{
  1.1320 +  NS_PRECONDITION(GetType() != nsGkAtoms::blockFrame,
  1.1321 +                  "you should have called nsBlockFrame::CreateContinuationFor instead");
  1.1322 +  NS_PRECONDITION(mFrames.ContainsFrame(aFrame), "expected an in-flow child frame");
  1.1323 +
  1.1324 +  nsPresContext* pc = PresContext();
  1.1325 +  aNextInFlowResult = nullptr;
  1.1326 +
  1.1327 +  nsIFrame* nextInFlow = aFrame->GetNextInFlow();
  1.1328 +  if (nullptr == nextInFlow) {
  1.1329 +    // Create a continuation frame for the child frame and insert it
  1.1330 +    // into our child list.
  1.1331 +    nextInFlow = pc->PresShell()->FrameConstructor()->
  1.1332 +      CreateContinuingFrame(pc, aFrame, this);
  1.1333 +    mFrames.InsertFrame(nullptr, aFrame, nextInFlow);
  1.1334 +
  1.1335 +    NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES,
  1.1336 +       ("nsContainerFrame::CreateNextInFlow: frame=%p nextInFlow=%p",
  1.1337 +        aFrame, nextInFlow));
  1.1338 +
  1.1339 +    aNextInFlowResult = nextInFlow;
  1.1340 +  }
  1.1341 +  return NS_OK;
  1.1342 +}
  1.1343 +
  1.1344 +/**
  1.1345 + * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
  1.1346 + * pointers
  1.1347 + */
  1.1348 +void
  1.1349 +nsContainerFrame::DeleteNextInFlowChild(nsIFrame* aNextInFlow,
  1.1350 +                                        bool      aDeletingEmptyFrames)
  1.1351 +{
  1.1352 +#ifdef DEBUG
  1.1353 +  nsIFrame* prevInFlow = aNextInFlow->GetPrevInFlow();
  1.1354 +#endif
  1.1355 +  NS_PRECONDITION(prevInFlow, "bad prev-in-flow");
  1.1356 +
  1.1357 +  // If the next-in-flow has a next-in-flow then delete it, too (and
  1.1358 +  // delete it first).
  1.1359 +  // Do this in a loop so we don't overflow the stack for frames
  1.1360 +  // with very many next-in-flows
  1.1361 +  nsIFrame* nextNextInFlow = aNextInFlow->GetNextInFlow();
  1.1362 +  if (nextNextInFlow) {
  1.1363 +    nsAutoTArray<nsIFrame*, 8> frames;
  1.1364 +    for (nsIFrame* f = nextNextInFlow; f; f = f->GetNextInFlow()) {
  1.1365 +      frames.AppendElement(f);
  1.1366 +    }
  1.1367 +    for (int32_t i = frames.Length() - 1; i >= 0; --i) {
  1.1368 +      nsIFrame* delFrame = frames.ElementAt(i);
  1.1369 +      static_cast<nsContainerFrame*>(delFrame->GetParent())
  1.1370 +        ->DeleteNextInFlowChild(delFrame, aDeletingEmptyFrames);
  1.1371 +    }
  1.1372 +  }
  1.1373 +
  1.1374 +  // Take the next-in-flow out of the parent's child list
  1.1375 +  DebugOnly<nsresult> rv = StealFrame(aNextInFlow);
  1.1376 +  NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
  1.1377 +
  1.1378 +#ifdef DEBUG
  1.1379 +  if (aDeletingEmptyFrames) {
  1.1380 +    nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow);
  1.1381 +  }
  1.1382 +#endif
  1.1383 +
  1.1384 +  // Delete the next-in-flow frame and its descendants. This will also
  1.1385 +  // remove it from its next-in-flow/prev-in-flow chain.
  1.1386 +  aNextInFlow->Destroy();
  1.1387 +
  1.1388 +  NS_POSTCONDITION(!prevInFlow->GetNextInFlow(), "non null next-in-flow");
  1.1389 +}
  1.1390 +
  1.1391 +/**
  1.1392 + * Set the frames on the overflow list
  1.1393 + */
  1.1394 +void
  1.1395 +nsContainerFrame::SetOverflowFrames(const nsFrameList& aOverflowFrames)
  1.1396 +{
  1.1397 +  NS_PRECONDITION(aOverflowFrames.NotEmpty(), "Shouldn't be called");
  1.1398 +
  1.1399 +  nsPresContext* pc = PresContext();
  1.1400 +  nsFrameList* newList = new (pc->PresShell()) nsFrameList(aOverflowFrames);
  1.1401 +
  1.1402 +  pc->PropertyTable()->Set(this, OverflowProperty(), newList);
  1.1403 +}
  1.1404 +
  1.1405 +nsFrameList*
  1.1406 +nsContainerFrame::GetPropTableFrames(const FramePropertyDescriptor* aProperty) const
  1.1407 +{
  1.1408 +  FramePropertyTable* propTable = PresContext()->PropertyTable();
  1.1409 +  return static_cast<nsFrameList*>(propTable->Get(this, aProperty));
  1.1410 +}
  1.1411 +
  1.1412 +nsFrameList*
  1.1413 +nsContainerFrame::RemovePropTableFrames(const FramePropertyDescriptor* aProperty)
  1.1414 +{
  1.1415 +  FramePropertyTable* propTable = PresContext()->PropertyTable();
  1.1416 +  return static_cast<nsFrameList*>(propTable->Remove(this, aProperty));
  1.1417 +}
  1.1418 +
  1.1419 +void
  1.1420 +nsContainerFrame::SetPropTableFrames(nsFrameList*                   aFrameList,
  1.1421 +                                     const FramePropertyDescriptor* aProperty)
  1.1422 +{
  1.1423 +  NS_PRECONDITION(aProperty && aFrameList, "null ptr");
  1.1424 +  NS_PRECONDITION(
  1.1425 +    (aProperty != nsContainerFrame::OverflowContainersProperty() &&
  1.1426 +     aProperty != nsContainerFrame::ExcessOverflowContainersProperty()) ||
  1.1427 +    IsFrameOfType(nsIFrame::eCanContainOverflowContainers),
  1.1428 +    "this type of frame can't have overflow containers");
  1.1429 +  MOZ_ASSERT(!GetPropTableFrames(aProperty));
  1.1430 +  PresContext()->PropertyTable()->Set(this, aProperty, aFrameList);
  1.1431 +}
  1.1432 +
  1.1433 +/**
  1.1434 + * Push aFromChild and its next siblings to the next-in-flow. Change the
  1.1435 + * geometric parent of each frame that's pushed. If there is no next-in-flow
  1.1436 + * the frames are placed on the overflow list (and the geometric parent is
  1.1437 + * left unchanged).
  1.1438 + *
  1.1439 + * Updates the next-in-flow's child count. Does <b>not</b> update the
  1.1440 + * pusher's child count.
  1.1441 + *
  1.1442 + * @param   aFromChild the first child frame to push. It is disconnected from
  1.1443 + *            aPrevSibling
  1.1444 + * @param   aPrevSibling aFromChild's previous sibling. Must not be null. It's
  1.1445 + *            an error to push a parent's first child frame
  1.1446 + */
  1.1447 +void
  1.1448 +nsContainerFrame::PushChildren(nsIFrame* aFromChild,
  1.1449 +                               nsIFrame* aPrevSibling)
  1.1450 +{
  1.1451 +  NS_PRECONDITION(aFromChild, "null pointer");
  1.1452 +  NS_PRECONDITION(aPrevSibling, "pushing first child");
  1.1453 +  NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
  1.1454 +
  1.1455 +  // Disconnect aFromChild from its previous sibling
  1.1456 +  nsFrameList tail = mFrames.RemoveFramesAfter(aPrevSibling);
  1.1457 +
  1.1458 +  nsContainerFrame* nextInFlow =
  1.1459 +    static_cast<nsContainerFrame*>(GetNextInFlow());
  1.1460 +  if (nextInFlow) {
  1.1461 +    // XXX This is not a very good thing to do. If it gets removed
  1.1462 +    // then remove the copy of this routine that doesn't do this from
  1.1463 +    // nsInlineFrame.
  1.1464 +    // When pushing and pulling frames we need to check for whether any
  1.1465 +    // views need to be reparented.
  1.1466 +    for (nsIFrame* f = aFromChild; f; f = f->GetNextSibling()) {
  1.1467 +      nsContainerFrame::ReparentFrameView(f, this, nextInFlow);
  1.1468 +    }
  1.1469 +    nextInFlow->mFrames.InsertFrames(nextInFlow, nullptr, tail);
  1.1470 +  }
  1.1471 +  else {
  1.1472 +    // Add the frames to our overflow list
  1.1473 +    SetOverflowFrames(tail);
  1.1474 +  }
  1.1475 +}
  1.1476 +
  1.1477 +/**
  1.1478 + * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
  1.1479 + * the receiver's overflow list) to the child list.
  1.1480 + *
  1.1481 + * Updates this frame's child count and content mapping.
  1.1482 + *
  1.1483 + * @return  true if any frames were moved and false otherwise
  1.1484 + */
  1.1485 +bool
  1.1486 +nsContainerFrame::MoveOverflowToChildList()
  1.1487 +{
  1.1488 +  bool result = false;
  1.1489 +
  1.1490 +  // Check for an overflow list with our prev-in-flow
  1.1491 +  nsContainerFrame* prevInFlow = (nsContainerFrame*)GetPrevInFlow();
  1.1492 +  if (nullptr != prevInFlow) {
  1.1493 +    AutoFrameListPtr prevOverflowFrames(PresContext(),
  1.1494 +                                        prevInFlow->StealOverflowFrames());
  1.1495 +    if (prevOverflowFrames) {
  1.1496 +      // Tables are special; they can have repeated header/footer
  1.1497 +      // frames on mFrames at this point.
  1.1498 +      NS_ASSERTION(mFrames.IsEmpty() || GetType() == nsGkAtoms::tableFrame,
  1.1499 +                   "bad overflow list");
  1.1500 +      // When pushing and pulling frames we need to check for whether any
  1.1501 +      // views need to be reparented.
  1.1502 +      nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames,
  1.1503 +                                              prevInFlow, this);
  1.1504 +      mFrames.AppendFrames(this, *prevOverflowFrames);
  1.1505 +      result = true;
  1.1506 +    }
  1.1507 +  }
  1.1508 +
  1.1509 +  // It's also possible that we have an overflow list for ourselves.
  1.1510 +  return DrainSelfOverflowList() || result;
  1.1511 +}
  1.1512 +
  1.1513 +bool
  1.1514 +nsContainerFrame::DrainSelfOverflowList()
  1.1515 +{
  1.1516 +  AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
  1.1517 +  if (overflowFrames) {
  1.1518 +    NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
  1.1519 +    mFrames.AppendFrames(nullptr, *overflowFrames);
  1.1520 +    return true;
  1.1521 +  }
  1.1522 +  return false;
  1.1523 +}
  1.1524 +
  1.1525 +nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsContainerFrame* aFrame,
  1.1526 +                                                             bool              aWalkOOFFrames,
  1.1527 +                                                             bool              aSkipOverflowContainerChildren)
  1.1528 +  : mOverflowContList(nullptr),
  1.1529 +    mPrevOverflowCont(nullptr),
  1.1530 +    mSentry(nullptr),
  1.1531 +    mParent(aFrame),
  1.1532 +    mSkipOverflowContainerChildren(aSkipOverflowContainerChildren),
  1.1533 +    mWalkOOFFrames(aWalkOOFFrames)
  1.1534 +{
  1.1535 +  NS_PRECONDITION(aFrame, "null frame pointer");
  1.1536 +  SetupOverflowContList();
  1.1537 +}
  1.1538 +
  1.1539 +void
  1.1540 +nsOverflowContinuationTracker::SetupOverflowContList()
  1.1541 +{
  1.1542 +  NS_PRECONDITION(mParent, "null frame pointer");
  1.1543 +  NS_PRECONDITION(!mOverflowContList, "already have list");
  1.1544 +  nsContainerFrame* nif =
  1.1545 +    static_cast<nsContainerFrame*>(mParent->GetNextInFlow());
  1.1546 +  if (nif) {
  1.1547 +    mOverflowContList = nif->GetPropTableFrames(
  1.1548 +      nsContainerFrame::OverflowContainersProperty());
  1.1549 +    if (mOverflowContList) {
  1.1550 +      mParent = nif;
  1.1551 +      SetUpListWalker();
  1.1552 +    }
  1.1553 +  }
  1.1554 +  if (!mOverflowContList) {
  1.1555 +    mOverflowContList = mParent->GetPropTableFrames(
  1.1556 +      nsContainerFrame::ExcessOverflowContainersProperty());
  1.1557 +    if (mOverflowContList) {
  1.1558 +      SetUpListWalker();
  1.1559 +    }
  1.1560 +  }
  1.1561 +}
  1.1562 +
  1.1563 +/**
  1.1564 + * Helper function to walk past overflow continuations whose prev-in-flow
  1.1565 + * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
  1.1566 + */
  1.1567 +void
  1.1568 +nsOverflowContinuationTracker::SetUpListWalker()
  1.1569 +{
  1.1570 +  NS_ASSERTION(!mSentry && !mPrevOverflowCont,
  1.1571 +               "forgot to reset mSentry or mPrevOverflowCont");
  1.1572 +  if (mOverflowContList) {
  1.1573 +    nsIFrame* cur = mOverflowContList->FirstChild();
  1.1574 +    if (mSkipOverflowContainerChildren) {
  1.1575 +      while (cur && (cur->GetPrevInFlow()->GetStateBits()
  1.1576 +                     & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
  1.1577 +        mPrevOverflowCont = cur;
  1.1578 +        cur = cur->GetNextSibling();
  1.1579 +      }
  1.1580 +      while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
  1.1581 +                     == mWalkOOFFrames)) {
  1.1582 +        mPrevOverflowCont = cur;
  1.1583 +        cur = cur->GetNextSibling();
  1.1584 +      }
  1.1585 +    }
  1.1586 +    if (cur) {
  1.1587 +      mSentry = cur->GetPrevInFlow();
  1.1588 +    }
  1.1589 +  }
  1.1590 +}
  1.1591 +
  1.1592 +/**
  1.1593 + * Helper function to step forward through the overflow continuations list.
  1.1594 + * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
  1.1595 + * as appropriate. May only be called when we have already set up an
  1.1596 + * mOverflowContList; mOverflowContList cannot be null.
  1.1597 + */
  1.1598 +void
  1.1599 +nsOverflowContinuationTracker::StepForward()
  1.1600 +{
  1.1601 +  NS_PRECONDITION(mOverflowContList, "null list");
  1.1602 +
  1.1603 +  // Step forward
  1.1604 +  if (mPrevOverflowCont) {
  1.1605 +    mPrevOverflowCont = mPrevOverflowCont->GetNextSibling();
  1.1606 +  }
  1.1607 +  else {
  1.1608 +    mPrevOverflowCont = mOverflowContList->FirstChild();
  1.1609 +  }
  1.1610 +
  1.1611 +  // Skip over oof or non-oof frames as appropriate
  1.1612 +  if (mSkipOverflowContainerChildren) {
  1.1613 +    nsIFrame* cur = mPrevOverflowCont->GetNextSibling();
  1.1614 +    while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
  1.1615 +                   == mWalkOOFFrames)) {
  1.1616 +      mPrevOverflowCont = cur;
  1.1617 +      cur = cur->GetNextSibling();
  1.1618 +    }
  1.1619 +  }
  1.1620 +
  1.1621 +  // Set up the sentry
  1.1622 +  mSentry = (mPrevOverflowCont->GetNextSibling())
  1.1623 +            ? mPrevOverflowCont->GetNextSibling()->GetPrevInFlow()
  1.1624 +            : nullptr;
  1.1625 +}
  1.1626 +
  1.1627 +nsresult
  1.1628 +nsOverflowContinuationTracker::Insert(nsIFrame*       aOverflowCont,
  1.1629 +                                      nsReflowStatus& aReflowStatus)
  1.1630 +{
  1.1631 +  NS_PRECONDITION(aOverflowCont, "null frame pointer");
  1.1632 +  NS_PRECONDITION(!mSkipOverflowContainerChildren || mWalkOOFFrames ==
  1.1633 +                  !!(aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
  1.1634 +                  "shouldn't insert frame that doesn't match walker type");
  1.1635 +  NS_PRECONDITION(aOverflowCont->GetPrevInFlow(),
  1.1636 +                  "overflow containers must have a prev-in-flow");
  1.1637 +  nsresult rv = NS_OK;
  1.1638 +  bool reparented = false;
  1.1639 +  nsPresContext* presContext = aOverflowCont->PresContext();
  1.1640 +  bool addToList = !mSentry || aOverflowCont != mSentry->GetNextInFlow();
  1.1641 +
  1.1642 +  // If we have a list and aOverflowCont is already in it then don't try to
  1.1643 +  // add it again.
  1.1644 +  if (addToList && aOverflowCont->GetParent() == mParent &&
  1.1645 +      (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) &&
  1.1646 +      mOverflowContList && mOverflowContList->ContainsFrame(aOverflowCont)) {
  1.1647 +    addToList = false;
  1.1648 +    mPrevOverflowCont = aOverflowCont->GetPrevSibling();
  1.1649 +  }
  1.1650 +
  1.1651 +  if (addToList) {
  1.1652 +    if (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
  1.1653 +      // aOverflowCont is in some other overflow container list,
  1.1654 +      // steal it first
  1.1655 +      NS_ASSERTION(!(mOverflowContList &&
  1.1656 +                     mOverflowContList->ContainsFrame(aOverflowCont)),
  1.1657 +                   "overflow containers out of order");
  1.1658 +      rv = static_cast<nsContainerFrame*>(aOverflowCont->GetParent())
  1.1659 +             ->StealFrame(aOverflowCont);
  1.1660 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1661 +    }
  1.1662 +    else {
  1.1663 +      aOverflowCont->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
  1.1664 +    }
  1.1665 +    if (!mOverflowContList) {
  1.1666 +      mOverflowContList = new (presContext->PresShell()) nsFrameList();
  1.1667 +      mParent->SetPropTableFrames(mOverflowContList,
  1.1668 +        nsContainerFrame::ExcessOverflowContainersProperty());
  1.1669 +      SetUpListWalker();
  1.1670 +    }
  1.1671 +    if (aOverflowCont->GetParent() != mParent) {
  1.1672 +      nsContainerFrame::ReparentFrameView(aOverflowCont,
  1.1673 +                                          aOverflowCont->GetParent(),
  1.1674 +                                          mParent);
  1.1675 +      reparented = true;
  1.1676 +    }
  1.1677 +
  1.1678 +    // If aOverflowCont has a prev/next-in-flow that might be in
  1.1679 +    // mOverflowContList we need to find it and insert after/before it to
  1.1680 +    // maintain the order amongst next-in-flows in this list.
  1.1681 +    nsIFrame* pif = aOverflowCont->GetPrevInFlow();
  1.1682 +    nsIFrame* nif = aOverflowCont->GetNextInFlow();
  1.1683 +    if ((pif && pif->GetParent() == mParent && pif != mPrevOverflowCont) ||
  1.1684 +        (nif && nif->GetParent() == mParent && mPrevOverflowCont)) {
  1.1685 +      for (nsFrameList::Enumerator e(*mOverflowContList); !e.AtEnd(); e.Next()) {
  1.1686 +        nsIFrame* f = e.get();
  1.1687 +        if (f == pif) {
  1.1688 +          mPrevOverflowCont = pif;
  1.1689 +          break;
  1.1690 +        }
  1.1691 +        if (f == nif) {
  1.1692 +          mPrevOverflowCont = f->GetPrevSibling();
  1.1693 +          break;
  1.1694 +        }
  1.1695 +      }
  1.1696 +    }
  1.1697 +
  1.1698 +    mOverflowContList->InsertFrame(mParent, mPrevOverflowCont, aOverflowCont);
  1.1699 +    aReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
  1.1700 +  }
  1.1701 +
  1.1702 +  // If we need to reflow it, mark it dirty
  1.1703 +  if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW)
  1.1704 +    aOverflowCont->AddStateBits(NS_FRAME_IS_DIRTY);
  1.1705 +
  1.1706 +  // It's in our list, just step forward
  1.1707 +  StepForward();
  1.1708 +  NS_ASSERTION(mPrevOverflowCont == aOverflowCont ||
  1.1709 +               (mSkipOverflowContainerChildren &&
  1.1710 +                (mPrevOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW) !=
  1.1711 +                (aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW)),
  1.1712 +              "OverflowContTracker in unexpected state");
  1.1713 +
  1.1714 +  if (addToList) {
  1.1715 +    // Convert all non-overflow-container continuations of aOverflowCont
  1.1716 +    // into overflow containers and move them to our overflow
  1.1717 +    // tracker. This preserves the invariant that the next-continuations
  1.1718 +    // of an overflow container are also overflow containers.
  1.1719 +    nsIFrame* f = aOverflowCont->GetNextContinuation();
  1.1720 +    if (f && (!(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) ||
  1.1721 +              (!reparented && f->GetParent() == mParent) ||
  1.1722 +              (reparented && f->GetParent() != mParent))) {
  1.1723 +      if (!(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
  1.1724 +        nsContainerFrame* parent = static_cast<nsContainerFrame*>(f->GetParent());
  1.1725 +        rv = parent->StealFrame(f);
  1.1726 +        NS_ENSURE_SUCCESS(rv, rv);
  1.1727 +      }
  1.1728 +      Insert(f, aReflowStatus);
  1.1729 +    }
  1.1730 +  }
  1.1731 +  return rv;
  1.1732 +}
  1.1733 +
  1.1734 +void
  1.1735 +nsOverflowContinuationTracker::BeginFinish(nsIFrame* aChild)
  1.1736 +{
  1.1737 +  NS_PRECONDITION(aChild, "null ptr");
  1.1738 +  NS_PRECONDITION(aChild->GetNextInFlow(),
  1.1739 +                  "supposed to call Finish *before* deleting next-in-flow!");
  1.1740 +  for (nsIFrame* f = aChild; f; f = f->GetNextInFlow()) {
  1.1741 +    // We'll update these in EndFinish after the next-in-flows are gone.
  1.1742 +    if (f == mPrevOverflowCont) {
  1.1743 +      mSentry = nullptr;
  1.1744 +      mPrevOverflowCont = nullptr;
  1.1745 +      break;
  1.1746 +    }
  1.1747 +    if (f == mSentry) {
  1.1748 +      mSentry = nullptr;
  1.1749 +      break;
  1.1750 +    }
  1.1751 +  }
  1.1752 +}
  1.1753 +
  1.1754 +void
  1.1755 +nsOverflowContinuationTracker::EndFinish(nsIFrame* aChild)
  1.1756 +{
  1.1757 +  if (!mOverflowContList) {
  1.1758 +    return;
  1.1759 +  }
  1.1760 +  // Forget mOverflowContList if it was deleted.
  1.1761 +  nsPresContext* pc = aChild->PresContext();
  1.1762 +  FramePropertyTable* propTable = pc->PropertyTable();
  1.1763 +  nsFrameList* eoc = static_cast<nsFrameList*>(propTable->Get(mParent,
  1.1764 +                       nsContainerFrame::ExcessOverflowContainersProperty()));
  1.1765 +  if (eoc != mOverflowContList) {
  1.1766 +    nsFrameList* oc = static_cast<nsFrameList*>(propTable->Get(mParent,
  1.1767 +                        nsContainerFrame::OverflowContainersProperty()));
  1.1768 +    if (oc != mOverflowContList) {
  1.1769 +      // mOverflowContList was deleted
  1.1770 +      mPrevOverflowCont = nullptr;
  1.1771 +      mSentry = nullptr;
  1.1772 +      mParent = static_cast<nsContainerFrame*>(aChild->GetParent());
  1.1773 +      mOverflowContList = nullptr;
  1.1774 +      SetupOverflowContList();
  1.1775 +      return;
  1.1776 +    }
  1.1777 +  }
  1.1778 +  // The list survived, update mSentry if needed.
  1.1779 +  if (!mSentry) {
  1.1780 +    if (!mPrevOverflowCont) {
  1.1781 +      SetUpListWalker();
  1.1782 +    } else {
  1.1783 +      mozilla::AutoRestore<nsIFrame*> saved(mPrevOverflowCont);
  1.1784 +      // step backward to make StepForward() use our current mPrevOverflowCont
  1.1785 +      mPrevOverflowCont = mPrevOverflowCont->GetPrevSibling();
  1.1786 +      StepForward();
  1.1787 +    }
  1.1788 +  }
  1.1789 +}
  1.1790 +
  1.1791 +/////////////////////////////////////////////////////////////////////////////
  1.1792 +// Debugging
  1.1793 +
  1.1794 +#ifdef DEBUG_FRAME_DUMP
  1.1795 +void
  1.1796 +nsContainerFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
  1.1797 +{
  1.1798 +  nsCString str;
  1.1799 +  ListGeneric(str, aPrefix, aFlags);
  1.1800 +
  1.1801 +  // Output the children
  1.1802 +  bool outputOneList = false;
  1.1803 +  ChildListIterator lists(this);
  1.1804 +  for (; !lists.IsDone(); lists.Next()) {
  1.1805 +    if (outputOneList) {
  1.1806 +      str += aPrefix;
  1.1807 +    }
  1.1808 +    if (lists.CurrentID() != kPrincipalList) {
  1.1809 +      if (!outputOneList) {
  1.1810 +        str += "\n";
  1.1811 +        str += aPrefix;
  1.1812 +      }
  1.1813 +      str += nsPrintfCString("%s %p ", mozilla::layout::ChildListName(lists.CurrentID()),
  1.1814 +                             &GetChildList(lists.CurrentID()));
  1.1815 +    }
  1.1816 +    fprintf_stderr(out, "%s<\n", str.get());
  1.1817 +    str = "";
  1.1818 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.1819 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.1820 +      nsIFrame* kid = childFrames.get();
  1.1821 +      // Verify the child frame's parent frame pointer is correct
  1.1822 +      NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");
  1.1823 +
  1.1824 +      // Have the child frame list
  1.1825 +      nsCString pfx(aPrefix);
  1.1826 +      pfx += "  ";
  1.1827 +      kid->List(out, pfx.get(), aFlags);
  1.1828 +    }
  1.1829 +    fprintf_stderr(out, "%s>\n", aPrefix);
  1.1830 +    outputOneList = true;
  1.1831 +  }
  1.1832 +
  1.1833 +  if (!outputOneList) {
  1.1834 +    fprintf_stderr(out, "%s<>\n", str.get());
  1.1835 +  }
  1.1836 +}
  1.1837 +#endif

mercurial