summaryrefslogtreecommitdiffstats
path: root/dom/xul/nsXULContentSink.h
blob: 0538c013b417baf7ec0d367db64d358ac5245ec9 (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
137
138
139
140
141
142
143
/* -*- Mode: C++; tab-width: 4; 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/. */

#ifndef nsXULContentSink_h__
#define nsXULContentSink_h__

#include "mozilla/Attributes.h"
#include "nsIExpatSink.h"
#include "nsIWeakReferenceUtils.h"
#include "nsIXMLContentSink.h"
#include "nsNodeInfoManager.h"
#include "nsXULElement.h"
#include "nsIDTD.h"

class nsIScriptSecurityManager;
class nsAttrName;
class nsXULPrototypeDocument;
class nsXULPrototypeElement;
class nsXULPrototypeNode;

class XULContentSinkImpl final : public nsIXMLContentSink, public nsIExpatSink {
 public:
  XULContentSinkImpl();

  // nsISupports
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_NSIEXPATSINK

  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(XULContentSinkImpl,
                                           nsIXMLContentSink)

  // nsIContentSink
  NS_IMETHOD WillParse(void) override { return NS_OK; }
  NS_IMETHOD DidBuildModel(bool aTerminated) override;
  NS_IMETHOD WillInterrupt(void) override;
  void WillResume() override;
  NS_IMETHOD SetParser(nsParserBase* aParser) override;
  virtual void FlushPendingNotifications(mozilla::FlushType aType) override {}
  virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override;
  virtual nsISupports* GetTarget() override;

  /**
   * Initialize the content sink, giving it a document with which to communicate
   * with the outside world, and an nsXULPrototypeDocument to build.
   */
  nsresult Init(mozilla::dom::Document* aDocument,
                nsXULPrototypeDocument* aPrototype);

 protected:
  virtual ~XULContentSinkImpl();

  // pseudo-constants
  char16_t* mText;
  int32_t mTextLength;
  int32_t mTextSize;
  bool mConstrainSize;

  nsresult AddAttributes(const char16_t** aAttributes, const uint32_t aAttrLen,
                         nsXULPrototypeElement* aElement);

  nsresult OpenRoot(const char16_t** aAttributes, const uint32_t aAttrLen,
                    mozilla::dom::NodeInfo* aNodeInfo);

  nsresult OpenTag(const char16_t** aAttributes, const uint32_t aAttrLen,
                   const uint32_t aLineNumber,
                   mozilla::dom::NodeInfo* aNodeInfo);

  // If OpenScript returns NS_OK and after it returns our state is eInScript,
  // that means that we created a prototype script and stuck it on
  // mContextStack.  If NS_OK is returned but the state is still
  // eInDocumentElement then we didn't create a prototype script (e.g. the
  // script had an unknown type), and the caller should create a prototype
  // element.
  nsresult OpenScript(const char16_t** aAttributes, const uint32_t aLineNumber);

  static bool IsDataInBuffer(char16_t* aBuffer, int32_t aLength);

  // Text management
  nsresult FlushText(bool aCreateTextNode = true);
  nsresult AddText(const char16_t* aText, int32_t aLength);

  RefPtr<nsNodeInfoManager> mNodeInfoManager;

  nsresult NormalizeAttributeString(const char16_t* aExpatName,
                                    nsAttrName& aName);

 public:
  enum State { eInProlog, eInDocumentElement, eInScript, eInEpilog };

 protected:
  State mState;

  // content stack management
  class ContextStack {
   protected:
    struct Entry {
      RefPtr<nsXULPrototypeNode> mNode;
      // a LOT of nodes have children; preallocate for 8
      nsPrototypeArray mChildren;
      State mState;
      Entry* mNext;
      Entry(RefPtr<nsXULPrototypeNode>&& aNode, State aState, Entry* aNext)
          : mNode(std::move(aNode)),
            mChildren(8),
            mState(aState),
            mNext(aNext) {}
    };

    Entry* mTop;
    int32_t mDepth;

   public:
    ContextStack();
    ~ContextStack();

    int32_t Depth() { return mDepth; }

    void Push(RefPtr<nsXULPrototypeNode>&& aNode, State aState);
    nsresult Pop(State* aState);

    nsresult GetTopNode(RefPtr<nsXULPrototypeNode>& aNode);
    nsresult GetTopChildren(nsPrototypeArray** aChildren);

    void Clear();

    void Traverse(nsCycleCollectionTraversalCallback& aCallback);
  };

  friend class ContextStack;
  ContextStack mContextStack;

  nsWeakPtr mDocument;            // [OWNER]
  nsCOMPtr<nsIURI> mDocumentURL;  // [OWNER]

  RefPtr<nsXULPrototypeDocument> mPrototype;  // [OWNER]

  RefPtr<nsParserBase> mParser;
  nsCOMPtr<nsIScriptSecurityManager> mSecMan;
};

#endif /* nsXULContentSink_h__ */