layout/style/nsNthIndexCache.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     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 that computes and caches the indices used for :nth-* pseudo-class
     8  * matching.
     9  */
    11 #include "nsNthIndexCache.h"
    12 #include "mozilla/dom/Element.h"
    14 nsNthIndexCache::nsNthIndexCache()
    15 {
    16 }
    18 nsNthIndexCache::~nsNthIndexCache()
    19 {
    20 }
    22 void
    23 nsNthIndexCache::Reset()
    24 {
    25   mCaches[0][0].clear();
    26   mCaches[0][1].clear();
    27   mCaches[1][0].clear();
    28   mCaches[1][1].clear();
    29 }
    31 inline bool
    32 nsNthIndexCache::SiblingMatchesElement(nsIContent* aSibling, Element* aElement,
    33                                        bool aIsOfType)
    34 {
    35   return aSibling->IsElement() &&
    36     (!aIsOfType ||
    37      aSibling->NodeInfo()->NameAndNamespaceEquals(aElement->NodeInfo()));
    38 }
    40 inline bool
    41 nsNthIndexCache::IndexDeterminedFromPreviousSibling(nsIContent* aSibling,
    42                                                     Element* aChild,
    43                                                     bool aIsOfType,
    44                                                     bool aIsFromEnd,
    45                                                     const Cache& aCache,
    46                                                     int32_t& aResult)
    47 {
    48   if (SiblingMatchesElement(aSibling, aChild, aIsOfType)) {
    49     Cache::Ptr siblingEntry = aCache.lookup(aSibling);
    50     if (siblingEntry) {
    51       int32_t siblingIndex = siblingEntry->value();
    52       NS_ASSERTION(siblingIndex != 0,
    53                    "How can a non-anonymous node have an anonymous sibling?");
    54       if (siblingIndex > 0) {
    55         // At this point, aResult is a count of how many elements matching
    56         // aChild we have seen after aSibling, including aChild itself.
    57         // |siblingIndex| is the index of aSibling.
    58         // So if aIsFromEnd, we want |aResult = siblingIndex - aResult| and
    59         // otherwise we want |aResult = siblingIndex + aResult|.
    60         aResult = siblingIndex + aResult * (1 - 2 * aIsFromEnd);
    61         return true;
    62       }
    63     }
    65     ++aResult;
    66   }
    68   return false;
    69 }
    71 int32_t
    72 nsNthIndexCache::GetNthIndex(Element* aChild, bool aIsOfType,
    73                              bool aIsFromEnd, bool aCheckEdgeOnly)
    74 {
    75   NS_ASSERTION(aChild->GetParent(), "caller should check GetParent()");
    77   if (aChild->IsRootOfAnonymousSubtree()) {
    78     return 0;
    79   }
    81   Cache &cache = mCaches[aIsOfType][aIsFromEnd];
    83   if (!cache.initialized() && !cache.init()) {
    84     // Give up and just don't match.
    85     return 0;
    86   }
    88   Cache::AddPtr entry = cache.lookupForAdd(aChild);
    90   // Default the value to -2 when adding
    91   if (!entry && !cache.add(entry, aChild, -2)) {
    92     // No good; don't match.
    93     return 0;
    94   }
    96   int32_t &slot = entry->value();
    97   if (slot != -2 && (slot != -1 || aCheckEdgeOnly)) {
    98     return slot;
    99   }
   101   int32_t result = 1;
   102   if (aCheckEdgeOnly) {
   103     // The caller only cares whether or not the result is 1, so we can
   104     // stop as soon as we see any other elements that match us.
   105     if (aIsFromEnd) {
   106       for (nsIContent *cur = aChild->GetNextSibling();
   107            cur;
   108            cur = cur->GetNextSibling()) {
   109         if (SiblingMatchesElement(cur, aChild, aIsOfType)) {
   110           result = -1;
   111           break;
   112         }
   113       }
   114     } else {
   115       for (nsIContent *cur = aChild->GetPreviousSibling();
   116            cur;
   117            cur = cur->GetPreviousSibling()) {
   118         if (SiblingMatchesElement(cur, aChild, aIsOfType)) {
   119           result = -1;
   120           break;
   121         }
   122       }
   123     }
   124   } else {
   125     // In the common case, we already have a cached index for one of
   126     // our previous siblings, so check that first.
   127     for (nsIContent *cur = aChild->GetPreviousSibling();
   128          cur;
   129          cur = cur->GetPreviousSibling()) {
   130       if (IndexDeterminedFromPreviousSibling(cur, aChild, aIsOfType,
   131                                              aIsFromEnd, cache, result)) {
   132         slot = result;
   133         return result;
   134       }
   135     }
   137     // Now if aIsFromEnd we lose: need to actually compute our index,
   138     // since looking at previous siblings wouldn't have told us
   139     // anything about it.  Note that it doesn't make sense to do cache
   140     // lookups on our following siblings, since chances are the cache
   141     // is not primed for them.
   142     if (aIsFromEnd) {
   143       result = 1;
   144       for (nsIContent *cur = aChild->GetNextSibling();
   145            cur;
   146            cur = cur->GetNextSibling()) {
   147         if (SiblingMatchesElement(cur, aChild, aIsOfType)) {
   148           ++result;
   149         }
   150       }
   151     }
   152   }
   154   slot = result;
   155   return result;
   156 }

mercurial