/* -*- 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 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 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 mNode; // a LOT of nodes have children; preallocate for 8 nsPrototypeArray mChildren; State mState; Entry* mNext; Entry(RefPtr&& 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&& aNode, State aState); nsresult Pop(State* aState); nsresult GetTopNode(RefPtr& aNode); nsresult GetTopChildren(nsPrototypeArray** aChildren); void Clear(); void Traverse(nsCycleCollectionTraversalCallback& aCallback); }; friend class ContextStack; ContextStack mContextStack; nsWeakPtr mDocument; // [OWNER] nsCOMPtr mDocumentURL; // [OWNER] RefPtr mPrototype; // [OWNER] RefPtr mParser; nsCOMPtr mSecMan; }; #endif /* nsXULContentSink_h__ */