1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef nsXMLContentSink_h__ 8 #define nsXMLContentSink_h__ 9 10 #include "mozilla/Attributes.h" 11 #include "nsContentSink.h" 12 #include "nsIXMLContentSink.h" 13 #include "nsIExpatSink.h" 14 #include "nsIDocumentTransformer.h" 15 #include "nsTArray.h" 16 #include "nsCOMPtr.h" 17 #include "nsCRT.h" 18 #include "nsCycleCollectionParticipant.h" 19 #include "nsIDTD.h" 20 #include "mozilla/dom/FromParser.h" 21 22 class nsIDocument; 23 class nsIURI; 24 class nsIContent; 25 class nsIParser; 26 27 namespace mozilla { 28 namespace dom { 29 class NodeInfo; 30 class ProcessingInstruction; 31 } // namespace dom 32 } // namespace mozilla 33 34 typedef enum { 35 eXMLContentSinkState_InProlog, 36 eXMLContentSinkState_InDocumentElement, 37 eXMLContentSinkState_InEpilog 38 } XMLContentSinkState; 39 40 struct StackNode { 41 nsCOMPtr<nsIContent> mContent; 42 uint32_t mNumFlushed; 43 }; 44 45 class nsXMLContentSink : public nsContentSink, 46 public nsIXMLContentSink, 47 public nsITransformObserver, 48 public nsIExpatSink { 49 public: 50 nsXMLContentSink(); 51 52 nsresult Init(nsIDocument* aDoc, nsIURI* aURL, nsISupports* aContainer, 53 nsIChannel* aChannel); 54 55 // nsISupports 56 NS_DECL_ISUPPORTS_INHERITED 57 58 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsXMLContentSink, 59 nsContentSink) 60 61 NS_DECL_NSIEXPATSINK 62 63 // nsIContentSink 64 NS_IMETHOD WillParse(void) override; 65 NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode) override; 66 NS_IMETHOD DidBuildModel(bool aTerminated) override; 67 NS_IMETHOD WillInterrupt(void) override; 68 NS_IMETHOD WillResume(void) override; 69 NS_IMETHOD SetParser(nsParserBase* aParser) override; 70 virtual void FlushPendingNotifications(mozilla::FlushType aType) override; 71 virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override; 72 virtual nsISupports* GetTarget() override; 73 virtual bool IsScriptExecuting() override; 74 virtual void ContinueInterruptedParsingAsync() override; 75 76 // nsITransformObserver 77 NS_IMETHOD OnDocumentCreated(nsIDocument* aResultDocument) override; 78 NS_IMETHOD OnTransformDone(nsresult aResult, 79 nsIDocument* aResultDocument) override; 80 81 // nsICSSLoaderObserver 82 NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet, bool aWasAlternate, 83 nsresult aStatus) override; 84 static bool ParsePIData(const nsString& aData, nsString& aHref, 85 nsString& aTitle, nsString& aMedia, 86 bool& aIsAlternate); 87 88 protected: 89 virtual ~nsXMLContentSink(); 90 91 nsIParser* GetParser(); 92 93 void ContinueInterruptedParsingIfEnabled(); 94 95 // Start layout. If aIgnorePendingSheets is true, this will happen even if 96 // we still have stylesheet loads pending. Otherwise, we'll wait until the 97 // stylesheets are all done loading. 98 virtual void MaybeStartLayout(bool aIgnorePendingSheets); 99 100 virtual nsresult AddAttributes(const char16_t** aNode, Element* aElement); 101 nsresult AddText(const char16_t* aString, int32_t aLength); 102 OnOpenContainer(const char16_t ** aAtts,uint32_t aAttsCount,int32_t aNameSpaceID,nsAtom * aTagName,uint32_t aLineNumber)103 virtual bool OnOpenContainer(const char16_t** aAtts, uint32_t aAttsCount, 104 int32_t aNameSpaceID, nsAtom* aTagName, 105 uint32_t aLineNumber) { 106 return true; 107 } 108 // Set the given content as the root element for the created document 109 // don't set if root element was already set. 110 // return TRUE if this call set the root element 111 virtual bool SetDocElement(int32_t aNameSpaceID, nsAtom* aTagName, 112 nsIContent* aContent); NotifyForDocElement()113 virtual bool NotifyForDocElement() { return true; } 114 virtual nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount, 115 mozilla::dom::NodeInfo* aNodeInfo, 116 uint32_t aLineNumber, nsIContent** aResult, 117 bool* aAppendContent, 118 mozilla::dom::FromParser aFromParser); 119 120 // aParent is allowed to be null here if this is the root content 121 // being closed 122 virtual nsresult CloseElement(nsIContent* aContent); 123 124 virtual nsresult FlushText(bool aReleaseTextNode = true); 125 126 nsresult AddContentAsLeaf(nsIContent* aContent); 127 128 nsIContent* GetCurrentContent(); 129 StackNode* GetCurrentStackNode(); 130 nsresult PushContent(nsIContent* aContent); 131 void PopContent(); 132 bool HaveNotifiedForCurrentContent() const; 133 134 nsresult FlushTags() override; 135 136 void UpdateChildCounts() override; 137 DidAddContent()138 void DidAddContent() { 139 if (!mXSLTProcessor && IsTimeToNotify()) { 140 FlushTags(); 141 } 142 } 143 144 // nsContentSink override 145 virtual nsresult ProcessStyleLinkFromHeader( 146 const nsAString& aHref, bool aAlternate, const nsAString& aTitle, 147 const nsAString& aType, const nsAString& aMedia, 148 const nsAString& aReferrerPolicy) override; 149 150 // Try to handle an XSLT style link. If NS_OK is returned and aWasXSLT is not 151 // null, *aWasXSLT will be set to whether we processed this link as XSLT. 152 // 153 // aProcessingInstruction can be null if this information comes from a Link 154 // header; otherwise it will be the xml-styleshset XML PI that the loading 155 // information comes from. 156 virtual nsresult MaybeProcessXSLTLink( 157 mozilla::dom::ProcessingInstruction* aProcessingInstruction, 158 const nsAString& aHref, bool aAlternate, const nsAString& aTitle, 159 const nsAString& aType, const nsAString& aMedia, 160 const nsAString& aReferrerPolicy, bool* aWasXSLT = nullptr); 161 162 nsresult LoadXSLStyleSheet(nsIURI* aUrl); 163 164 bool CanStillPrettyPrint(); 165 166 nsresult MaybePrettyPrint(); 167 168 bool IsMonolithicContainer(mozilla::dom::NodeInfo* aNodeInfo); 169 170 nsresult HandleStartElement(const char16_t* aName, const char16_t** aAtts, 171 uint32_t aAttsCount, uint32_t aLineNumber, 172 bool aInterruptable); 173 nsresult HandleEndElement(const char16_t* aName, bool aInterruptable); 174 nsresult HandleCharacterData(const char16_t* aData, uint32_t aLength, 175 bool aInterruptable); 176 177 nsCOMPtr<nsIContent> mDocElement; 178 nsCOMPtr<nsIContent> mCurrentHead; // When set, we're in an XHTML <haed> 179 180 XMLContentSinkState mState; 181 182 // The length of the valid data in mText. 183 int32_t mTextLength; 184 185 int32_t mNotifyLevel; 186 nsCOMPtr<nsIContent> mLastTextNode; 187 188 uint8_t mPrettyPrintXML : 1; 189 uint8_t mPrettyPrintHasSpecialRoot : 1; 190 uint8_t mPrettyPrintHasFactoredElements : 1; 191 uint8_t mPrettyPrinting : 1; // True if we called PrettyPrint() and it 192 // decided we should in fact prettyprint. 193 // True to call prevent script execution in the fragment mode. 194 uint8_t mPreventScriptExecution : 1; 195 196 nsTArray<StackNode> mContentStack; 197 198 nsCOMPtr<nsIDocumentTransformer> mXSLTProcessor; 199 200 // Holds the children in the prolog until the root element is added, after 201 // which they're inserted in the document. However, if we're doing an XSLT 202 // transform this will actually hold all the children of the source document, 203 // until the transform is finished. After the transform is finished we'll just 204 // discard the children. 205 nsTArray<nsCOMPtr<nsIContent>> mDocumentChildren; 206 207 static const int NS_ACCUMULATION_BUFFER_SIZE = 4096; 208 // Our currently accumulated text that we have not flushed to a textnode yet. 209 char16_t mText[NS_ACCUMULATION_BUFFER_SIZE]; 210 }; 211 212 #endif // nsXMLContentSink_h__ 213