layout/base/nsCounterManager.h

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: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 // vim:cindent:ai:sw=4:ts=4:et:
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* implementation of CSS counters (for numbering things) */
     9 #ifndef nsCounterManager_h_
    10 #define nsCounterManager_h_
    12 #include "mozilla/Attributes.h"
    13 #include "nsGenConList.h"
    14 #include "nsAutoPtr.h"
    15 #include "nsClassHashtable.h"
    16 #include "mozilla/Likely.h"
    18 class nsCounterList;
    19 struct nsCounterUseNode;
    20 struct nsCounterChangeNode;
    22 struct nsCounterNode : public nsGenConNode {
    23     enum Type {
    24         RESET,     // a "counter number" pair in 'counter-reset'
    25         INCREMENT, // a "counter number" pair in 'counter-increment'
    26         USE        // counter() or counters() in 'content'
    27     };
    29     Type mType;
    31     // Counter value after this node
    32     int32_t mValueAfter;
    34     // mScopeStart points to the node (usually a RESET, but not in the
    35     // case of an implied 'counter-reset') that created the scope for
    36     // this element (for a RESET, its outer scope, i.e., the one it is
    37     // inside rather than the one it creates).
    39     // May be null for all types, but only when mScopePrev is also null.
    40     // Being null for a non-RESET means that it is an implied
    41     // 'counter-reset'.  Being null for a RESET means it has no outer
    42     // scope.
    43     nsCounterNode *mScopeStart;
    45     // mScopePrev points to the previous node that is in the same scope,
    46     // or for a RESET, the previous node in the scope outside of the
    47     // reset.
    49     // May be null for all types, but only when mScopeStart is also
    50     // null.  Following the mScopePrev links will eventually lead to
    51     // mScopeStart.  Being null for a non-RESET means that it is an
    52     // implied 'counter-reset'.  Being null for a RESET means it has no
    53     // outer scope.
    54     nsCounterNode *mScopePrev;
    56     inline nsCounterUseNode* UseNode();
    57     inline nsCounterChangeNode* ChangeNode();
    59     // For RESET and INCREMENT nodes, aPseudoFrame need not be a
    60     // pseudo-element, and aContentIndex represents the index within the
    61     // 'counter-reset' or 'counter-increment' property instead of within
    62     // the 'content' property but offset to ensure that (reset,
    63     // increment, use) sort in that order.  (This slight weirdness
    64     // allows sharing a lot of code with 'quotes'.)
    65     nsCounterNode(int32_t aContentIndex, Type aType)
    66         : nsGenConNode(aContentIndex)
    67         , mType(aType)
    68         , mValueAfter(0)
    69         , mScopeStart(nullptr)
    70         , mScopePrev(nullptr)
    71     {
    72     }
    74     // to avoid virtual function calls in the common case
    75     inline void Calc(nsCounterList* aList);
    76 };
    78 struct nsCounterUseNode : public nsCounterNode {
    79     // The same structure passed through the style system:  an array
    80     // containing the values in the counter() or counters() in the order
    81     // given in the CSS spec.
    82     nsRefPtr<nsCSSValue::Array> mCounterStyle;
    84     // false for counter(), true for counters()
    85     bool mAllCounters;
    87     // args go directly to member variables here and of nsGenConNode
    88     nsCounterUseNode(nsCSSValue::Array* aCounterStyle,
    89                      uint32_t aContentIndex, bool aAllCounters)
    90         : nsCounterNode(aContentIndex, USE)
    91         , mCounterStyle(aCounterStyle)
    92         , mAllCounters(aAllCounters)
    93     {
    94         NS_ASSERTION(aContentIndex <= INT32_MAX, "out of range");
    95     }
    97     virtual bool InitTextFrame(nsGenConList* aList,
    98             nsIFrame* aPseudoFrame, nsIFrame* aTextFrame) MOZ_OVERRIDE;
   100     // assign the correct |mValueAfter| value to a node that has been inserted
   101     // Should be called immediately after calling |Insert|.
   102     void Calc(nsCounterList* aList);
   104     // The text that should be displayed for this counter.
   105     void GetText(nsString& aResult);
   106 };
   108 struct nsCounterChangeNode : public nsCounterNode {
   109     int32_t mChangeValue; // the numeric value of the increment or reset
   111     // |aPseudoFrame| is not necessarily a pseudo-element's frame, but
   112     // since it is for every other subclass of nsGenConNode, we follow
   113     // the naming convention here.
   114     // |aPropIndex| is the index of the value within the list in the
   115     // 'counter-increment' or 'counter-reset' property.
   116     nsCounterChangeNode(nsIFrame* aPseudoFrame,
   117                         nsCounterNode::Type aChangeType,
   118                         int32_t aChangeValue,
   119                         int32_t aPropIndex)
   120         : nsCounterNode(// Fake a content index for resets and increments
   121                         // that comes before all the real content, with
   122                         // the resets first, in order, and then the increments.
   123                         aPropIndex + (aChangeType == RESET
   124                                         ? (INT32_MIN) 
   125                                         : (INT32_MIN / 2)),
   126                         aChangeType)
   127         , mChangeValue(aChangeValue)
   128     {
   129         NS_ASSERTION(aPropIndex >= 0, "out of range");
   130         NS_ASSERTION(aChangeType == INCREMENT || aChangeType == RESET,
   131                      "bad type");
   132         mPseudoFrame = aPseudoFrame;
   133         CheckFrameAssertions();
   134     }
   136     // assign the correct |mValueAfter| value to a node that has been inserted
   137     // Should be called immediately after calling |Insert|.
   138     void Calc(nsCounterList* aList);
   139 };
   141 inline nsCounterUseNode* nsCounterNode::UseNode()
   142 {
   143     NS_ASSERTION(mType == USE, "wrong type");
   144     return static_cast<nsCounterUseNode*>(this);
   145 }
   147 inline nsCounterChangeNode* nsCounterNode::ChangeNode()
   148 {
   149     NS_ASSERTION(mType == INCREMENT || mType == RESET, "wrong type");
   150     return static_cast<nsCounterChangeNode*>(this);
   151 }
   153 inline void nsCounterNode::Calc(nsCounterList* aList)
   154 {
   155     if (mType == USE)
   156         UseNode()->Calc(aList);
   157     else
   158         ChangeNode()->Calc(aList);
   159 }
   161 class nsCounterList : public nsGenConList {
   162 public:
   163     nsCounterList() : nsGenConList(),
   164                       mDirty(false)
   165     {}
   167     void Insert(nsCounterNode* aNode) {
   168         nsGenConList::Insert(aNode);
   169         // Don't SetScope if we're dirty -- we'll reset all the scopes anyway,
   170         // and we can't usefully compute scopes right now.
   171         if (MOZ_LIKELY(!IsDirty())) {
   172             SetScope(aNode);
   173         }
   174     }
   176     nsCounterNode* First() {
   177         return static_cast<nsCounterNode*>(mFirstNode);
   178     }
   180     static nsCounterNode* Next(nsCounterNode* aNode) {
   181         return static_cast<nsCounterNode*>(nsGenConList::Next(aNode));
   182     }
   183     static nsCounterNode* Prev(nsCounterNode* aNode) {
   184         return static_cast<nsCounterNode*>(nsGenConList::Prev(aNode));
   185     }
   187     static int32_t ValueBefore(nsCounterNode* aNode) {
   188         return aNode->mScopePrev ? aNode->mScopePrev->mValueAfter : 0;
   189     }
   191     // Correctly set |aNode->mScopeStart| and |aNode->mScopePrev|
   192     void SetScope(nsCounterNode *aNode);
   194     // Recalculate |mScopeStart|, |mScopePrev|, and |mValueAfter| for
   195     // all nodes and update text in text content nodes.
   196     void RecalcAll();
   198     bool IsDirty() { return mDirty; }
   199     void SetDirty() { mDirty = true; }
   201 private:
   202     bool mDirty;
   203 };
   205 /**
   206  * The counter manager maintains an |nsCounterList| for each named
   207  * counter to keep track of all scopes with that name.
   208  */
   209 class nsCounterManager {
   210 public:
   211     nsCounterManager();
   212     // Returns true if dirty
   213     bool AddCounterResetsAndIncrements(nsIFrame *aFrame);
   215     // Gets the appropriate counter list, creating it if necessary.
   216     // Returns null only on out-of-memory.
   217     nsCounterList* CounterListFor(const nsSubstring& aCounterName);
   219     // Clean up data in any dirty counter lists.
   220     void RecalcAll();
   222     // Destroy nodes for the frame in any lists, and return whether any
   223     // nodes were destroyed.
   224     bool DestroyNodesFor(nsIFrame *aFrame);
   226     // Clear all data.
   227     void Clear() { mNames.Clear(); }
   229 #ifdef DEBUG
   230     void Dump();
   231 #endif
   233     static int32_t IncrementCounter(int32_t aOldValue, int32_t aIncrement)
   234     {
   235         // Addition of unsigned values is defined to be arithmetic
   236         // modulo 2^bits (C++ 2011, 3.9.1 [basic.fundamental], clause 4);
   237         // addition of signed values is undefined (and clang does
   238         // something very strange if we use it here).  Likewise integral
   239         // conversion from signed to unsigned is also defined as modulo
   240         // 2^bits (C++ 2011, 4.7 [conv.integral], clause 2); conversion
   241         // from unsigned to signed is however undefined (ibid., clause 3),
   242         // but to do what we want we must nonetheless depend on that
   243         // small piece of undefined behavior.
   244         int32_t newValue = int32_t(uint32_t(aOldValue) + uint32_t(aIncrement));
   245         // The CSS Working Group resolved that a counter-increment that
   246         // exceeds internal limits should not increment at all.
   247         // http://lists.w3.org/Archives/Public/www-style/2013Feb/0392.html
   248         // (This means, for example, that if aIncrement is 5, the
   249         // counter will get stuck at the largest multiple of 5 less than
   250         // the maximum 32-bit integer.)
   251         if ((aIncrement > 0) != (newValue > aOldValue)) {
   252           newValue = aOldValue;
   253         }
   254         return newValue;
   255     }
   257 private:
   258     // for |AddCounterResetsAndIncrements| only
   259     bool AddResetOrIncrement(nsIFrame *aFrame, int32_t aIndex,
   260                                const nsStyleCounterData *aCounterData,
   261                                nsCounterNode::Type aType);
   263     nsClassHashtable<nsStringHashKey, nsCounterList> mNames;
   264 };
   266 #endif /* nsCounterManager_h_ */

mercurial