summaryrefslogtreecommitdiff
path: root/layout/base/nsGenConList.h
blob: 58421d4301b8b2dbc88677bed98e8f03dca49016 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* base class for nsCounterList and nsQuoteList */

#ifndef nsGenConList_h___
#define nsGenConList_h___

#include "mozilla/LinkedList.h"
#include "nsIFrame.h"
#include "nsStyleStruct.h"
#include "nsCSSPseudoElements.h"
#include "nsTextNode.h"

class nsGenConList;

struct nsGenConNode : public mozilla::LinkedListElement<nsGenConNode> {
  // The wrapper frame for all of the pseudo-element's content.  This
  // frame generally has useful style data and has the
  // NS_FRAME_GENERATED_CONTENT bit set (so we use it to track removal),
  // but does not necessarily for |nsCounterChangeNode|s.
  nsIFrame* mPseudoFrame;

  // Index within the list of things specified by the 'content' property,
  // which is needed to do 'content: open-quote open-quote' correctly,
  // and needed for similar cases for counters.
  const int32_t mContentIndex;

  // null for 'content:no-open-quote', 'content:no-close-quote' and for
  // counter nodes for increments and resets (rather than uses)
  RefPtr<nsTextNode> mText;

  explicit nsGenConNode(int32_t aContentIndex)
    : mPseudoFrame(nullptr)
    , mContentIndex(aContentIndex)
  {
  }

  /**
   * Finish initializing the generated content node once we know the
   * relevant text frame. This must be called just after
   * the textframe has been initialized. This need not be called at all
   * for nodes that don't generate text. This will generally set the
   * mPseudoFrame, insert the node into aList, and set aTextFrame up
   * with the correct text.
   * @param aList the list the node belongs to
   * @param aPseudoFrame the :before or :after frame
   * @param aTextFrame the textframe where the node contents will render
   * @return true iff this marked the list dirty
   */
  virtual bool InitTextFrame(nsGenConList* aList, nsIFrame* aPseudoFrame,
                             nsIFrame* aTextFrame)
  {
    mPseudoFrame = aPseudoFrame;
    CheckFrameAssertions();
    return false;
  }

  virtual ~nsGenConNode() {} // XXX Avoid, perhaps?

protected:
  void CheckFrameAssertions() {
    NS_ASSERTION(mContentIndex <
                   int32_t(mPseudoFrame->StyleContent()->ContentCount()),
                 "index out of range");
      // We allow negative values of mContentIndex for 'counter-reset' and
      // 'counter-increment'.

    NS_ASSERTION(mContentIndex < 0 ||
                 mPseudoFrame->StyleContext()->GetPseudo() ==
                   nsCSSPseudoElements::before ||
                 mPseudoFrame->StyleContext()->GetPseudo() ==
                   nsCSSPseudoElements::after,
                 "not :before/:after generated content and not counter change");
    NS_ASSERTION(mContentIndex < 0 ||
                 mPseudoFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT,
                 "not generated content and not counter change");
  }
};

class nsGenConList {
protected:
  mozilla::LinkedList<nsGenConNode> mList;
  uint32_t mSize;

public:
  nsGenConList() : mSize(0), mLastInserted(nullptr) {}
  ~nsGenConList() { Clear(); }
  void Clear();
  static nsGenConNode* Next(nsGenConNode* aNode) {
    MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
    return aNode->getNext();
  }
  static nsGenConNode* Prev(nsGenConNode* aNode) {
    MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
    return aNode->getPrevious();
  }
  void Insert(nsGenConNode* aNode);

  // Destroy all nodes with aFrame as parent. Returns true if some nodes
  // have been destroyed; otherwise false.
  bool DestroyNodesFor(nsIFrame* aFrame);

  // Return true if |aNode1| is after |aNode2|.
  static bool NodeAfter(const nsGenConNode* aNode1,
                        const nsGenConNode* aNode2);

  bool IsFirst(nsGenConNode* aNode) {
    MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
    return aNode == mList.getFirst();
  }

  bool IsLast(nsGenConNode* aNode) {
    MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
    return aNode == mList.getLast();
  }

private:
  void Destroy(nsGenConNode* aNode)
  {
    MOZ_ASSERT(aNode, "aNode cannot be nullptr!");
    delete aNode;
    mSize--;
  }

  // Map from frame to the first nsGenConNode of it in the list.
  nsDataHashtable<nsPtrHashKey<nsIFrame>, nsGenConNode*> mNodes;

  // A weak pointer to the node most recently inserted, used to avoid repeated
  // list traversals in Insert().
  nsGenConNode* mLastInserted;
};

#endif /* nsGenConList_h___ */