1 /* -*- Mode: C++; tab-width: 4; 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 #ifndef nsXULContentSink_h__
7 #define nsXULContentSink_h__
8 
9 #include "mozilla/Attributes.h"
10 #include "nsIExpatSink.h"
11 #include "nsIWeakReferenceUtils.h"
12 #include "nsIXMLContentSink.h"
13 #include "nsNodeInfoManager.h"
14 #include "nsXULElement.h"
15 #include "nsIDTD.h"
16 
17 class nsIScriptSecurityManager;
18 class nsAttrName;
19 class nsXULPrototypeDocument;
20 class nsXULPrototypeElement;
21 class nsXULPrototypeNode;
22 
23 class XULContentSinkImpl final : public nsIXMLContentSink, public nsIExpatSink {
24  public:
25   XULContentSinkImpl();
26 
27   // nsISupports
28   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
29   NS_DECL_NSIEXPATSINK
30 
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(XULContentSinkImpl,nsIXMLContentSink)31   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(XULContentSinkImpl,
32                                            nsIXMLContentSink)
33 
34   // nsIContentSink
35   NS_IMETHOD WillParse(void) override { return NS_OK; }
36   NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode) override;
37   NS_IMETHOD DidBuildModel(bool aTerminated) override;
38   NS_IMETHOD WillInterrupt(void) override;
39   NS_IMETHOD WillResume(void) override;
40   NS_IMETHOD SetParser(nsParserBase* aParser) override;
FlushPendingNotifications(mozilla::FlushType aType)41   virtual void FlushPendingNotifications(mozilla::FlushType aType) override {}
42   virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override;
43   virtual nsISupports* GetTarget() override;
44 
45   /**
46    * Initialize the content sink, giving it a document with which to communicate
47    * with the outside world, and an nsXULPrototypeDocument to build.
48    */
49   nsresult Init(mozilla::dom::Document* aDocument,
50                 nsXULPrototypeDocument* aPrototype);
51 
52  protected:
53   virtual ~XULContentSinkImpl();
54 
55   // pseudo-constants
56   char16_t* mText;
57   int32_t mTextLength;
58   int32_t mTextSize;
59   bool mConstrainSize;
60 
61   nsresult AddAttributes(const char16_t** aAttributes, const uint32_t aAttrLen,
62                          nsXULPrototypeElement* aElement);
63 
64   nsresult OpenRoot(const char16_t** aAttributes, const uint32_t aAttrLen,
65                     mozilla::dom::NodeInfo* aNodeInfo);
66 
67   nsresult OpenTag(const char16_t** aAttributes, const uint32_t aAttrLen,
68                    const uint32_t aLineNumber,
69                    mozilla::dom::NodeInfo* aNodeInfo);
70 
71   // If OpenScript returns NS_OK and after it returns our state is eInScript,
72   // that means that we created a prototype script and stuck it on
73   // mContextStack.  If NS_OK is returned but the state is still
74   // eInDocumentElement then we didn't create a prototype script (e.g. the
75   // script had an unknown type), and the caller should create a prototype
76   // element.
77   nsresult OpenScript(const char16_t** aAttributes, const uint32_t aLineNumber);
78 
79   static bool IsDataInBuffer(char16_t* aBuffer, int32_t aLength);
80 
81   // Text management
82   nsresult FlushText(bool aCreateTextNode = true);
83   nsresult AddText(const char16_t* aText, int32_t aLength);
84 
85   RefPtr<nsNodeInfoManager> mNodeInfoManager;
86 
87   nsresult NormalizeAttributeString(const char16_t* aExpatName,
88                                     nsAttrName& aName);
89 
90  public:
91   enum State { eInProlog, eInDocumentElement, eInScript, eInEpilog };
92 
93  protected:
94   State mState;
95 
96   // content stack management
97   class ContextStack {
98    protected:
99     struct Entry {
100       RefPtr<nsXULPrototypeNode> mNode;
101       // a LOT of nodes have children; preallocate for 8
102       nsPrototypeArray mChildren;
103       State mState;
104       Entry* mNext;
EntryEntry105       Entry(RefPtr<nsXULPrototypeNode>&& aNode, State aState, Entry* aNext)
106           : mNode(std::move(aNode)),
107             mChildren(8),
108             mState(aState),
109             mNext(aNext) {}
110     };
111 
112     Entry* mTop;
113     int32_t mDepth;
114 
115    public:
116     ContextStack();
117     ~ContextStack();
118 
Depth()119     int32_t Depth() { return mDepth; }
120 
121     void Push(RefPtr<nsXULPrototypeNode>&& aNode, State aState);
122     nsresult Pop(State* aState);
123 
124     nsresult GetTopNode(RefPtr<nsXULPrototypeNode>& aNode);
125     nsresult GetTopChildren(nsPrototypeArray** aChildren);
126 
127     void Clear();
128 
129     void Traverse(nsCycleCollectionTraversalCallback& aCallback);
130   };
131 
132   friend class ContextStack;
133   ContextStack mContextStack;
134 
135   nsWeakPtr mDocument;            // [OWNER]
136   nsCOMPtr<nsIURI> mDocumentURL;  // [OWNER]
137 
138   RefPtr<nsXULPrototypeDocument> mPrototype;  // [OWNER]
139 
140   RefPtr<nsParserBase> mParser;
141   nsCOMPtr<nsIScriptSecurityManager> mSecMan;
142 };
143 
144 #endif /* nsXULContentSink_h__ */
145