LCOV - app.info - layout/base/RestyleTracker.cpp

LCOV - code coverage report
| Current view: | directory - layout/base - RestyleTracker.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 101 | 0 | 0.0 %
| Date: | 2012-04-21 | Functions: | 6 | 0 | 0.0 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is mozilla.org code.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * the Mozilla Foundation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 2010
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *     Boris Zbarsky <bzbarsky@mit.edu> (original author)
          24                 :  *
          25                 :  * Alternatively, the contents of this file may be used under the terms of
          26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          29                 :  * of those above. If you wish to allow use of your version of this file only
          30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          31                 :  * use your version of this file under the terms of the MPL, indicate your
          32                 :  * decision by deleting the provisions above and replace them with the notice
          33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          34                 :  * the provisions above, a recipient may use your version of this file under
          35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          36                 :  *
          37                 :  * ***** END LICENSE BLOCK ***** */
          38                 :
          39                 : /**
          40                 :  * A class which manages pending restyles.  This handles keeping track
          41                 :  * of what nodes restyles need to happen on and so forth.
          42                 :  */
          43                 :
          44                 : #include "RestyleTracker.h"
          45                 : #include "nsCSSFrameConstructor.h"
          46                 : #include "nsStyleChangeList.h"
          47                 : #include "sampler.h"
          48                 :
          49                 : namespace mozilla {
          50                 : namespace css {
          51                 :
          52                 : inline nsIDocument*
          53               0 : RestyleTracker::Document() const {
          54               0 :   return mFrameConstructor->mDocument;
          55                 : }
          56                 :
          57                 : #define RESTYLE_ARRAY_STACKSIZE 128
          58                 :
          59                 : struct LaterSiblingCollector {
          60                 :   RestyleTracker* tracker;
          61                 :   nsTArray< nsRefPtr<dom::Element> >* elements;
          62                 : };
          63                 :
          64                 : static PLDHashOperator
          65               0 : CollectLaterSiblings(nsISupports* aElement,
          66                 :                      RestyleTracker::RestyleData& aData,
          67                 :                      void* aSiblingCollector)
          68                 : {
          69                 :   dom::Element* element =
          70               0 :     static_cast<dom::Element*>(aElement);
          71                 :   LaterSiblingCollector* collector =
          72               0 :     static_cast<LaterSiblingCollector*>(aSiblingCollector);
          73                 :   // Only collect the entries that actually need restyling by us (and
          74                 :   // haven't, for example, already been restyled).
          75                 :   // It's important to not mess with the flags on entries not in our
          76                 :   // document.
          77               0 :   if (element->GetCurrentDoc() == collector->tracker->Document() &&
          78               0 :       element->HasFlag(collector->tracker->RestyleBit()) &&
          79                 :       (aData.mRestyleHint & eRestyle_LaterSiblings)) {
          80               0 :     collector->elements->AppendElement(element);
          81                 :   }
          82                 :
          83               0 :   return PL_DHASH_NEXT;
          84                 : }
          85                 :
          86                 : struct RestyleCollector {
          87                 :   RestyleTracker* tracker;
          88                 :   RestyleTracker::RestyleEnumerateData** restyleArrayPtr;
          89                 : };
          90                 :
          91                 : static PLDHashOperator
          92               0 : CollectRestyles(nsISupports* aElement,
          93                 :                 RestyleTracker::RestyleData& aData,
          94                 :                 void* aRestyleCollector)
          95                 : {
          96                 :   dom::Element* element =
          97               0 :     static_cast<dom::Element*>(aElement);
          98                 :   RestyleCollector* collector =
          99               0 :     static_cast<RestyleCollector*>(aRestyleCollector);
         100                 :   // Only collect the entries that actually need restyling by us (and
         101                 :   // haven't, for example, already been restyled).
         102                 :   // It's important to not mess with the flags on entries not in our
         103                 :   // document.
         104               0 :   if (element->GetCurrentDoc() != collector->tracker->Document() ||
         105               0 :       !element->HasFlag(collector->tracker->RestyleBit())) {
         106               0 :     return PL_DHASH_NEXT;
         107                 :   }
         108                 :
         109               0 :   NS_ASSERTION(!element->HasFlag(collector->tracker->RootBit()) ||
         110                 :                // Maybe we're just not reachable via the frame tree?
         111                 :                (element->GetFlattenedTreeParent() &&
         112                 :                 (!element->GetFlattenedTreeParent()->GetPrimaryFrame()||
         113                 :                  element->GetFlattenedTreeParent()->GetPrimaryFrame()->IsLeaf())) ||
         114                 :                // Or not reachable due to an async reinsert we have
         115                 :                // pending?  If so, we'll have a reframe hint around.
         116                 :                // That incidentally makes it safe that we still have
         117                 :                // the bit, since any descendants that didn't get added
         118                 :                // to the roots list because we had the bits will be
         119                 :                // completely restyled in a moment.
         120                 :                (aData.mChangeHint & nsChangeHint_ReconstructFrame),
         121                 :                "Why did this not get handled while processing mRestyleRoots?");
         122                 :
         123                 :   // Unset the restyle bits now, so if they get readded later as we
         124                 :   // process we won't clobber that adding of the bit.
         125               0 :   element->UnsetFlags(collector->tracker->RestyleBit() |
         126               0 :                       collector->tracker->RootBit());
         127                 :
         128                 :   RestyleTracker::RestyleEnumerateData** restyleArrayPtr =
         129               0 :     collector->restyleArrayPtr;
         130                 :   RestyleTracker::RestyleEnumerateData* currentRestyle =
         131               0 :     *restyleArrayPtr;
         132               0 :   currentRestyle->mElement = element;
         133               0 :   currentRestyle->mRestyleHint = aData.mRestyleHint;
         134               0 :   currentRestyle->mChangeHint = aData.mChangeHint;
         135                 :
         136                 :   // Increment to the next slot in the array
         137               0 :   *restyleArrayPtr = currentRestyle + 1;
         138                 :
         139               0 :   return PL_DHASH_NEXT;
         140                 : }
         141                 :
         142                 : inline void
         143               0 : RestyleTracker::ProcessOneRestyle(Element* aElement,
         144                 :                                   nsRestyleHint aRestyleHint,
         145                 :                                   nsChangeHint aChangeHint)
         146                 : {
         147               0 :   NS_PRECONDITION((aRestyleHint & eRestyle_LaterSiblings) == 0,
         148                 :                   "Someone should have handled this before calling us");
         149               0 :   NS_PRECONDITION(Document(), "Must have a document");
         150               0 :   NS_PRECONDITION(aElement->GetCurrentDoc() == Document(),
         151                 :                   "Element has unexpected document");
         152                 :
         153               0 :   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
         154               0 :   if (aRestyleHint & (eRestyle_Self | eRestyle_Subtree)) {
         155                 :     mFrameConstructor->RestyleElement(aElement, primaryFrame, aChangeHint,
         156                 :                                       *this,
         157               0 :                                       (aRestyleHint & eRestyle_Subtree) != 0);
         158               0 :   } else if (aChangeHint &&
         159                 :              (primaryFrame ||
         160                 :               (aChangeHint & nsChangeHint_ReconstructFrame))) {
         161                 :     // Don't need to recompute style; just apply the hint
         162               0 :     nsStyleChangeList changeList;
         163               0 :     changeList.AppendChange(primaryFrame, aElement, aChangeHint);
         164               0 :     mFrameConstructor->ProcessRestyledFrames(changeList);
         165                 :   }
         166               0 : }
         167                 :
         168                 : void
         169               0 : RestyleTracker::DoProcessRestyles()
         170                 : {
         171               0 :   SAMPLE_LABEL("CSS", "ProcessRestyles");
         172                 :   // Make sure to not rebuild quote or counter lists while we're
         173                 :   // processing restyles
         174               0 :   mFrameConstructor->BeginUpdate();
         175                 :
         176               0 :   mFrameConstructor->mInStyleRefresh = true;
         177                 :
         178                 :   // loop so that we process any restyle events generated by processing
         179               0 :   while (mPendingRestyles.Count()) {
         180               0 :     if (mHaveLaterSiblingRestyles) {
         181                 :       // Convert them to individual restyles on all the later siblings
         182               0 :       nsAutoTArray<nsRefPtr<Element>, RESTYLE_ARRAY_STACKSIZE> laterSiblingArr;
         183               0 :       LaterSiblingCollector siblingCollector = { this, &laterSiblingArr };
         184               0 :       mPendingRestyles.Enumerate(CollectLaterSiblings, &siblingCollector);
         185               0 :       for (PRUint32 i = 0; i < laterSiblingArr.Length(); ++i) {
         186               0 :         Element* element = laterSiblingArr[i];
         187               0 :         for (nsIContent* sibling = element->GetNextSibling();
         188                 :              sibling;
         189               0 :              sibling = sibling->GetNextSibling()) {
         190               0 :           if (sibling->IsElement() &&
         191                 :               AddPendingRestyle(sibling->AsElement(), eRestyle_Subtree,
         192               0 :                                 NS_STYLE_HINT_NONE)) {
         193                 :               // Nothing else to do here; we'll handle the following
         194                 :               // siblings when we get to |sibling| in laterSiblingArr.
         195               0 :             break;
         196                 :           }
         197                 :         }
         198                 :       }
         199                 :
         200                 :       // Now remove all those eRestyle_LaterSiblings bits
         201               0 :       for (PRUint32 i = 0; i < laterSiblingArr.Length(); ++i) {
         202               0 :         Element* element = laterSiblingArr[i];
         203               0 :         NS_ASSERTION(element->HasFlag(RestyleBit()), "How did that happen?");
         204                 :         RestyleData data;
         205                 : #ifdef DEBUG
         206                 :         bool found =
         207                 : #endif
         208               0 :           mPendingRestyles.Get(element, &data);
         209               0 :         NS_ASSERTION(found, "Where did our entry go?");
         210                 :         data.mRestyleHint =
         211               0 :           nsRestyleHint(data.mRestyleHint & ~eRestyle_LaterSiblings);
         212                 :
         213               0 :         mPendingRestyles.Put(element, data);
         214                 :       }
         215                 :
         216               0 :       mHaveLaterSiblingRestyles = false;
         217                 :     }
         218                 :
         219                 :     PRUint32 rootCount;
         220               0 :     while ((rootCount = mRestyleRoots.Length())) {
         221                 :       // Make sure to pop the element off our restyle root array, so
         222                 :       // that we can freely append to the array as we process this
         223                 :       // element.
         224               0 :       nsRefPtr<Element> element;
         225               0 :       element.swap(mRestyleRoots[rootCount - 1]);
         226               0 :       mRestyleRoots.RemoveElementAt(rootCount - 1);
         227                 :
         228                 :       // Do the document check before calling GetRestyleData, since we
         229                 :       // don't want to do the sibling-processing GetRestyleData does if
         230                 :       // the node is no longer relevant.
         231               0 :       if (element->GetCurrentDoc() != Document()) {
         232                 :         // Content node has been removed from our document; nothing else
         233                 :         // to do here
         234               0 :         continue;
         235                 :       }
         236                 :
         237                 :       RestyleData data;
         238               0 :       if (!GetRestyleData(element, &data)) {
         239               0 :         continue;
         240                 :       }
         241                 :
         242               0 :       ProcessOneRestyle(element, data.mRestyleHint, data.mChangeHint);
         243                 :     }
         244                 :
         245               0 :     if (mHaveLaterSiblingRestyles) {
         246                 :       // Keep processing restyles for now
         247               0 :       continue;
         248                 :     }
         249                 :
         250                 :     // Now we only have entries with change hints left.  To be safe in
         251                 :     // case of reentry from the handing of the change hint, use a
         252                 :     // scratch array instead of calling out to ProcessOneRestyle while
         253                 :     // enumerating the hashtable.  Use the stack if we can, otherwise
         254                 :     // fall back on heap-allocation.
         255               0 :     nsAutoTArray<RestyleEnumerateData, RESTYLE_ARRAY_STACKSIZE> restyleArr;
         256                 :     RestyleEnumerateData* restylesToProcess =
         257               0 :       restyleArr.AppendElements(mPendingRestyles.Count());
         258               0 :     if (restylesToProcess) {
         259               0 :       RestyleEnumerateData* lastRestyle = restylesToProcess;
         260               0 :       RestyleCollector collector = { this, &lastRestyle };
         261               0 :       mPendingRestyles.Enumerate(CollectRestyles, &collector);
         262                 :
         263                 :       // Clear the hashtable now that we don't need it anymore
         264               0 :       mPendingRestyles.Clear();
         265                 :
         266               0 :       for (RestyleEnumerateData* currentRestyle = restylesToProcess;
         267                 :            currentRestyle != lastRestyle;
         268                 :            ++currentRestyle) {
         269                 :         ProcessOneRestyle(currentRestyle->mElement,
         270                 :                           currentRestyle->mRestyleHint,
         271               0 :                           currentRestyle->mChangeHint);
         272                 :       }
         273                 :     }
         274                 :   }
         275                 :
         276                 :   // Set mInStyleRefresh to false now, since the EndUpdate call might
         277                 :   // add more restyles.
         278               0 :   mFrameConstructor->mInStyleRefresh = false;
         279                 :
         280               0 :   mFrameConstructor->EndUpdate();
         281                 :
         282                 : #ifdef DEBUG
         283               0 :   mFrameConstructor->mPresShell->VerifyStyleTree();
         284                 : #endif
         285               0 : }
         286                 :
         287                 : bool
         288               0 : RestyleTracker::GetRestyleData(Element* aElement, RestyleData* aData)
         289                 : {
         290               0 :   NS_PRECONDITION(aElement->GetCurrentDoc() == Document(),
         291                 :                   "Unexpected document; this will lead to incorrect behavior!");
         292                 :
         293               0 :   if (!aElement->HasFlag(RestyleBit())) {
         294               0 :     NS_ASSERTION(!aElement->HasFlag(RootBit()), "Bogus root bit?");
         295               0 :     return false;
         296                 :   }
         297                 :
         298                 : #ifdef DEBUG
         299                 :   bool gotData =
         300                 : #endif
         301               0 :   mPendingRestyles.Get(aElement, aData);
         302               0 :   NS_ASSERTION(gotData, "Must have data if restyle bit is set");
         303                 :
         304               0 :   if (aData->mRestyleHint & eRestyle_LaterSiblings) {
         305                 :     // Someone readded the eRestyle_LaterSiblings hint for this
         306                 :     // element.  Leave it around for now, but remove the other restyle
         307                 :     // hints and the change hint for it.  Also unset its root bit,
         308                 :     // since it's no longer a root with the new restyle data.
         309                 :     RestyleData newData;
         310               0 :     newData.mChangeHint = nsChangeHint(0);
         311               0 :     newData.mRestyleHint = eRestyle_LaterSiblings;
         312               0 :     mPendingRestyles.Put(aElement, newData);
         313               0 :     aElement->UnsetFlags(RootBit());
         314                 :     aData->mRestyleHint =
         315               0 :       nsRestyleHint(aData->mRestyleHint & ~eRestyle_LaterSiblings);
         316                 :   } else {
         317               0 :     mPendingRestyles.Remove(aElement);
         318               0 :     aElement->UnsetFlags(mRestyleBits);
         319                 :   }
         320                 :
         321               0 :   return true;
         322                 : }
         323                 :
         324                 : } // namespace css
         325                 : } // namespace mozilla
         326                 :

Generated by: LCOV version 1.7