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/. */
5 
6 /* base class for nsCounterList and nsQuoteList */
7 
8 #ifndef nsGenConList_h___
9 #define nsGenConList_h___
10 
11 #include "mozilla/LinkedList.h"
12 #include "nsIFrame.h"
13 #include "nsStyleStruct.h"
14 #include "nsCSSPseudoElements.h"
15 #include "nsTextNode.h"
16 
17 class nsGenConList;
18 
19 struct nsGenConNode : public mozilla::LinkedListElement<nsGenConNode> {
20   // The wrapper frame for all of the pseudo-element's content.  This
21   // frame generally has useful style data and has the
22   // NS_FRAME_GENERATED_CONTENT bit set (so we use it to track removal),
23   // but does not necessarily for |nsCounterChangeNode|s.
24   nsIFrame* mPseudoFrame;
25 
26   // Index within the list of things specified by the 'content' property,
27   // which is needed to do 'content: open-quote open-quote' correctly,
28   // and needed for similar cases for counters.
29   const int32_t mContentIndex;
30 
31   // null for 'content:no-open-quote', 'content:no-close-quote' and for
32   // counter nodes for increments and resets (rather than uses)
33   RefPtr<nsTextNode> mText;
34 
nsGenConNodensGenConNode35   explicit nsGenConNode(int32_t aContentIndex)
36     : mPseudoFrame(nullptr)
37     , mContentIndex(aContentIndex)
38   {
39   }
40 
41   /**
42    * Finish initializing the generated content node once we know the
43    * relevant text frame. This must be called just after
44    * the textframe has been initialized. This need not be called at all
45    * for nodes that don't generate text. This will generally set the
46    * mPseudoFrame, insert the node into aList, and set aTextFrame up
47    * with the correct text.
48    * @param aList the list the node belongs to
49    * @param aPseudoFrame the :before or :after frame
50    * @param aTextFrame the textframe where the node contents will render
51    * @return true iff this marked the list dirty
52    */
InitTextFramensGenConNode53   virtual bool InitTextFrame(nsGenConList* aList, nsIFrame* aPseudoFrame,
54                              nsIFrame* aTextFrame)
55   {
56     mPseudoFrame = aPseudoFrame;
57     CheckFrameAssertions();
58     return false;
59   }
60 
~nsGenConNodensGenConNode61   virtual ~nsGenConNode() {} // XXX Avoid, perhaps?
62 
63 protected:
CheckFrameAssertionsnsGenConNode64   void CheckFrameAssertions() {
65     NS_ASSERTION(mContentIndex <
66                    int32_t(mPseudoFrame->StyleContent()->ContentCount()),
67                  "index out of range");
68       // We allow negative values of mContentIndex for 'counter-reset' and
69       // 'counter-increment'.
70 
71     NS_ASSERTION(mContentIndex < 0 ||
72                  mPseudoFrame->StyleContext()->GetPseudo() ==
73                    nsCSSPseudoElements::before ||
74                  mPseudoFrame->StyleContext()->GetPseudo() ==
75                    nsCSSPseudoElements::after,
76                  "not :before/:after generated content and not counter change");
77     NS_ASSERTION(mContentIndex < 0 ||
78                  mPseudoFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT,
79                  "not generated content and not counter change");
80   }
81 };
82 
83 class nsGenConList {
84 protected:
85   mozilla::LinkedList<nsGenConNode> mList;
86   uint32_t mSize;
87 
88 public:
nsGenConList()89   nsGenConList() : mSize(0) {}
~nsGenConList()90   ~nsGenConList() { Clear(); }
91   void Clear();
Next(nsGenConNode * aNode)92   static nsGenConNode* Next(nsGenConNode* aNode) {
93     MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
94     return aNode->getNext();
95   }
Prev(nsGenConNode * aNode)96   static nsGenConNode* Prev(nsGenConNode* aNode) {
97     MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
98     return aNode->getPrevious();
99   }
100   void Insert(nsGenConNode* aNode);
101 
102   // Destroy all nodes with aFrame as parent. Returns true if some nodes
103   // have been destroyed; otherwise false.
104   bool DestroyNodesFor(nsIFrame* aFrame);
105 
106   // Return true if |aNode1| is after |aNode2|.
107   static bool NodeAfter(const nsGenConNode* aNode1,
108                         const nsGenConNode* aNode2);
109 
IsFirst(nsGenConNode * aNode)110   bool IsFirst(nsGenConNode* aNode) {
111     MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
112     return aNode == mList.getFirst();
113   }
114 
IsLast(nsGenConNode * aNode)115   bool IsLast(nsGenConNode* aNode) {
116     MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
117     return aNode == mList.getLast();
118   }
119 
120 private:
Destroy(nsGenConNode * aNode)121   void Destroy(nsGenConNode* aNode)
122   {
123     MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
124     delete aNode;
125     mSize--;
126   }
127 
128   // Map from frame to the first nsGenConNode of it in the list.
129   nsDataHashtable<nsPtrHashKey<nsIFrame>, nsGenConNode*> mNodes;
130 };
131 
132 #endif /* nsGenConList_h___ */
133