void
StickyScrollContainer::UpdatePositions(nsPoint aScrollPosition,
                                       nsIFrame* aSubtreeRoot)
{
#ifdef DEBUG
  {
    nsIFrame* scrollFrameAsFrame = do_QueryFrame(mScrollFrame);
    NS_ASSERTION(!aSubtreeRoot || aSubtreeRoot == scrollFrameAsFrame,
                 "If reflowing, should be reflowing the scroll frame");
  }
#endif
  mScrollPosition = aScrollPosition;

  OverflowChangedTracker oct;
  oct.SetSubtreeRoot(aSubtreeRoot);
  for (nsTArray<nsIFrame*>::size_type i = 0; i < mFrames.Length(); i++) {
    nsIFrame* f = mFrames[i];

    if (aSubtreeRoot) {
      // Reflowing the scroll frame, so recompute offsets.
      ComputeStickyOffsets(f);
    }
    // mFrames will only contain first continuations, because we filter in
    // nsIFrame::Init.
    PositionContinuations(f);

    for (nsIFrame* cont = f; cont; cont = cont->GetNextContinuation()) {
      oct.AddFrame(cont);
    }
  }
  oct.Flush();
}
void
StickyScrollContainer::UpdatePositions(nsPoint aScrollPosition,
                                       nsIFrame* aSubtreeRoot)
{
#ifdef DEBUG
  {
    nsIFrame* scrollFrameAsFrame = do_QueryFrame(mScrollFrame);
    NS_ASSERTION(!aSubtreeRoot || aSubtreeRoot == scrollFrameAsFrame,
                 "If reflowing, should be reflowing the scroll frame");
  }
#endif
  mScrollPosition = aScrollPosition;

  OverflowChangedTracker oct;
  oct.SetSubtreeRoot(aSubtreeRoot);
  for (nsTArray<nsIFrame*>::size_type i = 0; i < mFrames.Length(); i++) {
    nsIFrame* f = mFrames[i];
    if (!nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(f)) {
      // This frame was added in nsFrame::Init before we knew it wasn't
      // the first ib-split-sibling.
      mFrames.RemoveElementAt(i);
      --i;
      continue;
    }

    if (aSubtreeRoot) {
      // Reflowing the scroll frame, so recompute offsets.
      ComputeStickyOffsets(f);
    }
    // mFrames will only contain first continuations, because we filter in
    // nsIFrame::Init.
    PositionContinuations(f);

    f = f->GetParent();
    if (f != aSubtreeRoot) {
      for (nsIFrame* cont = f; cont;
           cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
        oct.AddFrame(cont, OverflowChangedTracker::CHILDREN_CHANGED);
      }
    }
  }
  oct.Flush();
}
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);
    }
  }
}
Beispiel #4
0
void
RestyleTracker::DoProcessRestyles()
{
  SAMPLE_LABEL("CSS", "ProcessRestyles");
  // Make sure to not rebuild quote or counter lists while we're
  // processing restyles
  mFrameConstructor->BeginUpdate();

  mFrameConstructor->mInStyleRefresh = true;

  OverflowChangedTracker tracker;

  // loop so that we process any restyle events generated by processing
  while (mPendingRestyles.Count()) {
    if (mHaveLaterSiblingRestyles) {
      // Convert them to individual restyles on all the later siblings
      nsAutoTArray<nsRefPtr<Element>, RESTYLE_ARRAY_STACKSIZE> laterSiblingArr;
      LaterSiblingCollector siblingCollector = { this, &laterSiblingArr };
      mPendingRestyles.Enumerate(CollectLaterSiblings, &siblingCollector);
      for (uint32_t i = 0; i < laterSiblingArr.Length(); ++i) {
        Element* element = laterSiblingArr[i];
        for (nsIContent* sibling = element->GetNextSibling();
             sibling;
             sibling = sibling->GetNextSibling()) {
          if (sibling->IsElement() &&
              AddPendingRestyle(sibling->AsElement(), eRestyle_Subtree,
                                NS_STYLE_HINT_NONE)) {
              // Nothing else to do here; we'll handle the following
              // siblings when we get to |sibling| in laterSiblingArr.
            break;
          }
        }
      }

      // Now remove all those eRestyle_LaterSiblings bits
      for (uint32_t i = 0; i < laterSiblingArr.Length(); ++i) {
        Element* element = laterSiblingArr[i];
        NS_ASSERTION(element->HasFlag(RestyleBit()), "How did that happen?");
        RestyleData data;
#ifdef DEBUG
        bool found =
#endif
          mPendingRestyles.Get(element, &data);
        NS_ASSERTION(found, "Where did our entry go?");
        data.mRestyleHint =
          nsRestyleHint(data.mRestyleHint & ~eRestyle_LaterSiblings);

        mPendingRestyles.Put(element, data);
      }

      mHaveLaterSiblingRestyles = false;
    }

    uint32_t rootCount;
    while ((rootCount = mRestyleRoots.Length())) {
      // Make sure to pop the element off our restyle root array, so
      // that we can freely append to the array as we process this
      // element.
      nsRefPtr<Element> element;
      element.swap(mRestyleRoots[rootCount - 1]);
      mRestyleRoots.RemoveElementAt(rootCount - 1);

      // Do the document check before calling GetRestyleData, since we
      // don't want to do the sibling-processing GetRestyleData does if
      // the node is no longer relevant.
      if (element->GetCurrentDoc() != Document()) {
        // Content node has been removed from our document; nothing else
        // to do here
        continue;
      }

      RestyleData data;
      if (!GetRestyleData(element, &data)) {
        continue;
      }

      ProcessOneRestyle(element, data.mRestyleHint, data.mChangeHint, tracker);
    }

    if (mHaveLaterSiblingRestyles) {
      // Keep processing restyles for now
      continue;
    }

    // Now we only have entries with change hints left.  To be safe in
    // case of reentry from the handing of the change hint, use a
    // scratch array instead of calling out to ProcessOneRestyle while
    // enumerating the hashtable.  Use the stack if we can, otherwise
    // fall back on heap-allocation.
    nsAutoTArray<RestyleEnumerateData, RESTYLE_ARRAY_STACKSIZE> restyleArr;
    RestyleEnumerateData* restylesToProcess =
      restyleArr.AppendElements(mPendingRestyles.Count());
    if (restylesToProcess) {
      RestyleEnumerateData* lastRestyle = restylesToProcess;
      RestyleCollector collector = { this, &lastRestyle };
      mPendingRestyles.Enumerate(CollectRestyles, &collector);

      // Clear the hashtable now that we don't need it anymore
      mPendingRestyles.Clear();

      for (RestyleEnumerateData* currentRestyle = restylesToProcess;
           currentRestyle != lastRestyle;
           ++currentRestyle) {
        ProcessOneRestyle(currentRestyle->mElement,
                          currentRestyle->mRestyleHint,
                          currentRestyle->mChangeHint,
                          tracker);
      }
    }
  }

  tracker.Flush();

  // Set mInStyleRefresh to false now, since the EndUpdate call might
  // add more restyles.
  mFrameConstructor->mInStyleRefresh = false;

  mFrameConstructor->EndUpdate();

#ifdef DEBUG
  mFrameConstructor->mPresShell->VerifyStyleTree();
#endif
}
Beispiel #5
0
void
nsTransitionManager::UpdateAllThrottledStyles()
{
  if (PR_CLIST_IS_EMPTY(&mElementData)) {
    // no throttled transitions, leave early
    mPresContext->TickLastUpdateThrottledStyle();
    return;
  }

  if (mPresContext->ThrottledStyleIsUpToDate()) {
    // throttled transitions are up to date, leave early
    return;
  }

  mPresContext->TickLastUpdateThrottledStyle();
  TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();

  nsStyleChangeList changeList;

  // update each transitioning element by finding its root-most ancestor with a
  // transition, and flushing the style on that ancestor and all its descendants
  PRCList *next = PR_LIST_HEAD(&mElementData);
  while (next != &mElementData) {
    ElementTransitions* et = static_cast<ElementTransitions*>(next);
    next = PR_NEXT_LINK(next);

    if (et->mFlushGeneration == now) {
      // this element has been ticked already
      continue;
    }

    // element is initialised to the starting element (i.e., one we know has
    // a transition) and ends up with the root-most transitioning ancestor,
    // that is, the element where we begin updates.
    dom::Element* element = et->mElement;
    // make a list of ancestors
    nsTArray<dom::Element*> ancestors;
    do {
      ancestors.AppendElement(element);
    } while ((element = element->GetElementParent()));

    // walk down the ancestors until we find one with a throttled transition
    for (int32_t i = ancestors.Length() - 1; i >= 0; --i) {
      if (GetElementTransitions(ancestors[i],
                                nsCSSPseudoElements::ePseudo_NotPseudoElement,
                                false)) {
        element = ancestors[i];
        break;
      }
    }

    nsIFrame* primaryFrame;
    if (element &&
        (primaryFrame = element->GetPrimaryFrame())) {
      UpdateThrottledStylesForSubtree(element,
        primaryFrame->GetStyleContext()->GetParent(), changeList);
    }
  }

  OverflowChangedTracker tracker;
  mPresContext->PresShell()->FrameConstructor()->
    ProcessRestyledFrames(changeList, tracker);
  tracker.Flush();
}