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-06-02 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