layout/base/RestyleTracker.cpp

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

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

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

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /**
     7  * A class which manages pending restyles.  This handles keeping track
     8  * of what nodes restyles need to happen on and so forth.
     9  */
    11 #include "RestyleTracker.h"
    12 #include "nsStyleChangeList.h"
    13 #include "RestyleManager.h"
    14 #include "GeckoProfiler.h"
    16 namespace mozilla {
    18 inline nsIDocument*
    19 RestyleTracker::Document() const {
    20   return mRestyleManager->PresContext()->Document();
    21 }
    23 #define RESTYLE_ARRAY_STACKSIZE 128
    25 struct LaterSiblingCollector {
    26   RestyleTracker* tracker;
    27   nsTArray< nsRefPtr<dom::Element> >* elements;
    28 };
    30 static PLDHashOperator
    31 CollectLaterSiblings(nsISupports* aElement,
    32                      RestyleTracker::RestyleData& aData,
    33                      void* aSiblingCollector)
    34 {
    35   dom::Element* element =
    36     static_cast<dom::Element*>(aElement);
    37   LaterSiblingCollector* collector =
    38     static_cast<LaterSiblingCollector*>(aSiblingCollector);
    39   // Only collect the entries that actually need restyling by us (and
    40   // haven't, for example, already been restyled).
    41   // It's important to not mess with the flags on entries not in our
    42   // document.
    43   if (element->GetCurrentDoc() == collector->tracker->Document() &&
    44       element->HasFlag(collector->tracker->RestyleBit()) &&
    45       (aData.mRestyleHint & eRestyle_LaterSiblings)) {
    46     collector->elements->AppendElement(element);
    47   }
    49   return PL_DHASH_NEXT;
    50 }
    52 struct RestyleCollector {
    53   RestyleTracker* tracker;
    54   RestyleTracker::RestyleEnumerateData** restyleArrayPtr;
    55 };
    57 static PLDHashOperator
    58 CollectRestyles(nsISupports* aElement,
    59                 RestyleTracker::RestyleData& aData,
    60                 void* aRestyleCollector)
    61 {
    62   dom::Element* element =
    63     static_cast<dom::Element*>(aElement);
    64   RestyleCollector* collector =
    65     static_cast<RestyleCollector*>(aRestyleCollector);
    66   // Only collect the entries that actually need restyling by us (and
    67   // haven't, for example, already been restyled).
    68   // It's important to not mess with the flags on entries not in our
    69   // document.
    70   if (element->GetCurrentDoc() != collector->tracker->Document() ||
    71       !element->HasFlag(collector->tracker->RestyleBit())) {
    72     return PL_DHASH_NEXT;
    73   }
    75   NS_ASSERTION(!element->HasFlag(collector->tracker->RootBit()) ||
    76                // Maybe we're just not reachable via the frame tree?
    77                (element->GetFlattenedTreeParent() &&
    78                 (!element->GetFlattenedTreeParent()->GetPrimaryFrame()||
    79                  element->GetFlattenedTreeParent()->GetPrimaryFrame()->IsLeaf())) ||
    80                // Or not reachable due to an async reinsert we have
    81                // pending?  If so, we'll have a reframe hint around.
    82                // That incidentally makes it safe that we still have
    83                // the bit, since any descendants that didn't get added
    84                // to the roots list because we had the bits will be
    85                // completely restyled in a moment.
    86                (aData.mChangeHint & nsChangeHint_ReconstructFrame),
    87                "Why did this not get handled while processing mRestyleRoots?");
    89   // Unset the restyle bits now, so if they get readded later as we
    90   // process we won't clobber that adding of the bit.
    91   element->UnsetFlags(collector->tracker->RestyleBit() |
    92                       collector->tracker->RootBit());
    94   RestyleTracker::RestyleEnumerateData** restyleArrayPtr =
    95     collector->restyleArrayPtr;
    96   RestyleTracker::RestyleEnumerateData* currentRestyle =
    97     *restyleArrayPtr;
    98   currentRestyle->mElement = element;
    99   currentRestyle->mRestyleHint = aData.mRestyleHint;
   100   currentRestyle->mChangeHint = aData.mChangeHint;
   102   // Increment to the next slot in the array
   103   *restyleArrayPtr = currentRestyle + 1;
   105   return PL_DHASH_NEXT;
   106 }
   108 inline void
   109 RestyleTracker::ProcessOneRestyle(Element* aElement,
   110                                   nsRestyleHint aRestyleHint,
   111                                   nsChangeHint aChangeHint)
   112 {
   113   NS_PRECONDITION((aRestyleHint & eRestyle_LaterSiblings) == 0,
   114                   "Someone should have handled this before calling us");
   115   NS_PRECONDITION(Document(), "Must have a document");
   116   NS_PRECONDITION(aElement->GetCurrentDoc() == Document(),
   117                   "Element has unexpected document");
   119   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
   120   if (aRestyleHint & (eRestyle_Self | eRestyle_Subtree)) {
   121     mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
   122                                     *this,
   123                                     (aRestyleHint & eRestyle_Subtree) != 0);
   124   } else if (aChangeHint &&
   125              (primaryFrame ||
   126               (aChangeHint & nsChangeHint_ReconstructFrame))) {
   127     // Don't need to recompute style; just apply the hint
   128     nsStyleChangeList changeList;
   129     changeList.AppendChange(primaryFrame, aElement, aChangeHint);
   130     mRestyleManager->ProcessRestyledFrames(changeList);
   131   }
   132 }
   134 void
   135 RestyleTracker::DoProcessRestyles()
   136 {
   137   PROFILER_LABEL("CSS", "ProcessRestyles");
   139   mRestyleManager->BeginProcessingRestyles();
   141   // loop so that we process any restyle events generated by processing
   142   while (mPendingRestyles.Count()) {
   143     if (mHaveLaterSiblingRestyles) {
   144       // Convert them to individual restyles on all the later siblings
   145       nsAutoTArray<nsRefPtr<Element>, RESTYLE_ARRAY_STACKSIZE> laterSiblingArr;
   146       LaterSiblingCollector siblingCollector = { this, &laterSiblingArr };
   147       mPendingRestyles.Enumerate(CollectLaterSiblings, &siblingCollector);
   148       for (uint32_t i = 0; i < laterSiblingArr.Length(); ++i) {
   149         Element* element = laterSiblingArr[i];
   150         for (nsIContent* sibling = element->GetNextSibling();
   151              sibling;
   152              sibling = sibling->GetNextSibling()) {
   153           if (sibling->IsElement() &&
   154               AddPendingRestyle(sibling->AsElement(), eRestyle_Subtree,
   155                                 NS_STYLE_HINT_NONE)) {
   156               // Nothing else to do here; we'll handle the following
   157               // siblings when we get to |sibling| in laterSiblingArr.
   158             break;
   159           }
   160         }
   161       }
   163       // Now remove all those eRestyle_LaterSiblings bits
   164       for (uint32_t i = 0; i < laterSiblingArr.Length(); ++i) {
   165         Element* element = laterSiblingArr[i];
   166         NS_ASSERTION(element->HasFlag(RestyleBit()), "How did that happen?");
   167         RestyleData data;
   168 #ifdef DEBUG
   169         bool found =
   170 #endif
   171           mPendingRestyles.Get(element, &data);
   172         NS_ASSERTION(found, "Where did our entry go?");
   173         data.mRestyleHint =
   174           nsRestyleHint(data.mRestyleHint & ~eRestyle_LaterSiblings);
   176         mPendingRestyles.Put(element, data);
   177       }
   179       mHaveLaterSiblingRestyles = false;
   180     }
   182     uint32_t rootCount;
   183     while ((rootCount = mRestyleRoots.Length())) {
   184       // Make sure to pop the element off our restyle root array, so
   185       // that we can freely append to the array as we process this
   186       // element.
   187       nsRefPtr<Element> element;
   188       element.swap(mRestyleRoots[rootCount - 1]);
   189       mRestyleRoots.RemoveElementAt(rootCount - 1);
   191       // Do the document check before calling GetRestyleData, since we
   192       // don't want to do the sibling-processing GetRestyleData does if
   193       // the node is no longer relevant.
   194       if (element->GetCurrentDoc() != Document()) {
   195         // Content node has been removed from our document; nothing else
   196         // to do here
   197         continue;
   198       }
   200       RestyleData data;
   201       if (!GetRestyleData(element, &data)) {
   202         continue;
   203       }
   205       ProcessOneRestyle(element, data.mRestyleHint, data.mChangeHint);
   206     }
   208     if (mHaveLaterSiblingRestyles) {
   209       // Keep processing restyles for now
   210       continue;
   211     }
   213     // Now we only have entries with change hints left.  To be safe in
   214     // case of reentry from the handing of the change hint, use a
   215     // scratch array instead of calling out to ProcessOneRestyle while
   216     // enumerating the hashtable.  Use the stack if we can, otherwise
   217     // fall back on heap-allocation.
   218     nsAutoTArray<RestyleEnumerateData, RESTYLE_ARRAY_STACKSIZE> restyleArr;
   219     RestyleEnumerateData* restylesToProcess =
   220       restyleArr.AppendElements(mPendingRestyles.Count());
   221     if (restylesToProcess) {
   222       RestyleEnumerateData* lastRestyle = restylesToProcess;
   223       RestyleCollector collector = { this, &lastRestyle };
   224       mPendingRestyles.Enumerate(CollectRestyles, &collector);
   226       // Clear the hashtable now that we don't need it anymore
   227       mPendingRestyles.Clear();
   229       for (RestyleEnumerateData* currentRestyle = restylesToProcess;
   230            currentRestyle != lastRestyle;
   231            ++currentRestyle) {
   232         ProcessOneRestyle(currentRestyle->mElement,
   233                           currentRestyle->mRestyleHint,
   234                           currentRestyle->mChangeHint);
   235       }
   236     }
   237   }
   239   mRestyleManager->EndProcessingRestyles();
   240 }
   242 bool
   243 RestyleTracker::GetRestyleData(Element* aElement, RestyleData* aData)
   244 {
   245   NS_PRECONDITION(aElement->GetCurrentDoc() == Document(),
   246                   "Unexpected document; this will lead to incorrect behavior!");
   248   if (!aElement->HasFlag(RestyleBit())) {
   249     NS_ASSERTION(!aElement->HasFlag(RootBit()), "Bogus root bit?");
   250     return false;
   251   }
   253 #ifdef DEBUG
   254   bool gotData =
   255 #endif
   256   mPendingRestyles.Get(aElement, aData);
   257   NS_ASSERTION(gotData, "Must have data if restyle bit is set");
   259   if (aData->mRestyleHint & eRestyle_LaterSiblings) {
   260     // Someone readded the eRestyle_LaterSiblings hint for this
   261     // element.  Leave it around for now, but remove the other restyle
   262     // hints and the change hint for it.  Also unset its root bit,
   263     // since it's no longer a root with the new restyle data.
   264     RestyleData newData;
   265     newData.mChangeHint = nsChangeHint(0);
   266     newData.mRestyleHint = eRestyle_LaterSiblings;
   267     mPendingRestyles.Put(aElement, newData);
   268     aElement->UnsetFlags(RootBit());
   269     aData->mRestyleHint =
   270       nsRestyleHint(aData->mRestyleHint & ~eRestyle_LaterSiblings);
   271   } else {
   272     mPendingRestyles.Remove(aElement);
   273     aElement->UnsetFlags(mRestyleBits);
   274   }
   276   return true;
   277 }
   279 } // namespace mozilla

mercurial