Bug 1290335: Hoist frame-construction logic in RestyleManager to static members in RestyleManagerBase. r=heycam
authorEmilio Cobos Álvarez <ecoal95@gmail.com>
Mon, 01 Aug 2016 13:31:57 -0700
changeset 308043 a8d9d9b868d60a58860db5c6b429fdb0bda1d148
parent 308042 4714ae58c55efc58987c5a30bf4a824392018500
child 308044 778a903685fe8730dbefe9ee61ce7f27c33e1fff
push id80239
push userecoal95@gmail.com
push dateWed, 03 Aug 2016 22:15:55 +0000
treeherdermozilla-inbound@bf81d98a39e9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1290335
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1290335: Hoist frame-construction logic in RestyleManager to static members in RestyleManagerBase. r=heycam MozReview-Commit-ID: BqywJXZ0CYU
layout/base/RestyleManager.cpp
layout/base/RestyleManager.h
layout/base/RestyleManagerBase.cpp
layout/base/RestyleManagerBase.h
layout/base/RestyleManagerHandle.h
layout/base/RestyleManagerHandleInlines.h
layout/base/ServoRestyleManager.cpp
layout/base/ServoRestyleManager.h
layout/base/nsCSSFrameConstructor.h
layout/base/nsCSSRendering.cpp
layout/base/nsPresShell.cpp
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -106,934 +106,16 @@ RestyleManager::RestyleManager(nsPresCon
 }
 
 void
 RestyleManager::NotifyDestroyingFrame(nsIFrame* aFrame)
 {
   mOverflowChangedTracker.RemoveFrame(aFrame);
 }
 
-#ifdef DEBUG
-  // To ensure that the functions below are only called within
-  // |ApplyRenderingChangeToTree|.
-static bool gInApplyRenderingChangeToTree = false;
-#endif
-
-static inline nsIFrame*
-GetNextBlockInInlineSibling(FramePropertyTable* aPropTable, nsIFrame* aFrame)
-{
-  NS_ASSERTION(!aFrame->GetPrevContinuation(),
-               "must start with the first continuation");
-  // Might we have ib-split siblings?
-  if (!(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
-    // nothing more to do here
-    return nullptr;
-  }
-
-  return static_cast<nsIFrame*>
-    (aPropTable->Get(aFrame, nsIFrame::IBSplitSibling()));
-}
-
-static nsIFrame*
-GetNearestAncestorFrame(nsIContent* aContent)
-{
-  nsIFrame* ancestorFrame = nullptr;
-  for (nsIContent* ancestor = aContent->GetParent();
-       ancestor && !ancestorFrame;
-       ancestor = ancestor->GetParent()) {
-    ancestorFrame = ancestor->GetPrimaryFrame();
-  }
-  return ancestorFrame;
-}
-
-static void
-DoApplyRenderingChangeToTree(nsIFrame* aFrame,
-                             nsChangeHint aChange);
-
-/**
- * Sync views on aFrame and all of aFrame's descendants (following placeholders),
- * if aChange has nsChangeHint_SyncFrameView.
- * Calls DoApplyRenderingChangeToTree on all aFrame's out-of-flow descendants
- * (following placeholders), if aChange has nsChangeHint_RepaintFrame.
- * aFrame should be some combination of nsChangeHint_SyncFrameView,
- * nsChangeHint_RepaintFrame, nsChangeHint_UpdateOpacityLayer and
- * nsChangeHint_SchedulePaint, nothing else.
-*/
-static void
-SyncViewsAndInvalidateDescendants(nsIFrame* aFrame,
-                                  nsChangeHint aChange)
-{
-  NS_PRECONDITION(gInApplyRenderingChangeToTree,
-                  "should only be called within ApplyRenderingChangeToTree");
-  NS_ASSERTION(nsChangeHint_size_t(aChange) ==
-                          (aChange & (nsChangeHint_RepaintFrame |
-                                      nsChangeHint_SyncFrameView |
-                                      nsChangeHint_UpdateOpacityLayer |
-                                      nsChangeHint_SchedulePaint)),
-               "Invalid change flag");
-
-  nsView* view = aFrame->GetView();
-  if (view) {
-    if (aChange & nsChangeHint_SyncFrameView) {
-      nsContainerFrame::SyncFrameViewProperties(aFrame->PresContext(),
-                                                aFrame, nullptr, view);
-    }
-  }
-
-  nsIFrame::ChildListIterator lists(aFrame);
-  for (; !lists.IsDone(); lists.Next()) {
-    for (nsIFrame* child : lists.CurrentList()) {
-      if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
-        // only do frames that don't have placeholders
-        if (nsGkAtoms::placeholderFrame == child->GetType()) {
-          // do the out-of-flow frame and its continuations
-          nsIFrame* outOfFlowFrame =
-            nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
-          DoApplyRenderingChangeToTree(outOfFlowFrame, aChange);
-        } else if (lists.CurrentID() == nsIFrame::kPopupList) {
-          DoApplyRenderingChangeToTree(child, aChange);
-        } else {  // regular frame
-          SyncViewsAndInvalidateDescendants(child, aChange);
-        }
-      }
-    }
-  }
-}
-
-/**
- * To handle nsChangeHint_ChildrenOnlyTransform we must iterate over the child
- * frames of the SVG frame concerned. This helper function is used to find that
- * SVG frame when we encounter nsChangeHint_ChildrenOnlyTransform to ensure
- * that we iterate over the intended children, since sometimes we end up
- * handling that hint while processing hints for one of the SVG frame's
- * ancestor frames.
- *
- * The reason that we sometimes end up trying to process the hint for an
- * ancestor of the SVG frame that the hint is intended for is due to the way we
- * process restyle events. ApplyRenderingChangeToTree adjusts the frame from
- * the restyled element's principle frame to one of its ancestor frames based
- * on what nsCSSRendering::FindBackground returns, since the background style
- * may have been propagated up to an ancestor frame. Processing hints using an
- * ancestor frame is fine in general, but nsChangeHint_ChildrenOnlyTransform is
- * a special case since it is intended to update the children of a specific
- * frame.
- */
-static nsIFrame*
-GetFrameForChildrenOnlyTransformHint(nsIFrame* aFrame)
-{
-  if (aFrame->GetType() == nsGkAtoms::viewportFrame) {
-    // This happens if the root-<svg> is fixed positioned, in which case we
-    // can't use aFrame->GetContent() to find the primary frame, since
-    // GetContent() returns nullptr for ViewportFrame.
-    aFrame = aFrame->PrincipalChildList().FirstChild();
-  }
-  // For an nsHTMLScrollFrame, this will get the SVG frame that has the
-  // children-only transforms:
-  aFrame = aFrame->GetContent()->GetPrimaryFrame();
-  if (aFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) {
-    aFrame = aFrame->PrincipalChildList().FirstChild();
-    MOZ_ASSERT(aFrame->GetType() == nsGkAtoms::svgOuterSVGAnonChildFrame,
-               "Where is the nsSVGOuterSVGFrame's anon child??");
-  }
-  MOZ_ASSERT(aFrame->IsFrameOfType(nsIFrame::eSVG |
-                                   nsIFrame::eSVGContainer),
-             "Children-only transforms only expected on SVG frames");
-  return aFrame;
-}
-
-static void
-DoApplyRenderingChangeToTree(nsIFrame* aFrame,
-                             nsChangeHint aChange)
-{
-  NS_PRECONDITION(gInApplyRenderingChangeToTree,
-                  "should only be called within ApplyRenderingChangeToTree");
-
-  for ( ; aFrame; aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame)) {
-    // Invalidate and sync views on all descendant frames, following placeholders.
-    // We don't need to update transforms in SyncViewsAndInvalidateDescendants, because
-    // there can't be any out-of-flows or popups that need to be transformed;
-    // all out-of-flow descendants of the transformed element must also be
-    // descendants of the transformed frame.
-    SyncViewsAndInvalidateDescendants(aFrame,
-      nsChangeHint(aChange & (nsChangeHint_RepaintFrame |
-                              nsChangeHint_SyncFrameView |
-                              nsChangeHint_UpdateOpacityLayer |
-                              nsChangeHint_SchedulePaint)));
-    // This must be set to true if the rendering change needs to
-    // invalidate content.  If it's false, a composite-only paint
-    // (empty transaction) will be scheduled.
-    bool needInvalidatingPaint = false;
-
-    // if frame has view, will already be invalidated
-    if (aChange & nsChangeHint_RepaintFrame) {
-      // Note that this whole block will be skipped when painting is suppressed
-      // (due to our caller ApplyRendingChangeToTree() discarding the
-      // nsChangeHint_RepaintFrame hint).  If you add handling for any other
-      // hints within this block, be sure that they too should be ignored when
-      // painting is suppressed.
-      needInvalidatingPaint = true;
-      aFrame->InvalidateFrameSubtree();
-      if ((aChange & nsChangeHint_UpdateEffects) &&
-          aFrame->IsFrameOfType(nsIFrame::eSVG) &&
-          !(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
-        // Need to update our overflow rects:
-        nsSVGUtils::ScheduleReflowSVG(aFrame);
-      }
-    }
-    if (aChange & nsChangeHint_UpdateTextPath) {
-      if (aFrame->IsSVGText()) {
-        // Invalidate and reflow the entire SVGTextFrame:
-        NS_ASSERTION(aFrame->GetContent()->IsSVGElement(nsGkAtoms::textPath),
-                     "expected frame for a <textPath> element");
-        nsIFrame* text = nsLayoutUtils::GetClosestFrameOfType(
-                                                      aFrame,
-                                                      nsGkAtoms::svgTextFrame);
-        NS_ASSERTION(text, "expected to find an ancestor SVGTextFrame");
-        static_cast<SVGTextFrame*>(text)->NotifyGlyphMetricsChange();
-      } else {
-        MOZ_ASSERT(false, "unexpected frame got nsChangeHint_UpdateTextPath");
-      }
-    }
-    if (aChange & nsChangeHint_UpdateOpacityLayer) {
-      // FIXME/bug 796697: we can get away with empty transactions for
-      // opacity updates in many cases.
-      needInvalidatingPaint = true;
-
-      ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_opacity);
-      if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
-        // SVG effects paints the opacity without using
-        // nsDisplayOpacity. We need to invalidate manually.
-        aFrame->InvalidateFrameSubtree();
-      }
-    }
-    if ((aChange & nsChangeHint_UpdateTransformLayer) &&
-        aFrame->IsTransformed()) {
-      ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_transform);
-      // If we're not already going to do an invalidating paint, see
-      // if we can get away with only updating the transform on a
-      // layer for this frame, and not scheduling an invalidating
-      // paint.
-      if (!needInvalidatingPaint) {
-        Layer* layer;
-        needInvalidatingPaint |= !aFrame->TryUpdateTransformOnly(&layer);
-
-        if (!needInvalidatingPaint) {
-          // Since we're not going to paint, we need to resend animation
-          // data to the layer.
-          MOZ_ASSERT(layer, "this can't happen if there's no layer");
-          nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(layer,
-            nullptr, nullptr, aFrame, eCSSProperty_transform);
-        }
-      }
-    }
-    if (aChange & nsChangeHint_ChildrenOnlyTransform) {
-      needInvalidatingPaint = true;
-      nsIFrame* childFrame =
-        GetFrameForChildrenOnlyTransformHint(aFrame)->PrincipalChildList().FirstChild();
-      for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
-        ActiveLayerTracker::NotifyRestyle(childFrame, eCSSProperty_transform);
-      }
-    }
-    if (aChange & nsChangeHint_SchedulePaint) {
-      needInvalidatingPaint = true;
-    }
-    aFrame->SchedulePaint(needInvalidatingPaint ?
-                          nsIFrame::PAINT_DEFAULT :
-                          nsIFrame::PAINT_COMPOSITE_ONLY);
-  }
-}
-
-static void
-ApplyRenderingChangeToTree(nsPresContext* aPresContext,
-                           nsIFrame* aFrame,
-                           nsChangeHint aChange)
-{
-  // We check StyleDisplay()->HasTransformStyle() in addition to checking
-  // IsTransformed() since we can get here for some frames that don't support
-  // CSS transforms.
-  NS_ASSERTION(!(aChange & nsChangeHint_UpdateTransformLayer) ||
-               aFrame->IsTransformed() ||
-               aFrame->StyleDisplay()->HasTransformStyle(),
-               "Unexpected UpdateTransformLayer hint");
-
-  nsIPresShell* shell = aPresContext->PresShell();
-  if (shell->IsPaintingSuppressed()) {
-    // Don't allow synchronous rendering changes when painting is turned off.
-    aChange &= ~nsChangeHint_RepaintFrame;
-    if (!aChange) {
-      return;
-    }
-  }
-
-  // Trigger rendering updates by damaging this frame and any
-  // continuations of this frame.
-#ifdef DEBUG
-  gInApplyRenderingChangeToTree = true;
-#endif
-  if (aChange & nsChangeHint_RepaintFrame) {
-    // If the frame's background is propagated to an ancestor, walk up to
-    // that ancestor and apply the RepaintFrame change hint to it.
-    nsStyleContext* bgSC;
-    nsIFrame* propagatedFrame = aFrame;
-    while (!nsCSSRendering::FindBackground(propagatedFrame, &bgSC)) {
-      propagatedFrame = propagatedFrame->GetParent();
-      NS_ASSERTION(aFrame, "root frame must paint");
-    }
-
-    if (propagatedFrame != aFrame) {
-      DoApplyRenderingChangeToTree(propagatedFrame, nsChangeHint_RepaintFrame);
-      aChange &= ~nsChangeHint_RepaintFrame;
-      if (!aChange) {
-        return;
-      }
-    }
-  }
-  DoApplyRenderingChangeToTree(aFrame, aChange);
-#ifdef DEBUG
-  gInApplyRenderingChangeToTree = false;
-#endif
-}
-
-bool
-RestyleManager::RecomputePosition(nsIFrame* aFrame)
-{
-  // Don't process position changes on table frames, since we already handle
-  // the dynamic position change on the table wrapper frame, and the
-  // reflow-based fallback code path also ignores positions on inner table
-  // frames.
-  if (aFrame->GetType() == nsGkAtoms::tableFrame) {
-    return true;
-  }
-
-  const nsStyleDisplay* display = aFrame->StyleDisplay();
-  // Changes to the offsets of a non-positioned element can safely be ignored.
-  if (display->mPosition == NS_STYLE_POSITION_STATIC) {
-    return true;
-  }
-
-  // Don't process position changes on frames which have views or the ones which
-  // have a view somewhere in their descendants, because the corresponding view
-  // needs to be repositioned properly as well.
-  if (aFrame->HasView() ||
-      (aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
-    StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
-    return false;
-  }
-
-  aFrame->SchedulePaint();
-
-  // For relative positioning, we can simply update the frame rect
-  if (display->IsRelativelyPositionedStyle()) {
-    // Move the frame
-    if (display->mPosition == NS_STYLE_POSITION_STICKY) {
-      if (display->IsInnerTableStyle()) {
-        // We don't currently support sticky positioning of inner table
-        // elements (bug 975644). Bail.
-        //
-        // When this is fixed, remove the null-check for the computed
-        // offsets in nsTableRowFrame::ReflowChildren.
-        return true;
-      }
-
-      // Update sticky positioning for an entire element at once, starting with
-      // the first continuation or ib-split sibling.
-      // It's rare that the frame we already have isn't already the first
-      // continuation or ib-split sibling, but it can happen when styles differ
-      // across continuations such as ::first-line or ::first-letter, and in
-      // those cases we will generally (but maybe not always) do the work twice.
-      nsIFrame* firstContinuation =
-        nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
-
-      StickyScrollContainer::ComputeStickyOffsets(firstContinuation);
-      StickyScrollContainer* ssc =
-        StickyScrollContainer::GetStickyScrollContainerForFrame(firstContinuation);
-      if (ssc) {
-        ssc->PositionContinuations(firstContinuation);
-      }
-    } else {
-      MOZ_ASSERT(NS_STYLE_POSITION_RELATIVE == display->mPosition,
-                 "Unexpected type of positioning");
-      for (nsIFrame* cont = aFrame; cont;
-           cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
-        nsIFrame* cb = cont->GetContainingBlock();
-        nsMargin newOffsets;
-        WritingMode wm = cb->GetWritingMode();
-        const LogicalSize size(wm, cb->GetContentRectRelativeToSelf().Size());
-
-        ReflowInput::ComputeRelativeOffsets(wm, cont, size, newOffsets);
-        NS_ASSERTION(newOffsets.left == -newOffsets.right &&
-                     newOffsets.top == -newOffsets.bottom,
-                     "ComputeRelativeOffsets should return valid results");
-
-        // ReflowInput::ApplyRelativePositioning would work here, but
-        // since we've already checked mPosition and aren't changing the frame's
-        // normal position, go ahead and add the offsets directly.
-        cont->SetPosition(cont->GetNormalPosition() +
-                          nsPoint(newOffsets.left, newOffsets.top));
-      }
-    }
-
-    return true;
-  }
-
-  // For the absolute positioning case, set up a fake HTML reflow state for
-  // the frame, and then get the offsets and size from it. If the frame's size
-  // doesn't need to change, we can simply update the frame position. Otherwise
-  // we fall back to a reflow.
-  nsRenderingContext rc(
-    aFrame->PresContext()->PresShell()->CreateReferenceRenderingContext());
-
-  // Construct a bogus parent reflow state so that there's a usable
-  // containing block reflow state.
-  nsIFrame* parentFrame = aFrame->GetParent();
-  WritingMode parentWM = parentFrame->GetWritingMode();
-  WritingMode frameWM = aFrame->GetWritingMode();
-  LogicalSize parentSize = parentFrame->GetLogicalSize();
-
-  nsFrameState savedState = parentFrame->GetStateBits();
-  ReflowInput parentReflowInput(aFrame->PresContext(), parentFrame,
-                                      &rc, parentSize);
-  parentFrame->RemoveStateBits(~nsFrameState(0));
-  parentFrame->AddStateBits(savedState);
-
-  // The bogus parent state here was created with no parent state of its own,
-  // and therefore it won't have an mCBReflowInput set up.
-  // But we may need one (for InitCBReflowInput in a child state), so let's
-  // try to create one here for the cases where it will be needed.
-  Maybe<ReflowInput> cbReflowInput;
-  nsIFrame* cbFrame = parentFrame->GetContainingBlock();
-  if (cbFrame && (aFrame->GetContainingBlock() != parentFrame ||
-                  parentFrame->GetType() == nsGkAtoms::tableFrame)) {
-    LogicalSize cbSize = cbFrame->GetLogicalSize();
-    cbReflowInput.emplace(cbFrame->PresContext(), cbFrame, &rc, cbSize);
-    cbReflowInput->ComputedPhysicalMargin() = cbFrame->GetUsedMargin();
-    cbReflowInput->ComputedPhysicalPadding() = cbFrame->GetUsedPadding();
-    cbReflowInput->ComputedPhysicalBorderPadding() =
-      cbFrame->GetUsedBorderAndPadding();
-    parentReflowInput.mCBReflowInput = cbReflowInput.ptr();
-  }
-
-  NS_WARN_IF_FALSE(parentSize.ISize(parentWM) != NS_INTRINSICSIZE &&
-                   parentSize.BSize(parentWM) != NS_INTRINSICSIZE,
-                   "parentSize should be valid");
-  parentReflowInput.SetComputedISize(std::max(parentSize.ISize(parentWM), 0));
-  parentReflowInput.SetComputedBSize(std::max(parentSize.BSize(parentWM), 0));
-  parentReflowInput.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
-
-  parentReflowInput.ComputedPhysicalPadding() = parentFrame->GetUsedPadding();
-  parentReflowInput.ComputedPhysicalBorderPadding() =
-    parentFrame->GetUsedBorderAndPadding();
-  LogicalSize availSize = parentSize.ConvertTo(frameWM, parentWM);
-  availSize.BSize(frameWM) = NS_INTRINSICSIZE;
-
-  ViewportFrame* viewport = do_QueryFrame(parentFrame);
-  nsSize cbSize = viewport ?
-    viewport->AdjustReflowInputAsContainingBlock(&parentReflowInput).Size()
-    : aFrame->GetContainingBlock()->GetSize();
-  const nsMargin& parentBorder =
-    parentReflowInput.mStyleBorder->GetComputedBorder();
-  cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom());
-  LogicalSize lcbSize(frameWM, cbSize);
-  ReflowInput reflowInput(aFrame->PresContext(), parentReflowInput,
-                                aFrame, availSize, &lcbSize);
-  nsSize computedSize(reflowInput.ComputedWidth(), reflowInput.ComputedHeight());
-  computedSize.width += reflowInput.ComputedPhysicalBorderPadding().LeftRight();
-  if (computedSize.height != NS_INTRINSICSIZE) {
-    computedSize.height += reflowInput.ComputedPhysicalBorderPadding().TopBottom();
-  }
-  nsSize size = aFrame->GetSize();
-  // The RecomputePosition hint is not used if any offset changed between auto
-  // and non-auto. If computedSize.height == NS_INTRINSICSIZE then the new
-  // element height will be its intrinsic height, and since 'top' and 'bottom''s
-  // auto-ness hasn't changed, the old height must also be its intrinsic
-  // height, which we can assume hasn't changed (or reflow would have
-  // been triggered).
-  if (computedSize.width == size.width &&
-      (computedSize.height == NS_INTRINSICSIZE || computedSize.height == size.height)) {
-    // If we're solving for 'left' or 'top', then compute it here, in order to
-    // match the reflow code path.
-    if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().left) {
-      reflowInput.ComputedPhysicalOffsets().left = cbSize.width -
-                                          reflowInput.ComputedPhysicalOffsets().right -
-                                          reflowInput.ComputedPhysicalMargin().right -
-                                          size.width -
-                                          reflowInput.ComputedPhysicalMargin().left;
-    }
-
-    if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().top) {
-      reflowInput.ComputedPhysicalOffsets().top = cbSize.height -
-                                         reflowInput.ComputedPhysicalOffsets().bottom -
-                                         reflowInput.ComputedPhysicalMargin().bottom -
-                                         size.height -
-                                         reflowInput.ComputedPhysicalMargin().top;
-    }
-
-    // Move the frame
-    nsPoint pos(parentBorder.left + reflowInput.ComputedPhysicalOffsets().left +
-                reflowInput.ComputedPhysicalMargin().left,
-                parentBorder.top + reflowInput.ComputedPhysicalOffsets().top +
-                reflowInput.ComputedPhysicalMargin().top);
-    aFrame->SetPosition(pos);
-
-    return true;
-  }
-
-  // Fall back to a reflow
-  StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
-  return false;
-}
-
-static bool
-HasBoxAncestor(nsIFrame* aFrame)
-{
-  for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
-    if (f->IsXULBoxFrame()) {
-      return true;
-    }
-  }
-  return false;
-}
-
-void
-RestyleManager::StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint)
-{
-  nsIPresShell::IntrinsicDirty dirtyType;
-  if (aHint & nsChangeHint_ClearDescendantIntrinsics) {
-    NS_ASSERTION(aHint & nsChangeHint_ClearAncestorIntrinsics,
-                 "Please read the comments in nsChangeHint.h");
-    NS_ASSERTION(aHint & nsChangeHint_NeedDirtyReflow,
-                 "ClearDescendantIntrinsics requires NeedDirtyReflow");
-    dirtyType = nsIPresShell::eStyleChange;
-  } else if ((aHint & nsChangeHint_UpdateComputedBSize) &&
-             aFrame->HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
-    dirtyType = nsIPresShell::eStyleChange;
-  } else if (aHint & nsChangeHint_ClearAncestorIntrinsics) {
-    dirtyType = nsIPresShell::eTreeChange;
-  } else if ((aHint & nsChangeHint_UpdateComputedBSize) &&
-             HasBoxAncestor(aFrame)) {
-    // The frame's computed BSize is changing, and we have a box ancestor
-    // whose cached intrinsic height may need to be updated.
-    dirtyType = nsIPresShell::eTreeChange;
-  } else {
-    dirtyType = nsIPresShell::eResize;
-  }
-
-  nsFrameState dirtyBits;
-  if (aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
-    dirtyBits = nsFrameState(0);
-  } else if ((aHint & nsChangeHint_NeedDirtyReflow) ||
-             dirtyType == nsIPresShell::eStyleChange) {
-    dirtyBits = NS_FRAME_IS_DIRTY;
-  } else {
-    dirtyBits = NS_FRAME_HAS_DIRTY_CHILDREN;
-  }
-
-  // If we're not going to clear any intrinsic sizes on the frames, and
-  // there are no dirty bits to set, then there's nothing to do.
-  if (dirtyType == nsIPresShell::eResize && !dirtyBits)
-    return;
-
-  nsIPresShell::ReflowRootHandling rootHandling;
-  if (aHint & nsChangeHint_ReflowChangesSizeOrPosition) {
-    rootHandling = nsIPresShell::ePositionOrSizeChange;
-  } else {
-    rootHandling = nsIPresShell::eNoPositionOrSizeChange;
-  }
-
-  do {
-    PresContext()->PresShell()->FrameNeedsReflow(aFrame, dirtyType, dirtyBits,
-                                                rootHandling);
-    aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame);
-  } while (aFrame);
-}
-
-void
-RestyleManager::AddSubtreeToOverflowTracker(nsIFrame* aFrame)
-{
-  if (aFrame->FrameMaintainsOverflow()) {
-    mOverflowChangedTracker.AddFrame(aFrame,
-                                     OverflowChangedTracker::CHILDREN_CHANGED);
-  }
-  nsIFrame::ChildListIterator lists(aFrame);
-  for (; !lists.IsDone(); lists.Next()) {
-    for (nsIFrame* child : lists.CurrentList()) {
-      AddSubtreeToOverflowTracker(child);
-    }
-  }
-}
-
-NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ChangeListProperty, bool)
-
-/**
- * Return true if aFrame's subtree has placeholders for out-of-flow content
- * whose 'position' style's bit in aPositionMask is set.
- */
-static bool
-FrameHasPositionedPlaceholderDescendants(nsIFrame* aFrame, uint32_t aPositionMask)
-{
-  const nsIFrame::ChildListIDs skip(nsIFrame::kAbsoluteList |
-                                    nsIFrame::kFixedList);
-  for (nsIFrame::ChildListIterator lists(aFrame); !lists.IsDone(); lists.Next()) {
-    if (!skip.Contains(lists.CurrentID())) {
-      for (nsIFrame* f : lists.CurrentList()) {
-        if (f->GetType() == nsGkAtoms::placeholderFrame) {
-          nsIFrame* outOfFlow = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
-          // If SVG text frames could appear here, they could confuse us since
-          // they ignore their position style ... but they can't.
-          NS_ASSERTION(!outOfFlow->IsSVGText(),
-                       "SVG text frames can't be out of flow");
-          if (aPositionMask & (1 << outOfFlow->StyleDisplay()->mPosition)) {
-            return true;
-          }
-        }
-        if (FrameHasPositionedPlaceholderDescendants(f, aPositionMask)) {
-          return true;
-        }
-      }
-    }
-  }
-  return false;
-}
-
-static bool
-NeedToReframeForAddingOrRemovingTransform(nsIFrame* aFrame)
-{
-  static_assert(0 <= NS_STYLE_POSITION_ABSOLUTE &&
-                NS_STYLE_POSITION_ABSOLUTE < 32, "Style constant out of range");
-  static_assert(0 <= NS_STYLE_POSITION_FIXED &&
-                NS_STYLE_POSITION_FIXED < 32, "Style constant out of range");
-
-  uint32_t positionMask;
-  // Don't call aFrame->IsPositioned here, since that returns true if
-  // the frame already has a transform, and we want to ignore that here
-  if (aFrame->IsAbsolutelyPositioned() ||
-      aFrame->IsRelativelyPositioned()) {
-    // This frame is a container for abs-pos descendants whether or not it
-    // has a transform.
-    // So abs-pos descendants are no problem; we only need to reframe if
-    // we have fixed-pos descendants.
-    positionMask = 1 << NS_STYLE_POSITION_FIXED;
-  } else {
-    // This frame may not be a container for abs-pos descendants already.
-    // So reframe if we have abs-pos or fixed-pos descendants.
-    positionMask = (1 << NS_STYLE_POSITION_FIXED) |
-        (1 << NS_STYLE_POSITION_ABSOLUTE);
-  }
-  for (nsIFrame* f = aFrame; f;
-       f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
-    if (FrameHasPositionedPlaceholderDescendants(f, positionMask)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-nsresult
-RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
-{
-  NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
-               "Someone forgot a script blocker");
-  int32_t count = aChangeList.Count();
-  if (!count)
-    return NS_OK;
-
-  PROFILER_LABEL("RestyleManager", "ProcessRestyledFrames",
-    js::ProfileEntry::Category::CSS);
-
-  // Make sure to not rebuild quote or counter lists while we're
-  // processing restyles
-  FrameConstructor()->BeginUpdate();
-
-  FramePropertyTable* propTable = PresContext()->PropertyTable();
-
-  // Mark frames so that we skip frames that die along the way, bug 123049.
-  // A frame can be in the list multiple times with different hints. Further
-  // optmization is possible if nsStyleChangeList::AppendChange could coalesce
-  int32_t index = count;
-
-  while (0 <= --index) {
-    const nsStyleChangeData* changeData;
-    aChangeList.ChangeAt(index, &changeData);
-    if (changeData->mFrame) {
-      propTable->Set(changeData->mFrame, ChangeListProperty(), true);
-    }
-  }
-
-  index = count;
-
-  bool didUpdateCursor = false;
-
-  while (0 <= --index) {
-    nsIFrame* frame;
-    nsIContent* content;
-    bool didReflowThisFrame = false;
-    nsChangeHint hint;
-    aChangeList.ChangeAt(index, frame, content, hint);
-
-    NS_ASSERTION(!(hint & nsChangeHint_AllReflowHints) ||
-                 (hint & nsChangeHint_NeedReflow),
-                 "Reflow hint bits set without actually asking for a reflow");
-
-    // skip any frame that has been destroyed due to a ripple effect
-    if (frame && !propTable->Get(frame, ChangeListProperty())) {
-      continue;
-    }
-
-    if (frame && frame->GetContent() != content) {
-      // XXXbz this is due to image maps messing with the primary frame of
-      // <area>s.  See bug 135040.  Remove this block once that's fixed.
-      frame = nullptr;
-      if (!(hint & nsChangeHint_ReconstructFrame)) {
-        continue;
-      }
-    }
-
-    if ((hint & nsChangeHint_UpdateContainingBlock) && frame &&
-        !(hint & nsChangeHint_ReconstructFrame)) {
-      if (NeedToReframeForAddingOrRemovingTransform(frame) ||
-          frame->GetType() == nsGkAtoms::fieldSetFrame ||
-          frame->GetContentInsertionFrame() != frame) {
-        // The frame has positioned children that need to be reparented, or
-        // it can't easily be converted to/from being an abs-pos container correctly.
-        hint |= nsChangeHint_ReconstructFrame;
-      } else {
-        for (nsIFrame* cont = frame; cont;
-             cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
-          // Normally frame construction would set state bits as needed,
-          // but we're not going to reconstruct the frame so we need to set them.
-          // It's because we need to set this state on each affected frame
-          // that we can't coalesce nsChangeHint_UpdateContainingBlock hints up
-          // to ancestors (i.e. it can't be an inherited change hint).
-          if (cont->IsAbsPosContaininingBlock()) {
-            if (cont->StyleDisplay()->HasTransform(cont)) {
-              cont->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
-            }
-            if (!cont->IsAbsoluteContainer() &&
-                (cont->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
-              cont->MarkAsAbsoluteContainingBlock();
-            }
-          } else {
-            // Don't remove NS_FRAME_MAY_BE_TRANSFORMED since it may still by
-            // transformed by other means. It's OK to have the bit even if it's
-            // not needed.
-            if (cont->IsAbsoluteContainer()) {
-              cont->MarkAsNotAbsoluteContainingBlock();
-            }
-          }
-        }
-      }
-    }
-    if (hint & nsChangeHint_ReconstructFrame) {
-      // If we ever start passing true here, be careful of restyles
-      // that involve a reframe and animations.  In particular, if the
-      // restyle we're processing here is an animation restyle, but
-      // the style resolution we will do for the frame construction
-      // happens async when we're not in an animation restyle already,
-      // problems could arise.
-      // We could also have problems with triggering of CSS transitions
-      // on elements whose frames are reconstructed, since we depend on
-      // the reconstruction happening synchronously.
-      FrameConstructor()->RecreateFramesForContent(content, false,
-        nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION, nullptr);
-    } else {
-      NS_ASSERTION(frame, "This shouldn't happen");
-
-      if (!frame->FrameMaintainsOverflow()) {
-        // frame does not maintain overflow rects, so avoid calling
-        // FinishAndStoreOverflow on it:
-        hint &= ~(nsChangeHint_UpdateOverflow |
-                  nsChangeHint_ChildrenOnlyTransform |
-                  nsChangeHint_UpdatePostTransformOverflow |
-                  nsChangeHint_UpdateParentOverflow);
-      }
-
-      if (!(frame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED)) {
-        // Frame can not be transformed, and thus a change in transform will
-        // have no effect and we should not use the
-        // nsChangeHint_UpdatePostTransformOverflow hint.
-        hint &= ~nsChangeHint_UpdatePostTransformOverflow;
-      }
-
-      if (hint & nsChangeHint_UpdateEffects) {
-        for (nsIFrame* cont = frame; cont;
-             cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
-          nsSVGEffects::UpdateEffects(cont);
-        }
-      }
-      if ((hint & nsChangeHint_InvalidateRenderingObservers) ||
-          ((hint & nsChangeHint_UpdateOpacityLayer) &&
-           frame->IsFrameOfType(nsIFrame::eSVG) &&
-           !(frame->GetStateBits() & NS_STATE_IS_OUTER_SVG))) {
-        nsSVGEffects::InvalidateRenderingObservers(frame);
-      }
-      if (hint & nsChangeHint_NeedReflow) {
-        StyleChangeReflow(frame, hint);
-        didReflowThisFrame = true;
-      }
-
-      if ((hint & nsChangeHint_UpdateUsesOpacity) &&
-          frame->IsFrameOfType(nsIFrame::eTablePart)) {
-        NS_ASSERTION(hint & nsChangeHint_UpdateOpacityLayer,
-                     "should only return UpdateUsesOpacity hint "
-                     "when also returning UpdateOpacityLayer hint");
-        // When an internal table part (including cells) changes between
-        // having opacity 1 and non-1, it changes whether its
-        // backgrounds (and those of table parts inside of it) are
-        // painted as part of the table's nsDisplayTableBorderBackground
-        // display item, or part of its own display item.  That requires
-        // invalidation, so change UpdateOpacityLayer to RepaintFrame.
-        hint &= ~nsChangeHint_UpdateOpacityLayer;
-        hint |= nsChangeHint_RepaintFrame;
-      }
-
-      if (hint & nsChangeHint_UpdateBackgroundPosition) {
-        // For most frame types, DLBI can detect background position changes,
-        // so we only need to schedule a paint.
-        hint |= nsChangeHint_SchedulePaint;
-        if (frame->IsFrameOfType(nsIFrame::eTablePart) ||
-            frame->IsFrameOfType(nsIFrame::eMathML)) {
-          // Table parts and MathML frames don't build display items for their
-          // backgrounds, so DLBI can't detect background-position changes for
-          // these frames. Repaint the whole frame.
-          hint |= nsChangeHint_RepaintFrame;
-        }
-      }
-
-      if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView |
-                  nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer |
-                  nsChangeHint_ChildrenOnlyTransform | nsChangeHint_SchedulePaint)) {
-        ApplyRenderingChangeToTree(PresContext(), frame, hint);
-      }
-      if ((hint & nsChangeHint_RecomputePosition) && !didReflowThisFrame) {
-        ActiveLayerTracker::NotifyOffsetRestyle(frame);
-        // It is possible for this to fall back to a reflow
-        if (!RecomputePosition(frame)) {
-          didReflowThisFrame = true;
-        }
-      }
-      NS_ASSERTION(!(hint & nsChangeHint_ChildrenOnlyTransform) ||
-                   (hint & nsChangeHint_UpdateOverflow),
-                   "nsChangeHint_UpdateOverflow should be passed too");
-      if (!didReflowThisFrame &&
-          (hint & (nsChangeHint_UpdateOverflow |
-                   nsChangeHint_UpdatePostTransformOverflow |
-                   nsChangeHint_UpdateParentOverflow |
-                   nsChangeHint_UpdateSubtreeOverflow))) {
-        if (hint & nsChangeHint_UpdateSubtreeOverflow) {
-          for (nsIFrame* cont = frame; cont; cont =
-                 nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
-            AddSubtreeToOverflowTracker(cont);
-          }
-          // The work we just did in AddSubtreeToOverflowTracker
-          // subsumes some of the other hints:
-          hint &= ~(nsChangeHint_UpdateOverflow |
-                    nsChangeHint_UpdatePostTransformOverflow);
-        }
-        if (hint & nsChangeHint_ChildrenOnlyTransform) {
-          // The overflow areas of the child frames need to be updated:
-          nsIFrame* hintFrame = GetFrameForChildrenOnlyTransformHint(frame);
-          nsIFrame* childFrame = hintFrame->PrincipalChildList().FirstChild();
-          NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame),
-                       "SVG frames should not have continuations "
-                       "or ib-split siblings");
-          NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(hintFrame),
-                       "SVG frames should not have continuations "
-                       "or ib-split siblings");
-          for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
-            MOZ_ASSERT(childFrame->IsFrameOfType(nsIFrame::eSVG),
-                       "Not expecting non-SVG children");
-            // If |childFrame| is dirty or has dirty children, we don't bother
-            // updating overflows since that will happen when it's reflowed.
-            if (!(childFrame->GetStateBits() &
-                  (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
-              mOverflowChangedTracker.AddFrame(childFrame,
-                           OverflowChangedTracker::CHILDREN_CHANGED);
-            }
-            NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(childFrame),
-                         "SVG frames should not have continuations "
-                         "or ib-split siblings");
-            NS_ASSERTION(childFrame->GetParent() == hintFrame,
-                         "SVG child frame not expected to have different parent");
-          }
-        }
-        // If |frame| is dirty or has dirty children, we don't bother updating
-        // overflows since that will happen when it's reflowed.
-        if (!(frame->GetStateBits() &
-              (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
-          if (hint & (nsChangeHint_UpdateOverflow |
-                      nsChangeHint_UpdatePostTransformOverflow)) {
-            OverflowChangedTracker::ChangeKind changeKind;
-            // If we have both nsChangeHint_UpdateOverflow and
-            // nsChangeHint_UpdatePostTransformOverflow,
-            // CHILDREN_CHANGED is selected as it is
-            // strictly stronger.
-            if (hint & nsChangeHint_UpdateOverflow) {
-              changeKind = OverflowChangedTracker::CHILDREN_CHANGED;
-            } else {
-              changeKind = OverflowChangedTracker::TRANSFORM_CHANGED;
-            }
-            for (nsIFrame* cont = frame; cont; cont =
-                   nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
-              mOverflowChangedTracker.AddFrame(cont, changeKind);
-            }
-          }
-          // UpdateParentOverflow hints need to be processed in addition
-          // to the above, since if the processing of the above hints
-          // yields no change, the update will not propagate to the
-          // parent.
-          if (hint & nsChangeHint_UpdateParentOverflow) {
-            MOZ_ASSERT(frame->GetParent(),
-                       "shouldn't get style hints for the root frame");
-            for (nsIFrame* cont = frame; cont; cont =
-                   nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
-              mOverflowChangedTracker.AddFrame(cont->GetParent(),
-                                   OverflowChangedTracker::CHILDREN_CHANGED);
-            }
-          }
-        }
-      }
-      if ((hint & nsChangeHint_UpdateCursor) && !didUpdateCursor) {
-        PresContext()->PresShell()->SynthesizeMouseMove(false);
-        didUpdateCursor = true;
-      }
-    }
-  }
-
-  FrameConstructor()->EndUpdate();
-
-  // cleanup references and verify the style tree.  Note that the latter needs
-  // to happen once we've processed the whole list, since until then the tree
-  // is not in fact in a consistent state.
-  index = count;
-  while (0 <= --index) {
-    const nsStyleChangeData* changeData;
-    aChangeList.ChangeAt(index, &changeData);
-    if (changeData->mFrame) {
-      propTable->Delete(changeData->mFrame, ChangeListProperty());
-    }
-
-#ifdef DEBUG
-    // reget frame from content since it may have been regenerated...
-    if (changeData->mContent) {
-      nsIFrame* frame = changeData->mContent->GetPrimaryFrame();
-      if (frame) {
-        DebugVerifyStyleTree(frame);
-      }
-    } else if (!changeData->mFrame ||
-               changeData->mFrame->GetType() != nsGkAtoms::viewportFrame) {
-      NS_WARNING("Unable to test style tree integrity -- no content node "
-                 "(and not a viewport frame)");
-    }
-#endif
-  }
-
-  aChangeList.Clear();
-  return NS_OK;
-}
-
 void
 RestyleManager::RestyleElement(Element*               aElement,
                                nsIFrame*              aPrimaryFrame,
                                nsChangeHint           aMinHint,
                                RestyleTracker&        aRestyleTracker,
                                nsRestyleHint          aRestyleHint,
                                const RestyleHintData& aRestyleHintData)
 {
@@ -1907,176 +989,16 @@ RestyleManager::PostRebuildAllStyleDataE
   mDoRebuildAllStyleData = true;
   mRebuildAllExtraHint |= aExtraHint;
   mRebuildAllRestyleHint |= aRestyleHint;
 
   // Get a restyle event posted if necessary
   PostRestyleEventInternal(false);
 }
 
-#ifdef DEBUG
-static void
-DumpContext(nsIFrame* aFrame, nsStyleContext* aContext)
-{
-  if (aFrame) {
-    fputs("frame: ", stdout);
-    nsAutoString  name;
-    aFrame->GetFrameName(name);
-    fputs(NS_LossyConvertUTF16toASCII(name).get(), stdout);
-    fprintf(stdout, " (%p)", static_cast<void*>(aFrame));
-  }
-  if (aContext) {
-    fprintf(stdout, " style: %p ", static_cast<void*>(aContext));
-
-    nsIAtom* pseudoTag = aContext->GetPseudo();
-    if (pseudoTag) {
-      nsAutoString  buffer;
-      pseudoTag->ToString(buffer);
-      fputs(NS_LossyConvertUTF16toASCII(buffer).get(), stdout);
-      fputs(" ", stdout);
-    }
-    fputs("{}\n", stdout);
-  }
-}
-
-static void
-VerifySameTree(nsStyleContext* aContext1, nsStyleContext* aContext2)
-{
-  nsStyleContext* top1 = aContext1;
-  nsStyleContext* top2 = aContext2;
-  nsStyleContext* parent;
-  for (;;) {
-    parent = top1->GetParent();
-    if (!parent)
-      break;
-    top1 = parent;
-  }
-  for (;;) {
-    parent = top2->GetParent();
-    if (!parent)
-      break;
-    top2 = parent;
-  }
-  NS_ASSERTION(top1 == top2,
-               "Style contexts are not in the same style context tree");
-}
-
-static void
-VerifyContextParent(nsIFrame* aFrame, nsStyleContext* aContext,
-                    nsStyleContext* aParentContext)
-{
-  // get the contexts not provided
-  if (!aContext) {
-    aContext = aFrame->StyleContext();
-  }
-
-  if (!aParentContext) {
-    nsIFrame* providerFrame;
-    aParentContext = aFrame->GetParentStyleContext(&providerFrame);
-    // aParentContext could still be null
-  }
-
-  NS_ASSERTION(aContext, "Failure to get required contexts");
-  nsStyleContext* actualParentContext = aContext->GetParent();
-
-  if (aParentContext) {
-    if (aParentContext != actualParentContext) {
-      DumpContext(aFrame, aContext);
-      if (aContext == aParentContext) {
-        NS_ERROR("Using parent's style context");
-      }
-      else {
-        NS_ERROR("Wrong parent style context");
-        fputs("Wrong parent style context: ", stdout);
-        DumpContext(nullptr, actualParentContext);
-        fputs("should be using: ", stdout);
-        DumpContext(nullptr, aParentContext);
-        VerifySameTree(actualParentContext, aParentContext);
-        fputs("\n", stdout);
-      }
-    }
-
-  }
-  else {
-    if (actualParentContext) {
-      NS_ERROR("Have parent context and shouldn't");
-      DumpContext(aFrame, aContext);
-      fputs("Has parent context: ", stdout);
-      DumpContext(nullptr, actualParentContext);
-      fputs("Should be null\n\n", stdout);
-    }
-  }
-
-  nsStyleContext* childStyleIfVisited = aContext->GetStyleIfVisited();
-  // Either childStyleIfVisited has aContext->GetParent()->GetStyleIfVisited()
-  // as the parent or it has a different rulenode from aContext _and_ has
-  // aContext->GetParent() as the parent.
-  if (childStyleIfVisited &&
-      !((childStyleIfVisited->RuleNode() != aContext->RuleNode() &&
-         childStyleIfVisited->GetParent() == aContext->GetParent()) ||
-        childStyleIfVisited->GetParent() ==
-          aContext->GetParent()->GetStyleIfVisited())) {
-    NS_ERROR("Visited style has wrong parent");
-    DumpContext(aFrame, aContext);
-    fputs("\n", stdout);
-  }
-}
-
-static void
-VerifyStyleTree(nsIFrame* aFrame)
-{
-  nsStyleContext*  context = aFrame->StyleContext();
-  VerifyContextParent(aFrame, context, nullptr);
-
-  nsIFrame::ChildListIterator lists(aFrame);
-  for (; !lists.IsDone(); lists.Next()) {
-    for (nsIFrame* child : lists.CurrentList()) {
-      if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
-        // only do frames that are in flow
-        if (nsGkAtoms::placeholderFrame == child->GetType()) {
-          // placeholder: first recurse and verify the out of flow frame,
-          // then verify the placeholder's context
-          nsIFrame* outOfFlowFrame =
-            nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
-
-          // recurse to out of flow frame, letting the parent context get resolved
-          do {
-            VerifyStyleTree(outOfFlowFrame);
-          } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
-
-          // verify placeholder using the parent frame's context as
-          // parent context
-          VerifyContextParent(child, nullptr, nullptr);
-        }
-        else { // regular frame
-          VerifyStyleTree(child);
-        }
-      }
-    }
-  }
-
-  // do additional contexts
-  int32_t contextIndex = 0;
-  for (nsStyleContext* extraContext;
-       (extraContext = aFrame->GetAdditionalStyleContext(contextIndex));
-       ++contextIndex) {
-    VerifyContextParent(aFrame, extraContext, context);
-  }
-}
-
-void
-RestyleManager::DebugVerifyStyleTree(nsIFrame* aFrame)
-{
-  if (aFrame) {
-    VerifyStyleTree(aFrame);
-  }
-}
-
-#endif // DEBUG
-
 // aContent must be the content for the frame in question, which may be
 // :before/:after content
 /* static */ bool
 RestyleManager::TryStartingTransition(nsPresContext* aPresContext,
                                       nsIContent* aContent,
                                       nsStyleContext* aOldStyleContext,
                                       RefPtr<nsStyleContext>*
                                         aNewStyleContext /* inout */)
@@ -2484,17 +1406,17 @@ RestyleManager::ReparentStyleContext(nsI
             NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
                          "Our frame tree is likely to be bogus!");
           }
 
           aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
         }
       }
 #ifdef DEBUG
-      VerifyStyleTree(aFrame);
+      DebugVerifyStyleTree(aFrame);
 #endif
     }
   }
 
   return NS_OK;
 }
 
 ElementRestyler::ElementRestyler(nsPresContext* aPresContext,
@@ -4493,17 +3415,17 @@ ElementRestyler::ComputeStyleChangeFor(n
     content ? content->GetParentElementCrossingShadowRoot() : nullptr;
   treeMatchContext.InitAncestors(parent);
   nsTArray<nsCSSSelector*> selectorsForDescendants;
   selectorsForDescendants.AppendElements(
       aRestyleHintData.mSelectorsForDescendants);
   nsTArray<nsIContent*> visibleKidsOfHiddenElement;
   nsIFrame* nextIBSibling;
   for (nsIFrame* ibSibling = aFrame; ibSibling; ibSibling = nextIBSibling) {
-    nextIBSibling = GetNextBlockInInlineSibling(propTable, ibSibling);
+    nextIBSibling = RestyleManager::GetNextBlockInInlineSibling(propTable, ibSibling);
 
     if (nextIBSibling) {
       // Don't allow some ib-split siblings to be processed with
       // RestyleResult::eStopWithStyleChange and others not.
       aRestyleHint |= eRestyle_Force;
     }
 
     // Outer loop over ib-split siblings
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -32,17 +32,20 @@ namespace mozilla {
 
 namespace dom {
   class Element;
 } // namespace dom
 
 class RestyleManager final : public RestyleManagerBase
 {
 public:
+  typedef RestyleManagerBase base_type;
+
   friend class RestyleTracker;
+  friend class ElementRestyler;
 
   explicit RestyleManager(nsPresContext* aPresContext);
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~RestyleManager()
   {
     MOZ_ASSERT(!mReframingStyleContexts,
@@ -132,29 +135,26 @@ private:
                                     Element*               aElement,
                                     nsChangeHint           aMinChange,
                                     RestyleTracker&        aRestyleTracker,
                                     nsRestyleHint          aRestyleHint,
                                     const RestyleHintData& aRestyleHintData);
 
 public:
 
-#ifdef DEBUG
-  /**
-   * DEBUG ONLY method to verify integrity of style tree versus frame tree
-   */
-  void DebugVerifyStyleTree(nsIFrame* aFrame);
-#endif
-
   // Note: It's the caller's responsibility to make sure to wrap a
   // ProcessRestyledFrames call in a view update batch and a script blocker.
   // This function does not call ProcessAttachedQueue() on the binding manager.
   // If the caller wants that to happen synchronously, it needs to handle that
   // itself.
-  nsresult ProcessRestyledFrames(nsStyleChangeList& aRestyleArray);
+  nsresult ProcessRestyledFrames(nsStyleChangeList& aChangeList) {
+    return base_type::ProcessRestyledFrames(aChangeList,
+                                            *PresContext(),
+                                            mOverflowChangedTracker);
+  }
 
   /**
    * In order to start CSS transitions on elements that are being
    * reframed, we need to stash their style contexts somewhere during
    * the reframing process.
    *
    * In all cases, the content node in the hash table is the real
    * content node, not the anonymous content node we create for ::before
@@ -488,21 +488,16 @@ private:
   void StartRebuildAllStyleData(RestyleTracker& aRestyleTracker);
   void FinishRebuildAllStyleData();
 
   void StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint);
 
   // Recursively add all the given frame and all children to the tracker.
   void AddSubtreeToOverflowTracker(nsIFrame* aFrame);
 
-  // Returns true if this function managed to successfully move a frame, and
-  // false if it could not process the position change, and a reflow should
-  // be performed instead.
-  bool RecomputePosition(nsIFrame* aFrame);
-
   bool ShouldStartRebuildAllFor(RestyleTracker& aRestyleTracker) {
     // When we process our primary restyle tracker and we have a pending
     // rebuild-all, we need to process it.
     return mDoRebuildAllStyleData &&
            &aRestyleTracker == &mPendingRestyles;
   }
 
   void ProcessRestyles(RestyleTracker& aRestyleTracker) {
--- a/layout/base/RestyleManagerBase.cpp
+++ b/layout/base/RestyleManagerBase.cpp
@@ -129,10 +129,1095 @@ RestyleManagerBase::RestyleHintToString(
   } else {
     if (!any) {
       result.AppendLiteral("0");
     }
   }
   return result;
 }
 
+/**
+ * Frame construction helpers follow.
+ */
+#ifdef DEBUG
+static bool gInApplyRenderingChangeToTree = false;
+#endif
+
+#ifdef DEBUG
+static void
+DumpContext(nsIFrame* aFrame, nsStyleContext* aContext)
+{
+  if (aFrame) {
+    fputs("frame: ", stdout);
+    nsAutoString  name;
+    aFrame->GetFrameName(name);
+    fputs(NS_LossyConvertUTF16toASCII(name).get(), stdout);
+    fprintf(stdout, " (%p)", static_cast<void*>(aFrame));
+  }
+  if (aContext) {
+    fprintf(stdout, " style: %p ", static_cast<void*>(aContext));
+
+    nsIAtom* pseudoTag = aContext->GetPseudo();
+    if (pseudoTag) {
+      nsAutoString  buffer;
+      pseudoTag->ToString(buffer);
+      fputs(NS_LossyConvertUTF16toASCII(buffer).get(), stdout);
+      fputs(" ", stdout);
+    }
+    fputs("{}\n", stdout);
+  }
+}
+
+static void
+VerifySameTree(nsStyleContext* aContext1, nsStyleContext* aContext2)
+{
+  nsStyleContext* top1 = aContext1;
+  nsStyleContext* top2 = aContext2;
+  nsStyleContext* parent;
+  for (;;) {
+    parent = top1->GetParent();
+    if (!parent)
+      break;
+    top1 = parent;
+  }
+  for (;;) {
+    parent = top2->GetParent();
+    if (!parent)
+      break;
+    top2 = parent;
+  }
+  NS_ASSERTION(top1 == top2,
+               "Style contexts are not in the same style context tree");
+}
+
+static void
+VerifyContextParent(nsIFrame* aFrame, nsStyleContext* aContext,
+                    nsStyleContext* aParentContext)
+{
+  // get the contexts not provided
+  if (!aContext) {
+    aContext = aFrame->StyleContext();
+  }
+
+  if (!aParentContext) {
+    nsIFrame* providerFrame;
+    aParentContext = aFrame->GetParentStyleContext(&providerFrame);
+    // aParentContext could still be null
+  }
+
+  NS_ASSERTION(aContext, "Failure to get required contexts");
+  nsStyleContext* actualParentContext = aContext->GetParent();
+
+  if (aParentContext) {
+    if (aParentContext != actualParentContext) {
+      DumpContext(aFrame, aContext);
+      if (aContext == aParentContext) {
+        NS_ERROR("Using parent's style context");
+      }
+      else {
+        NS_ERROR("Wrong parent style context");
+        fputs("Wrong parent style context: ", stdout);
+        DumpContext(nullptr, actualParentContext);
+        fputs("should be using: ", stdout);
+        DumpContext(nullptr, aParentContext);
+        VerifySameTree(actualParentContext, aParentContext);
+        fputs("\n", stdout);
+      }
+    }
+
+  }
+  else {
+    if (actualParentContext) {
+      NS_ERROR("Have parent context and shouldn't");
+      DumpContext(aFrame, aContext);
+      fputs("Has parent context: ", stdout);
+      DumpContext(nullptr, actualParentContext);
+      fputs("Should be null\n\n", stdout);
+    }
+  }
+
+  nsStyleContext* childStyleIfVisited = aContext->GetStyleIfVisited();
+  // Either childStyleIfVisited has aContext->GetParent()->GetStyleIfVisited()
+  // as the parent or it has a different rulenode from aContext _and_ has
+  // aContext->GetParent() as the parent.
+  if (childStyleIfVisited &&
+      !((childStyleIfVisited->RuleNode() != aContext->RuleNode() &&
+         childStyleIfVisited->GetParent() == aContext->GetParent()) ||
+        childStyleIfVisited->GetParent() ==
+          aContext->GetParent()->GetStyleIfVisited())) {
+    NS_ERROR("Visited style has wrong parent");
+    DumpContext(aFrame, aContext);
+    fputs("\n", stdout);
+  }
+}
+
+static void
+VerifyStyleTree(nsIFrame* aFrame)
+{
+  nsStyleContext*  context = aFrame->StyleContext();
+  VerifyContextParent(aFrame, context, nullptr);
+
+  nsIFrame::ChildListIterator lists(aFrame);
+  for (; !lists.IsDone(); lists.Next()) {
+    for (nsIFrame* child : lists.CurrentList()) {
+      if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+        // only do frames that are in flow
+        if (nsGkAtoms::placeholderFrame == child->GetType()) {
+          // placeholder: first recurse and verify the out of flow frame,
+          // then verify the placeholder's context
+          nsIFrame* outOfFlowFrame =
+            nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
+
+          // recurse to out of flow frame, letting the parent context get resolved
+          do {
+            VerifyStyleTree(outOfFlowFrame);
+          } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
+
+          // verify placeholder using the parent frame's context as
+          // parent context
+          VerifyContextParent(child, nullptr, nullptr);
+        } else { // regular frame
+          VerifyStyleTree(child);
+        }
+      }
+    }
+  }
+
+  // do additional contexts
+  int32_t contextIndex = 0;
+  for (nsStyleContext* extraContext;
+       (extraContext = aFrame->GetAdditionalStyleContext(contextIndex));
+       ++contextIndex) {
+    VerifyContextParent(aFrame, extraContext, context);
+  }
+}
+
+void
+RestyleManagerBase::DebugVerifyStyleTree(nsIFrame* aFrame)
+{
+  if (aFrame) {
+    VerifyStyleTree(aFrame);
+  }
+}
+
+#endif // DEBUG
+
+
+NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ChangeListProperty, bool)
+
+/**
+ * Sync views on aFrame and all of aFrame's descendants (following placeholders),
+ * if aChange has nsChangeHint_SyncFrameView.
+ * Calls DoApplyRenderingChangeToTree on all aFrame's out-of-flow descendants
+ * (following placeholders), if aChange has nsChangeHint_RepaintFrame.
+ * aFrame should be some combination of nsChangeHint_SyncFrameView,
+ * nsChangeHint_RepaintFrame, nsChangeHint_UpdateOpacityLayer and
+ * nsChangeHint_SchedulePaint, nothing else.
+*/
+static void
+SyncViewsAndInvalidateDescendants(nsIFrame* aFrame, nsChangeHint aChange);
+
+static void
+StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint);
+
+/**
+ * To handle nsChangeHint_ChildrenOnlyTransform we must iterate over the child
+ * frames of the SVG frame concerned. This helper function is used to find that
+ * SVG frame when we encounter nsChangeHint_ChildrenOnlyTransform to ensure
+ * that we iterate over the intended children, since sometimes we end up
+ * handling that hint while processing hints for one of the SVG frame's
+ * ancestor frames.
+ *
+ * The reason that we sometimes end up trying to process the hint for an
+ * ancestor of the SVG frame that the hint is intended for is due to the way we
+ * process restyle events. ApplyRenderingChangeToTree adjusts the frame from
+ * the restyled element's principle frame to one of its ancestor frames based
+ * on what nsCSSRendering::FindBackground returns, since the background style
+ * may have been propagated up to an ancestor frame. Processing hints using an
+ * ancestor frame is fine in general, but nsChangeHint_ChildrenOnlyTransform is
+ * a special case since it is intended to update the children of a specific
+ * frame.
+ */
+static nsIFrame*
+GetFrameForChildrenOnlyTransformHint(nsIFrame* aFrame)
+{
+  if (aFrame->GetType() == nsGkAtoms::viewportFrame) {
+    // This happens if the root-<svg> is fixed positioned, in which case we
+    // can't use aFrame->GetContent() to find the primary frame, since
+    // GetContent() returns nullptr for ViewportFrame.
+    aFrame = aFrame->PrincipalChildList().FirstChild();
+  }
+  // For an nsHTMLScrollFrame, this will get the SVG frame that has the
+  // children-only transforms:
+  aFrame = aFrame->GetContent()->GetPrimaryFrame();
+  if (aFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) {
+    aFrame = aFrame->PrincipalChildList().FirstChild();
+    MOZ_ASSERT(aFrame->GetType() == nsGkAtoms::svgOuterSVGAnonChildFrame,
+               "Where is the nsSVGOuterSVGFrame's anon child??");
+  }
+  MOZ_ASSERT(aFrame->IsFrameOfType(nsIFrame::eSVG |
+                                   nsIFrame::eSVGContainer),
+             "Children-only transforms only expected on SVG frames");
+  return aFrame;
+}
+
+
+// Returns true if this function managed to successfully move a frame, and
+// false if it could not process the position change, and a reflow should
+// be performed instead.
+bool
+RecomputePosition(nsIFrame* aFrame)
+{
+  // Don't process position changes on table frames, since we already handle
+  // the dynamic position change on the table wrapper frame, and the
+  // reflow-based fallback code path also ignores positions on inner table
+  // frames.
+  if (aFrame->GetType() == nsGkAtoms::tableFrame) {
+    return true;
+  }
+
+  const nsStyleDisplay* display = aFrame->StyleDisplay();
+  // Changes to the offsets of a non-positioned element can safely be ignored.
+  if (display->mPosition == NS_STYLE_POSITION_STATIC) {
+    return true;
+  }
+
+  // Don't process position changes on frames which have views or the ones which
+  // have a view somewhere in their descendants, because the corresponding view
+  // needs to be repositioned properly as well.
+  if (aFrame->HasView() ||
+      (aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
+    StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
+    return false;
+  }
+
+  aFrame->SchedulePaint();
+
+  // For relative positioning, we can simply update the frame rect
+  if (display->IsRelativelyPositionedStyle()) {
+    // Move the frame
+    if (display->mPosition == NS_STYLE_POSITION_STICKY) {
+      if (display->IsInnerTableStyle()) {
+        // We don't currently support sticky positioning of inner table
+        // elements (bug 975644). Bail.
+        //
+        // When this is fixed, remove the null-check for the computed
+        // offsets in nsTableRowFrame::ReflowChildren.
+        return true;
+      }
+
+      // Update sticky positioning for an entire element at once, starting with
+      // the first continuation or ib-split sibling.
+      // It's rare that the frame we already have isn't already the first
+      // continuation or ib-split sibling, but it can happen when styles differ
+      // across continuations such as ::first-line or ::first-letter, and in
+      // those cases we will generally (but maybe not always) do the work twice.
+      nsIFrame* firstContinuation =
+        nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
+
+      StickyScrollContainer::ComputeStickyOffsets(firstContinuation);
+      StickyScrollContainer* ssc =
+        StickyScrollContainer::GetStickyScrollContainerForFrame(firstContinuation);
+      if (ssc) {
+        ssc->PositionContinuations(firstContinuation);
+      }
+    } else {
+      MOZ_ASSERT(NS_STYLE_POSITION_RELATIVE == display->mPosition,
+                 "Unexpected type of positioning");
+      for (nsIFrame* cont = aFrame; cont;
+           cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
+        nsIFrame* cb = cont->GetContainingBlock();
+        nsMargin newOffsets;
+        WritingMode wm = cb->GetWritingMode();
+        const LogicalSize size(wm, cb->GetContentRectRelativeToSelf().Size());
+
+        ReflowInput::ComputeRelativeOffsets(wm, cont, size, newOffsets);
+        NS_ASSERTION(newOffsets.left == -newOffsets.right &&
+                     newOffsets.top == -newOffsets.bottom,
+                     "ComputeRelativeOffsets should return valid results");
+
+        // ReflowInput::ApplyRelativePositioning would work here, but
+        // since we've already checked mPosition and aren't changing the frame's
+        // normal position, go ahead and add the offsets directly.
+        cont->SetPosition(cont->GetNormalPosition() +
+                          nsPoint(newOffsets.left, newOffsets.top));
+      }
+    }
+
+    return true;
+  }
+
+  // For the absolute positioning case, set up a fake HTML reflow state for
+  // the frame, and then get the offsets and size from it. If the frame's size
+  // doesn't need to change, we can simply update the frame position. Otherwise
+  // we fall back to a reflow.
+  nsRenderingContext rc(
+    aFrame->PresContext()->PresShell()->CreateReferenceRenderingContext());
+
+  // Construct a bogus parent reflow state so that there's a usable
+  // containing block reflow state.
+  nsIFrame* parentFrame = aFrame->GetParent();
+  WritingMode parentWM = parentFrame->GetWritingMode();
+  WritingMode frameWM = aFrame->GetWritingMode();
+  LogicalSize parentSize = parentFrame->GetLogicalSize();
+
+  nsFrameState savedState = parentFrame->GetStateBits();
+  ReflowInput parentReflowInput(aFrame->PresContext(), parentFrame,
+                                      &rc, parentSize);
+  parentFrame->RemoveStateBits(~nsFrameState(0));
+  parentFrame->AddStateBits(savedState);
+
+  // The bogus parent state here was created with no parent state of its own,
+  // and therefore it won't have an mCBReflowInput set up.
+  // But we may need one (for InitCBReflowInput in a child state), so let's
+  // try to create one here for the cases where it will be needed.
+  Maybe<ReflowInput> cbReflowInput;
+  nsIFrame* cbFrame = parentFrame->GetContainingBlock();
+  if (cbFrame && (aFrame->GetContainingBlock() != parentFrame ||
+                  parentFrame->GetType() == nsGkAtoms::tableFrame)) {
+    LogicalSize cbSize = cbFrame->GetLogicalSize();
+    cbReflowInput.emplace(cbFrame->PresContext(), cbFrame, &rc, cbSize);
+    cbReflowInput->ComputedPhysicalMargin() = cbFrame->GetUsedMargin();
+    cbReflowInput->ComputedPhysicalPadding() = cbFrame->GetUsedPadding();
+    cbReflowInput->ComputedPhysicalBorderPadding() =
+      cbFrame->GetUsedBorderAndPadding();
+    parentReflowInput.mCBReflowInput = cbReflowInput.ptr();
+  }
+
+  NS_WARN_IF_FALSE(parentSize.ISize(parentWM) != NS_INTRINSICSIZE &&
+                   parentSize.BSize(parentWM) != NS_INTRINSICSIZE,
+                   "parentSize should be valid");
+  parentReflowInput.SetComputedISize(std::max(parentSize.ISize(parentWM), 0));
+  parentReflowInput.SetComputedBSize(std::max(parentSize.BSize(parentWM), 0));
+  parentReflowInput.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
+
+  parentReflowInput.ComputedPhysicalPadding() = parentFrame->GetUsedPadding();
+  parentReflowInput.ComputedPhysicalBorderPadding() =
+    parentFrame->GetUsedBorderAndPadding();
+  LogicalSize availSize = parentSize.ConvertTo(frameWM, parentWM);
+  availSize.BSize(frameWM) = NS_INTRINSICSIZE;
+
+  ViewportFrame* viewport = do_QueryFrame(parentFrame);
+  nsSize cbSize = viewport ?
+    viewport->AdjustReflowInputAsContainingBlock(&parentReflowInput).Size()
+    : aFrame->GetContainingBlock()->GetSize();
+  const nsMargin& parentBorder =
+    parentReflowInput.mStyleBorder->GetComputedBorder();
+  cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom());
+  LogicalSize lcbSize(frameWM, cbSize);
+  ReflowInput reflowInput(aFrame->PresContext(), parentReflowInput,
+                                aFrame, availSize, &lcbSize);
+  nsSize computedSize(reflowInput.ComputedWidth(), reflowInput.ComputedHeight());
+  computedSize.width += reflowInput.ComputedPhysicalBorderPadding().LeftRight();
+  if (computedSize.height != NS_INTRINSICSIZE) {
+    computedSize.height += reflowInput.ComputedPhysicalBorderPadding().TopBottom();
+  }
+  nsSize size = aFrame->GetSize();
+  // The RecomputePosition hint is not used if any offset changed between auto
+  // and non-auto. If computedSize.height == NS_INTRINSICSIZE then the new
+  // element height will be its intrinsic height, and since 'top' and 'bottom''s
+  // auto-ness hasn't changed, the old height must also be its intrinsic
+  // height, which we can assume hasn't changed (or reflow would have
+  // been triggered).
+  if (computedSize.width == size.width &&
+      (computedSize.height == NS_INTRINSICSIZE || computedSize.height == size.height)) {
+    // If we're solving for 'left' or 'top', then compute it here, in order to
+    // match the reflow code path.
+    if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().left) {
+      reflowInput.ComputedPhysicalOffsets().left = cbSize.width -
+                                          reflowInput.ComputedPhysicalOffsets().right -
+                                          reflowInput.ComputedPhysicalMargin().right -
+                                          size.width -
+                                          reflowInput.ComputedPhysicalMargin().left;
+    }
+
+    if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().top) {
+      reflowInput.ComputedPhysicalOffsets().top = cbSize.height -
+                                         reflowInput.ComputedPhysicalOffsets().bottom -
+                                         reflowInput.ComputedPhysicalMargin().bottom -
+                                         size.height -
+                                         reflowInput.ComputedPhysicalMargin().top;
+    }
+
+    // Move the frame
+    nsPoint pos(parentBorder.left + reflowInput.ComputedPhysicalOffsets().left +
+                reflowInput.ComputedPhysicalMargin().left,
+                parentBorder.top + reflowInput.ComputedPhysicalOffsets().top +
+                reflowInput.ComputedPhysicalMargin().top);
+    aFrame->SetPosition(pos);
+
+    return true;
+  }
+
+  // Fall back to a reflow
+  StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
+  return false;
+}
+
+static bool
+HasBoxAncestor(nsIFrame* aFrame)
+{
+  for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
+    if (f->IsXULBoxFrame()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ * Return true if aFrame's subtree has placeholders for out-of-flow content
+ * whose 'position' style's bit in aPositionMask is set.
+ */
+static bool
+FrameHasPositionedPlaceholderDescendants(nsIFrame* aFrame, uint32_t aPositionMask)
+{
+  const nsIFrame::ChildListIDs skip(nsIFrame::kAbsoluteList |
+                                    nsIFrame::kFixedList);
+  for (nsIFrame::ChildListIterator lists(aFrame); !lists.IsDone(); lists.Next()) {
+    if (!skip.Contains(lists.CurrentID())) {
+      for (nsIFrame* f : lists.CurrentList()) {
+        if (f->GetType() == nsGkAtoms::placeholderFrame) {
+          nsIFrame* outOfFlow = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
+          // If SVG text frames could appear here, they could confuse us since
+          // they ignore their position style ... but they can't.
+          NS_ASSERTION(!outOfFlow->IsSVGText(),
+                       "SVG text frames can't be out of flow");
+          if (aPositionMask & (1 << outOfFlow->StyleDisplay()->mPosition)) {
+            return true;
+          }
+        }
+        if (FrameHasPositionedPlaceholderDescendants(f, aPositionMask)) {
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+static bool
+NeedToReframeForAddingOrRemovingTransform(nsIFrame* aFrame)
+{
+  static_assert(0 <= NS_STYLE_POSITION_ABSOLUTE &&
+                NS_STYLE_POSITION_ABSOLUTE < 32, "Style constant out of range");
+  static_assert(0 <= NS_STYLE_POSITION_FIXED &&
+                NS_STYLE_POSITION_FIXED < 32, "Style constant out of range");
+
+  uint32_t positionMask;
+  // Don't call aFrame->IsPositioned here, since that returns true if
+  // the frame already has a transform, and we want to ignore that here
+  if (aFrame->IsAbsolutelyPositioned() ||
+      aFrame->IsRelativelyPositioned()) {
+    // This frame is a container for abs-pos descendants whether or not it
+    // has a transform.
+    // So abs-pos descendants are no problem; we only need to reframe if
+    // we have fixed-pos descendants.
+    positionMask = 1 << NS_STYLE_POSITION_FIXED;
+  } else {
+    // This frame may not be a container for abs-pos descendants already.
+    // So reframe if we have abs-pos or fixed-pos descendants.
+    positionMask = (1 << NS_STYLE_POSITION_FIXED) |
+        (1 << NS_STYLE_POSITION_ABSOLUTE);
+  }
+  for (nsIFrame* f = aFrame; f;
+       f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
+    if (FrameHasPositionedPlaceholderDescendants(f, positionMask)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/* static */ nsIFrame*
+RestyleManagerBase::GetNearestAncestorFrame(nsIContent* aContent)
+{
+  nsIFrame* ancestorFrame = nullptr;
+  for (nsIContent* ancestor = aContent->GetParent();
+       ancestor && !ancestorFrame;
+       ancestor = ancestor->GetParent()) {
+    ancestorFrame = ancestor->GetPrimaryFrame();
+  }
+  return ancestorFrame;
+}
+
+/* static */ nsIFrame*
+RestyleManagerBase::GetNextBlockInInlineSibling(FramePropertyTable* aPropTable, nsIFrame* aFrame)
+{
+  NS_ASSERTION(!aFrame->GetPrevContinuation(),
+               "must start with the first continuation");
+  // Might we have ib-split siblings?
+  if (!(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
+    // nothing more to do here
+    return nullptr;
+  }
+
+  return static_cast<nsIFrame*>
+    (aPropTable->Get(aFrame, nsIFrame::IBSplitSibling()));
+}
+
+static void
+DoApplyRenderingChangeToTree(nsIFrame* aFrame,
+                             nsChangeHint aChange)
+{
+  NS_PRECONDITION(gInApplyRenderingChangeToTree,
+                  "should only be called within ApplyRenderingChangeToTree");
+
+  for ( ; aFrame; aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame)) {
+    // Invalidate and sync views on all descendant frames, following placeholders.
+    // We don't need to update transforms in SyncViewsAndInvalidateDescendants, because
+    // there can't be any out-of-flows or popups that need to be transformed;
+    // all out-of-flow descendants of the transformed element must also be
+    // descendants of the transformed frame.
+    SyncViewsAndInvalidateDescendants(aFrame,
+      nsChangeHint(aChange & (nsChangeHint_RepaintFrame |
+                              nsChangeHint_SyncFrameView |
+                              nsChangeHint_UpdateOpacityLayer |
+                              nsChangeHint_SchedulePaint)));
+    // This must be set to true if the rendering change needs to
+    // invalidate content.  If it's false, a composite-only paint
+    // (empty transaction) will be scheduled.
+    bool needInvalidatingPaint = false;
+
+    // if frame has view, will already be invalidated
+    if (aChange & nsChangeHint_RepaintFrame) {
+      // Note that this whole block will be skipped when painting is suppressed
+      // (due to our caller ApplyRendingChangeToTree() discarding the
+      // nsChangeHint_RepaintFrame hint).  If you add handling for any other
+      // hints within this block, be sure that they too should be ignored when
+      // painting is suppressed.
+      needInvalidatingPaint = true;
+      aFrame->InvalidateFrameSubtree();
+      if ((aChange & nsChangeHint_UpdateEffects) &&
+          aFrame->IsFrameOfType(nsIFrame::eSVG) &&
+          !(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
+        // Need to update our overflow rects:
+        nsSVGUtils::ScheduleReflowSVG(aFrame);
+      }
+    }
+    if (aChange & nsChangeHint_UpdateTextPath) {
+      if (aFrame->IsSVGText()) {
+        // Invalidate and reflow the entire SVGTextFrame:
+        NS_ASSERTION(aFrame->GetContent()->IsSVGElement(nsGkAtoms::textPath),
+                     "expected frame for a <textPath> element");
+        nsIFrame* text = nsLayoutUtils::GetClosestFrameOfType(
+                                                      aFrame,
+                                                      nsGkAtoms::svgTextFrame);
+        NS_ASSERTION(text, "expected to find an ancestor SVGTextFrame");
+        static_cast<SVGTextFrame*>(text)->NotifyGlyphMetricsChange();
+      } else {
+        MOZ_ASSERT(false, "unexpected frame got nsChangeHint_UpdateTextPath");
+      }
+    }
+    if (aChange & nsChangeHint_UpdateOpacityLayer) {
+      // FIXME/bug 796697: we can get away with empty transactions for
+      // opacity updates in many cases.
+      needInvalidatingPaint = true;
+
+      ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_opacity);
+      if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
+        // SVG effects paints the opacity without using
+        // nsDisplayOpacity. We need to invalidate manually.
+        aFrame->InvalidateFrameSubtree();
+      }
+    }
+    if ((aChange & nsChangeHint_UpdateTransformLayer) &&
+        aFrame->IsTransformed()) {
+      ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_transform);
+      // If we're not already going to do an invalidating paint, see
+      // if we can get away with only updating the transform on a
+      // layer for this frame, and not scheduling an invalidating
+      // paint.
+      if (!needInvalidatingPaint) {
+        Layer* layer;
+        needInvalidatingPaint |= !aFrame->TryUpdateTransformOnly(&layer);
+
+        if (!needInvalidatingPaint) {
+          // Since we're not going to paint, we need to resend animation
+          // data to the layer.
+          MOZ_ASSERT(layer, "this can't happen if there's no layer");
+          nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(layer,
+            nullptr, nullptr, aFrame, eCSSProperty_transform);
+        }
+      }
+    }
+    if (aChange & nsChangeHint_ChildrenOnlyTransform) {
+      needInvalidatingPaint = true;
+      nsIFrame* childFrame =
+        GetFrameForChildrenOnlyTransformHint(aFrame)->PrincipalChildList().FirstChild();
+      for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
+        ActiveLayerTracker::NotifyRestyle(childFrame, eCSSProperty_transform);
+      }
+    }
+    if (aChange & nsChangeHint_SchedulePaint) {
+      needInvalidatingPaint = true;
+    }
+    aFrame->SchedulePaint(needInvalidatingPaint ?
+                          nsIFrame::PAINT_DEFAULT :
+                          nsIFrame::PAINT_COMPOSITE_ONLY);
+  }
+}
+
+/* static */ void
+SyncViewsAndInvalidateDescendants(nsIFrame* aFrame,
+                                  nsChangeHint aChange)
+{
+  NS_ASSERTION(nsChangeHint_size_t(aChange) ==
+                          (aChange & (nsChangeHint_RepaintFrame |
+                                      nsChangeHint_SyncFrameView |
+                                      nsChangeHint_UpdateOpacityLayer |
+                                      nsChangeHint_SchedulePaint)),
+               "Invalid change flag");
+
+  nsView* view = aFrame->GetView();
+  if (view) {
+    if (aChange & nsChangeHint_SyncFrameView) {
+      nsContainerFrame::SyncFrameViewProperties(aFrame->PresContext(),
+                                                aFrame, nullptr, view);
+    }
+  }
+
+  nsIFrame::ChildListIterator lists(aFrame);
+  for (; !lists.IsDone(); lists.Next()) {
+    for (nsIFrame* child : lists.CurrentList()) {
+      if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+        // only do frames that don't have placeholders
+        if (nsGkAtoms::placeholderFrame == child->GetType()) {
+          // do the out-of-flow frame and its continuations
+          nsIFrame* outOfFlowFrame =
+            nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
+          DoApplyRenderingChangeToTree(outOfFlowFrame, aChange);
+        } else if (lists.CurrentID() == nsIFrame::kPopupList) {
+          DoApplyRenderingChangeToTree(child, aChange);
+        } else {  // regular frame
+          SyncViewsAndInvalidateDescendants(child, aChange);
+        }
+      }
+    }
+  }
+}
+
+void
+ApplyRenderingChangeToTree(nsIPresShell* aPresShell,
+                           nsIFrame* aFrame,
+                           nsChangeHint aChange)
+{
+  // We check StyleDisplay()->HasTransformStyle() in addition to checking
+  // IsTransformed() since we can get here for some frames that don't support
+  // CSS transforms.
+  NS_ASSERTION(!(aChange & nsChangeHint_UpdateTransformLayer) ||
+               aFrame->IsTransformed() ||
+               aFrame->StyleDisplay()->HasTransformStyle(),
+               "Unexpected UpdateTransformLayer hint");
+
+  if (aPresShell->IsPaintingSuppressed()) {
+    // Don't allow synchronous rendering changes when painting is turned off.
+    aChange &= ~nsChangeHint_RepaintFrame;
+    if (!aChange) {
+      return;
+    }
+  }
+
+  // Trigger rendering updates by damaging this frame and any
+  // continuations of this frame.
+#ifdef DEBUG
+  gInApplyRenderingChangeToTree = true;
+#endif
+  if (aChange & nsChangeHint_RepaintFrame) {
+    // If the frame's background is propagated to an ancestor, walk up to
+    // that ancestor and apply the RepaintFrame change hint to it.
+    nsStyleContext* bgSC;
+    nsIFrame* propagatedFrame = aFrame;
+    while (!nsCSSRendering::FindBackground(propagatedFrame, &bgSC)) {
+      propagatedFrame = propagatedFrame->GetParent();
+      NS_ASSERTION(aFrame, "root frame must paint");
+    }
+
+    if (propagatedFrame != aFrame) {
+      DoApplyRenderingChangeToTree(propagatedFrame, nsChangeHint_RepaintFrame);
+      aChange &= ~nsChangeHint_RepaintFrame;
+      if (!aChange) {
+        return;
+      }
+    }
+  }
+  DoApplyRenderingChangeToTree(aFrame, aChange);
+#ifdef DEBUG
+  gInApplyRenderingChangeToTree = false;
+#endif
+}
+
+static void
+AddSubtreeToOverflowTracker(nsIFrame* aFrame,
+                            OverflowChangedTracker& aOverflowChangedTracker)
+{
+  if (aFrame->FrameMaintainsOverflow()) {
+    aOverflowChangedTracker.AddFrame(aFrame,
+                                     OverflowChangedTracker::CHILDREN_CHANGED);
+  }
+  nsIFrame::ChildListIterator lists(aFrame);
+  for (; !lists.IsDone(); lists.Next()) {
+    for (nsIFrame* child : lists.CurrentList()) {
+      AddSubtreeToOverflowTracker(child, aOverflowChangedTracker);
+    }
+  }
+}
+
+static void
+StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint)
+{
+  nsIPresShell::IntrinsicDirty dirtyType;
+  if (aHint & nsChangeHint_ClearDescendantIntrinsics) {
+    NS_ASSERTION(aHint & nsChangeHint_ClearAncestorIntrinsics,
+                 "Please read the comments in nsChangeHint.h");
+    NS_ASSERTION(aHint & nsChangeHint_NeedDirtyReflow,
+                 "ClearDescendantIntrinsics requires NeedDirtyReflow");
+    dirtyType = nsIPresShell::eStyleChange;
+  } else if ((aHint & nsChangeHint_UpdateComputedBSize) &&
+             aFrame->HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
+    dirtyType = nsIPresShell::eStyleChange;
+  } else if (aHint & nsChangeHint_ClearAncestorIntrinsics) {
+    dirtyType = nsIPresShell::eTreeChange;
+  } else if ((aHint & nsChangeHint_UpdateComputedBSize) &&
+             HasBoxAncestor(aFrame)) {
+    // The frame's computed BSize is changing, and we have a box ancestor
+    // whose cached intrinsic height may need to be updated.
+    dirtyType = nsIPresShell::eTreeChange;
+  } else {
+    dirtyType = nsIPresShell::eResize;
+  }
+
+  nsFrameState dirtyBits;
+  if (aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
+    dirtyBits = nsFrameState(0);
+  } else if ((aHint & nsChangeHint_NeedDirtyReflow) ||
+             dirtyType == nsIPresShell::eStyleChange) {
+    dirtyBits = NS_FRAME_IS_DIRTY;
+  } else {
+    dirtyBits = NS_FRAME_HAS_DIRTY_CHILDREN;
+  }
+
+  // If we're not going to clear any intrinsic sizes on the frames, and
+  // there are no dirty bits to set, then there's nothing to do.
+  if (dirtyType == nsIPresShell::eResize && !dirtyBits)
+    return;
+
+  nsIPresShell::ReflowRootHandling rootHandling;
+  if (aHint & nsChangeHint_ReflowChangesSizeOrPosition) {
+    rootHandling = nsIPresShell::ePositionOrSizeChange;
+  } else {
+    rootHandling = nsIPresShell::eNoPositionOrSizeChange;
+  }
+
+  do {
+    aFrame->PresContext()->PresShell()->FrameNeedsReflow(aFrame, dirtyType, dirtyBits,
+                                                         rootHandling);
+    aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame);
+  } while (aFrame);
+}
+
+/* static */ nsresult
+RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList,
+                                          nsPresContext& aPresContext,
+                                          OverflowChangedTracker& aOverflowChangedTracker)
+{
+  NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
+               "Someone forgot a script blocker");
+  int32_t count = aChangeList.Count();
+  if (!count)
+    return NS_OK;
+
+  PROFILER_LABEL("RestyleManager", "ProcessRestyledFrames",
+    js::ProfileEntry::Category::CSS);
+
+  FramePropertyTable* propTable = aPresContext.PropertyTable();
+  nsCSSFrameConstructor* frameConstructor = aPresContext.FrameConstructor();
+
+  // Make sure to not rebuild quote or counter lists while we're
+  // processing restyles
+  frameConstructor->BeginUpdate();
+
+  // Mark frames so that we skip frames that die along the way, bug 123049.
+  // A frame can be in the list multiple times with different hints. Further
+  // optmization is possible if nsStyleChangeList::AppendChange could coalesce
+  int32_t index = count;
+
+  while (0 <= --index) {
+    const nsStyleChangeData* changeData;
+    aChangeList.ChangeAt(index, &changeData);
+    if (changeData->mFrame) {
+      propTable->Set(changeData->mFrame, ChangeListProperty(), true);
+    }
+  }
+
+  index = count;
+
+  bool didUpdateCursor = false;
+
+  while (0 <= --index) {
+    nsIFrame* frame;
+    nsIContent* content;
+    bool didReflowThisFrame = false;
+    nsChangeHint hint;
+    aChangeList.ChangeAt(index, frame, content, hint);
+
+    NS_ASSERTION(!(hint & nsChangeHint_AllReflowHints) ||
+                 (hint & nsChangeHint_NeedReflow),
+                 "Reflow hint bits set without actually asking for a reflow");
+
+    // skip any frame that has been destroyed due to a ripple effect
+    if (frame && !propTable->Get(frame, ChangeListProperty())) {
+      continue;
+    }
+
+    if (frame && frame->GetContent() != content) {
+      // XXXbz this is due to image maps messing with the primary frame of
+      // <area>s.  See bug 135040.  Remove this block once that's fixed.
+      frame = nullptr;
+      if (!(hint & nsChangeHint_ReconstructFrame)) {
+        continue;
+      }
+    }
+
+    if ((hint & nsChangeHint_UpdateContainingBlock) && frame &&
+        !(hint & nsChangeHint_ReconstructFrame)) {
+      if (NeedToReframeForAddingOrRemovingTransform(frame) ||
+          frame->GetType() == nsGkAtoms::fieldSetFrame ||
+          frame->GetContentInsertionFrame() != frame) {
+        // The frame has positioned children that need to be reparented, or
+        // it can't easily be converted to/from being an abs-pos container correctly.
+        hint |= nsChangeHint_ReconstructFrame;
+      } else {
+        for (nsIFrame* cont = frame; cont;
+             cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
+          // Normally frame construction would set state bits as needed,
+          // but we're not going to reconstruct the frame so we need to set them.
+          // It's because we need to set this state on each affected frame
+          // that we can't coalesce nsChangeHint_UpdateContainingBlock hints up
+          // to ancestors (i.e. it can't be an inherited change hint).
+          if (cont->IsAbsPosContaininingBlock()) {
+            if (cont->StyleDisplay()->HasTransform(cont)) {
+              cont->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
+            }
+            if (!cont->IsAbsoluteContainer() &&
+                (cont->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
+              cont->MarkAsAbsoluteContainingBlock();
+            }
+          } else {
+            // Don't remove NS_FRAME_MAY_BE_TRANSFORMED since it may still by
+            // transformed by other means. It's OK to have the bit even if it's
+            // not needed.
+            if (cont->IsAbsoluteContainer()) {
+              cont->MarkAsNotAbsoluteContainingBlock();
+            }
+          }
+        }
+      }
+    }
+    if (hint & nsChangeHint_ReconstructFrame) {
+      // If we ever start passing true here, be careful of restyles
+      // that involve a reframe and animations.  In particular, if the
+      // restyle we're processing here is an animation restyle, but
+      // the style resolution we will do for the frame construction
+      // happens async when we're not in an animation restyle already,
+      // problems could arise.
+      // We could also have problems with triggering of CSS transitions
+      // on elements whose frames are reconstructed, since we depend on
+      // the reconstruction happening synchronously.
+      frameConstructor->RecreateFramesForContent(content, false,
+        nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION, nullptr);
+    } else {
+      NS_ASSERTION(frame, "This shouldn't happen");
+
+      if (!frame->FrameMaintainsOverflow()) {
+        // frame does not maintain overflow rects, so avoid calling
+        // FinishAndStoreOverflow on it:
+        hint &= ~(nsChangeHint_UpdateOverflow |
+                  nsChangeHint_ChildrenOnlyTransform |
+                  nsChangeHint_UpdatePostTransformOverflow |
+                  nsChangeHint_UpdateParentOverflow);
+      }
+
+      if (!(frame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED)) {
+        // Frame can not be transformed, and thus a change in transform will
+        // have no effect and we should not use the
+        // nsChangeHint_UpdatePostTransformOverflow hint.
+        hint &= ~nsChangeHint_UpdatePostTransformOverflow;
+      }
+
+      if (hint & nsChangeHint_UpdateEffects) {
+        for (nsIFrame* cont = frame; cont;
+             cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
+          nsSVGEffects::UpdateEffects(cont);
+        }
+      }
+      if ((hint & nsChangeHint_InvalidateRenderingObservers) ||
+          ((hint & nsChangeHint_UpdateOpacityLayer) &&
+           frame->IsFrameOfType(nsIFrame::eSVG) &&
+           !(frame->GetStateBits() & NS_STATE_IS_OUTER_SVG))) {
+        nsSVGEffects::InvalidateRenderingObservers(frame);
+      }
+      if (hint & nsChangeHint_NeedReflow) {
+        StyleChangeReflow(frame, hint);
+        didReflowThisFrame = true;
+      }
+
+      if ((hint & nsChangeHint_UpdateUsesOpacity) &&
+          frame->IsFrameOfType(nsIFrame::eTablePart)) {
+        NS_ASSERTION(hint & nsChangeHint_UpdateOpacityLayer,
+                     "should only return UpdateUsesOpacity hint "
+                     "when also returning UpdateOpacityLayer hint");
+        // When an internal table part (including cells) changes between
+        // having opacity 1 and non-1, it changes whether its
+        // backgrounds (and those of table parts inside of it) are
+        // painted as part of the table's nsDisplayTableBorderBackground
+        // display item, or part of its own display item.  That requires
+        // invalidation, so change UpdateOpacityLayer to RepaintFrame.
+        hint &= ~nsChangeHint_UpdateOpacityLayer;
+        hint |= nsChangeHint_RepaintFrame;
+      }
+
+      if (hint & nsChangeHint_UpdateBackgroundPosition) {
+        // For most frame types, DLBI can detect background position changes,
+        // so we only need to schedule a paint.
+        hint |= nsChangeHint_SchedulePaint;
+        if (frame->IsFrameOfType(nsIFrame::eTablePart) ||
+            frame->IsFrameOfType(nsIFrame::eMathML)) {
+          // Table parts and MathML frames don't build display items for their
+          // backgrounds, so DLBI can't detect background-position changes for
+          // these frames. Repaint the whole frame.
+          hint |= nsChangeHint_RepaintFrame;
+        }
+      }
+
+      if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView |
+                  nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer |
+                  nsChangeHint_ChildrenOnlyTransform | nsChangeHint_SchedulePaint)) {
+        ApplyRenderingChangeToTree(aPresContext.PresShell(), frame, hint);
+      }
+      if ((hint & nsChangeHint_RecomputePosition) && !didReflowThisFrame) {
+        ActiveLayerTracker::NotifyOffsetRestyle(frame);
+        // It is possible for this to fall back to a reflow
+        if (!RecomputePosition(frame)) {
+          didReflowThisFrame = true;
+        }
+      }
+      NS_ASSERTION(!(hint & nsChangeHint_ChildrenOnlyTransform) ||
+                   (hint & nsChangeHint_UpdateOverflow),
+                   "nsChangeHint_UpdateOverflow should be passed too");
+      if (!didReflowThisFrame &&
+          (hint & (nsChangeHint_UpdateOverflow |
+                   nsChangeHint_UpdatePostTransformOverflow |
+                   nsChangeHint_UpdateParentOverflow |
+                   nsChangeHint_UpdateSubtreeOverflow))) {
+        if (hint & nsChangeHint_UpdateSubtreeOverflow) {
+          for (nsIFrame* cont = frame; cont; cont =
+                 nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
+            AddSubtreeToOverflowTracker(cont, aOverflowChangedTracker);
+          }
+          // The work we just did in AddSubtreeToOverflowTracker
+          // subsumes some of the other hints:
+          hint &= ~(nsChangeHint_UpdateOverflow |
+                    nsChangeHint_UpdatePostTransformOverflow);
+        }
+        if (hint & nsChangeHint_ChildrenOnlyTransform) {
+          // The overflow areas of the child frames need to be updated:
+          nsIFrame* hintFrame = GetFrameForChildrenOnlyTransformHint(frame);
+          nsIFrame* childFrame = hintFrame->PrincipalChildList().FirstChild();
+          NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame),
+                       "SVG frames should not have continuations "
+                       "or ib-split siblings");
+          NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(hintFrame),
+                       "SVG frames should not have continuations "
+                       "or ib-split siblings");
+          for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
+            MOZ_ASSERT(childFrame->IsFrameOfType(nsIFrame::eSVG),
+                       "Not expecting non-SVG children");
+            // If |childFrame| is dirty or has dirty children, we don't bother
+            // updating overflows since that will happen when it's reflowed.
+            if (!(childFrame->GetStateBits() &
+                  (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
+              aOverflowChangedTracker.AddFrame(childFrame,
+                                        OverflowChangedTracker::CHILDREN_CHANGED);
+            }
+            NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(childFrame),
+                         "SVG frames should not have continuations "
+                         "or ib-split siblings");
+            NS_ASSERTION(childFrame->GetParent() == hintFrame,
+                         "SVG child frame not expected to have different parent");
+          }
+        }
+        // If |frame| is dirty or has dirty children, we don't bother updating
+        // overflows since that will happen when it's reflowed.
+        if (!(frame->GetStateBits() &
+              (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
+          if (hint & (nsChangeHint_UpdateOverflow |
+                      nsChangeHint_UpdatePostTransformOverflow)) {
+            OverflowChangedTracker::ChangeKind changeKind;
+            // If we have both nsChangeHint_UpdateOverflow and
+            // nsChangeHint_UpdatePostTransformOverflow,
+            // CHILDREN_CHANGED is selected as it is
+            // strictly stronger.
+            if (hint & nsChangeHint_UpdateOverflow) {
+              changeKind = OverflowChangedTracker::CHILDREN_CHANGED;
+            } else {
+              changeKind = OverflowChangedTracker::TRANSFORM_CHANGED;
+            }
+            for (nsIFrame* cont = frame; cont; cont =
+                   nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
+              aOverflowChangedTracker.AddFrame(cont, changeKind);
+            }
+          }
+          // UpdateParentOverflow hints need to be processed in addition
+          // to the above, since if the processing of the above hints
+          // yields no change, the update will not propagate to the
+          // parent.
+          if (hint & nsChangeHint_UpdateParentOverflow) {
+            MOZ_ASSERT(frame->GetParent(),
+                       "shouldn't get style hints for the root frame");
+            for (nsIFrame* cont = frame; cont; cont =
+                   nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
+              aOverflowChangedTracker.AddFrame(cont->GetParent(),
+                                   OverflowChangedTracker::CHILDREN_CHANGED);
+            }
+          }
+        }
+      }
+      if ((hint & nsChangeHint_UpdateCursor) && !didUpdateCursor) {
+        aPresContext.PresShell()->SynthesizeMouseMove(false);
+        didUpdateCursor = true;
+      }
+    }
+  }
+
+  frameConstructor->EndUpdate();
+
+  // cleanup references and verify the style tree.  Note that the latter needs
+  // to happen once we've processed the whole list, since until then the tree
+  // is not in fact in a consistent state.
+  index = count;
+  while (0 <= --index) {
+    const nsStyleChangeData* changeData;
+    aChangeList.ChangeAt(index, &changeData);
+    if (changeData->mFrame) {
+      propTable->Delete(changeData->mFrame, ChangeListProperty());
+    }
+
+#ifdef DEBUG
+    // reget frame from content since it may have been regenerated...
+    if (changeData->mContent) {
+      nsIFrame* frame = changeData->mContent->GetPrimaryFrame();
+      if (frame) {
+        DebugVerifyStyleTree(frame);
+      }
+    } else if (!changeData->mFrame ||
+               changeData->mFrame->GetType() != nsGkAtoms::viewportFrame) {
+      NS_WARNING("Unable to test style tree integrity -- no content node "
+                 "(and not a viewport frame)");
+    }
+#endif
+  }
+
+  aChangeList.Clear();
+  return NS_OK;
+}
 
 } // namespace mozilla
--- a/layout/base/RestyleManagerBase.h
+++ b/layout/base/RestyleManagerBase.h
@@ -4,18 +4,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_RestyleManagerBase_h
 #define mozilla_RestyleManagerBase_h
 
 #include "nsChangeHint.h"
 
+class nsStyleChangeList;
+
 namespace mozilla {
 
+class OverflowChangedTracker;
 class ServoRestyleManager;
 class RestyleManager;
 
 /**
  * Class for sharing data and logic common to both RestyleManager and
  * ServoRestyleManager.
  */
 class RestyleManagerBase
@@ -39,16 +42,23 @@ public:
   void SetObservingRefreshDriver(bool aObserving) {
       mObservingRefreshDriver = aObserving;
   }
 
   void Disconnect() { mPresContext = nullptr; }
 
   static nsCString RestyleHintToString(nsRestyleHint aHint);
 
+#ifdef DEBUG
+  /**
+   * DEBUG ONLY method to verify integrity of style tree versus frame tree
+   */
+  static void DebugVerifyStyleTree(nsIFrame* aFrame);
+#endif
+
 protected:
   void ContentStateChangedInternal(Element* aElement,
                                    EventStates aStateMask,
                                    nsChangeHint* aOutChangeHint,
                                    nsRestyleHint* aOutRestyleHint);
 
   bool IsDisconnected() { return mPresContext == nullptr; }
 
@@ -87,13 +97,29 @@ protected:
   }
 
 private:
   nsPresContext* mPresContext; // weak, can be null after Disconnect().
   uint32_t mRestyleGeneration;
   uint32_t mHoverGeneration;
   // True if we're already waiting for a refresh notification.
   bool mObservingRefreshDriver;
+
+  /**
+   * These are protected static methods that help with the frame construction
+   * bits of the restyle managers.
+   */
+protected:
+  static nsIFrame*
+  GetNearestAncestorFrame(nsIContent* aContent);
+
+  static nsIFrame*
+  GetNextBlockInInlineSibling(FramePropertyTable* aPropTable, nsIFrame* aFrame);
+
+  static nsresult
+  ProcessRestyledFrames(nsStyleChangeList& aChangeList,
+                        nsPresContext& aPresContext,
+                        OverflowChangedTracker& aOverflowChangedTracker);
 };
 
 } // namespace mozilla
 
 #endif
--- a/layout/base/RestyleManagerHandle.h
+++ b/layout/base/RestyleManagerHandle.h
@@ -20,16 +20,17 @@ class ServoRestyleManager;
 namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
 class nsAttrValue;
 class nsIAtom;
 class nsIContent;
 class nsIFrame;
+class nsStyleChangeList;
 
 namespace mozilla {
 
 #define SERVO_BIT 0x1
 
 /**
  * Smart pointer class that can hold a pointer to either a RestyleManager
  * or a ServoRestyleManager.
@@ -132,16 +133,18 @@ public:
                                  nsIAtom* aAttribute,
                                  int32_t aModType,
                                  const nsAttrValue* aOldValue);
     inline nsresult ReparentStyleContext(nsIFrame* aFrame);
     inline bool HasPendingRestyles();
     inline uint64_t GetRestyleGeneration() const;
     inline uint32_t GetHoverGeneration() const;
     inline void SetObservingRefreshDriver(bool aObserving);
+    inline nsresult ProcessRestyledFrames(nsStyleChangeList& aChangeList);
+    inline void FlushOverflowChangedTracker();
 
   private:
     // Stores a pointer to an RestyleManager or a ServoRestyleManager.  The least
     // significant bit is 0 for the former, 1 for the latter.  This is
     // valid as the least significant bit will never be used for a pointer
     // value on platforms we care about.
     uintptr_t mValue;
   };
--- a/layout/base/RestyleManagerHandleInlines.h
+++ b/layout/base/RestyleManagerHandleInlines.h
@@ -69,16 +69,28 @@ RestyleManagerHandle::Ptr::PostRebuildAl
 }
 
 void
 RestyleManagerHandle::Ptr::ProcessPendingRestyles()
 {
   FORWARD(ProcessPendingRestyles, ());
 }
 
+nsresult
+RestyleManagerHandle::Ptr::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
+{
+  FORWARD(ProcessRestyledFrames, (aChangeList));
+}
+
+void
+RestyleManagerHandle::Ptr::FlushOverflowChangedTracker()
+{
+  FORWARD(FlushOverflowChangedTracker, ());
+}
+
 void
 RestyleManagerHandle::Ptr::RestyleForInsertOrChange(dom::Element* aContainer,
                                                     nsIContent* aChild)
 {
   FORWARD(RestyleForInsertOrChange, (aContainer, aChild));
 }
 
 void
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -306,9 +306,23 @@ ServoRestyleManager::ReparentStyleContex
 ServoElementSnapshot*
 ServoRestyleManager::SnapshotForElement(Element* aElement)
 {
   // NB: aElement is the argument for the construction of the snapshot in the
   // not found case.
   return mModifiedElements.LookupOrAdd(aElement, aElement);
 }
 
+nsresult
+ServoRestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
+{
+  MOZ_CRASH("stylo: ServoRestyleManager::ProcessRestyledFrames not implemented "
+            "for Servo-backed style system");
+}
+
+void
+ServoRestyleManager::FlushOverflowChangedTracker()
+{
+  MOZ_CRASH("stylo: ServoRestyleManager::FlushOverflowChangedTracker "
+            "not implemented for Servo-backed style system");
+}
+
 } // namespace mozilla
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -20,16 +20,17 @@ namespace mozilla {
 namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
 class nsAttrValue;
 class nsIAtom;
 class nsIContent;
 class nsIFrame;
+class nsStyleChangeList;
 
 namespace mozilla {
 
 /**
  * Restyle manager for a Servo-backed style system.
  */
 class ServoRestyleManager : public RestyleManagerBase
 {
@@ -64,16 +65,18 @@ public:
                            const nsAttrValue* aNewValue);
 
   // XXXbholley: We should assert that the element is already snapshotted.
   void AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID,
                         nsIAtom* aAttribute, int32_t aModType,
                         const nsAttrValue* aOldValue) {}
 
   nsresult ReparentStyleContext(nsIFrame* aFrame);
+  nsresult ProcessRestyledFrames(nsStyleChangeList& aChangeList);
+  void FlushOverflowChangedTracker();
 
   bool HasPendingRestyles() { return !mModifiedElements.IsEmpty(); }
 
 protected:
   ~ServoRestyleManager() {}
 
 private:
   ServoElementSnapshot* SnapshotForElement(Element* aElement);
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -7,16 +7,17 @@
  * construction of a frame tree that is nearly isomorphic to the content
  * tree and updating of that tree in response to dynamic changes
  */
 
 #ifndef nsCSSFrameConstructor_h___
 #define nsCSSFrameConstructor_h___
 
 #include "mozilla/Attributes.h"
+#include "mozilla/RestyleManagerBase.h"
 #include "mozilla/RestyleManagerHandle.h"
 
 #include "nsCOMPtr.h"
 #include "nsILayoutHistoryState.h"
 #include "nsQuoteList.h"
 #include "nsCounterManager.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsFrameManager.h"
@@ -48,16 +49,17 @@ class FlattenedChildIterator;
 
 class nsCSSFrameConstructor : public nsFrameManager
 {
 public:
   typedef mozilla::CSSPseudoElementType CSSPseudoElementType;
   typedef mozilla::dom::Element Element;
 
   friend class mozilla::RestyleManager;
+  friend class mozilla::RestyleManagerBase;
 
   nsCSSFrameConstructor(nsIDocument* aDocument, nsIPresShell* aPresShell);
   ~nsCSSFrameConstructor(void) {
     NS_ASSERTION(mUpdateCount == 0, "Dying in the middle of our own update?");
   }
 
   // get the alternate text for a content node
   static void GetAlternateTextFor(nsIContent*    aContent,
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -52,16 +52,17 @@
 #include "GeckoProfiler.h"
 #include "nsCSSRenderingBorders.h"
 #include "mozilla/css/ImageLoader.h"
 #include "ImageContainer.h"
 #include "mozilla/Telemetry.h"
 #include "gfxUtils.h"
 #include "gfxGradientCache.h"
 #include "nsInlineFrame.h"
+#include "nsRubyTextContainerFrame.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::gfx;
 using namespace mozilla::image;
 using mozilla::CSSSizeOrRatio;
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -2907,22 +2907,18 @@ PresShell::RecreateFramesFor(nsIContent*
   nsAutoScriptBlocker scriptBlocker;
 
   nsStyleChangeList changeList;
   changeList.AppendChange(nullptr, aContent, nsChangeHint_ReconstructFrame);
 
   // Mark ourselves as not safe to flush while we're doing frame construction.
   ++mChangeNestCount;
   RestyleManagerHandle restyleManager = mPresContext->RestyleManager();
-  if (restyleManager->IsServo()) {
-    MOZ_CRASH("stylo: PresShell::RecreateFramesFor not implemented for Servo-"
-              "backed style system");
-  }
-  nsresult rv = restyleManager->AsGecko()->ProcessRestyledFrames(changeList);
-  restyleManager->AsGecko()->FlushOverflowChangedTracker();
+  nsresult rv = restyleManager->ProcessRestyledFrames(changeList);
+  restyleManager->FlushOverflowChangedTracker();
   --mChangeNestCount;
 
   return rv;
 }
 
 void
 nsIPresShell::PostRecreateFramesFor(Element* aElement)
 {