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); } } }
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 }
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(); }