PrototypeDocumentContentSink.h (8119B)
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 https://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_PrototypeDocumentContentSink_h__ 8 #define mozilla_dom_PrototypeDocumentContentSink_h__ 9 10 #include "js/experimental/JSStencil.h" 11 #include "mozilla/Logging.h" 12 #include "mozilla/RefPtr.h" 13 #include "mozilla/dom/FromParser.h" 14 #include "nsCOMPtr.h" 15 #include "nsCRT.h" 16 #include "nsCycleCollectionNoteChild.h" 17 #include "nsCycleCollectionParticipant.h" 18 #include "nsICSSLoaderObserver.h" 19 #include "nsIContentSink.h" 20 #include "nsIScriptContext.h" 21 #include "nsIStreamLoader.h" 22 #include "nsTArray.h" 23 #include "nsXULPrototypeDocument.h" 24 25 class nsIURI; 26 class nsIChannel; 27 class nsIContent; 28 class nsIParser; 29 class nsTextNode; 30 class nsINode; 31 class nsXULPrototypeElement; 32 class nsXULPrototypePI; 33 class nsXULPrototypeScript; 34 35 namespace mozilla::dom { 36 class Element; 37 class ScriptLoader; 38 class Document; 39 class XMLStylesheetProcessingInstruction; 40 } // namespace mozilla::dom 41 42 nsresult NS_NewPrototypeDocumentContentSink(nsIContentSink** aResult, 43 mozilla::dom::Document* aDoc, 44 nsIURI* aURI, 45 nsISupports* aContainer, 46 nsIChannel* aChannel); 47 48 namespace mozilla::dom { 49 50 class PrototypeDocumentContentSink final : public nsIStreamLoaderObserver, 51 public nsIContentSink, 52 public nsICSSLoaderObserver, 53 public nsIOffThreadScriptReceiver { 54 public: 55 PrototypeDocumentContentSink(); 56 57 nsresult Init(Document* aDoc, nsIURI* aURL, nsISupports* aContainer, 58 nsIChannel* aChannel); 59 60 // nsISupports 61 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 62 NS_DECL_NSISTREAMLOADEROBSERVER 63 64 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(PrototypeDocumentContentSink, 65 nsIContentSink) 66 67 // nsIContentSink 68 NS_IMETHOD WillParse(void) override { return NS_OK; }; 69 NS_IMETHOD WillInterrupt(void) override { return NS_OK; }; 70 void WillResume() override {}; 71 NS_IMETHOD SetParser(nsParserBase* aParser) override; 72 virtual void InitialTranslationCompleted() override; 73 virtual void FlushPendingNotifications(FlushType aType) override {}; 74 virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override; 75 virtual nsISupports* GetTarget() override; 76 virtual bool IsScriptExecuting() override; 77 virtual void ContinueInterruptedParsingAsync() override; 78 79 // nsICSSLoaderObserver 80 NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred, 81 nsresult aStatus) override; 82 83 // nsIOffThreadScriptReceiver 84 NS_IMETHOD OnScriptCompileComplete(JS::Stencil* aStencil, 85 nsresult aStatus) override; 86 87 nsresult OnPrototypeLoadDone(nsXULPrototypeDocument* aPrototype); 88 89 protected: 90 virtual ~PrototypeDocumentContentSink(); 91 92 static LazyLogModule gLog; 93 94 nsIParser* GetParser(); 95 96 void ContinueInterruptedParsingIfEnabled(); 97 void StartLayout(); 98 99 virtual nsresult AddAttributes(nsXULPrototypeElement* aPrototype, 100 Element* aElement); 101 102 RefPtr<nsParserBase> mParser; 103 nsCOMPtr<nsIURI> mDocumentURI; 104 RefPtr<Document> mDocument; 105 RefPtr<ScriptLoader> mScriptLoader; 106 107 PrototypeDocumentContentSink* mNextSrcLoadWaiter; // [OWNER] but not COMPtr 108 109 /** 110 * The prototype-script of the current transcluded script that is being 111 * loaded. For document.write('<script src="nestedwrite.js"><\/script>') 112 * to work, these need to be in a stack element type, and we need to hold 113 * the top of stack here. 114 */ 115 nsXULPrototypeScript* mCurrentScriptProto; 116 117 /** 118 * Whether the current transcluded script is being compiled off thread. 119 * The load event is blocked while this is in progress. 120 */ 121 bool mOffThreadCompiling; 122 123 /** 124 * Wether the prototype document is still be traversed to create the DOM. 125 * Layout will not be started until false. 126 */ 127 bool mStillWalking; 128 129 /** 130 * Number of style sheets still loading. Layout will not start until zero. 131 */ 132 uint32_t mPendingSheets; 133 134 /** 135 * Context stack, which maintains the state of the Builder and allows 136 * it to be interrupted. 137 */ 138 class ContextStack { 139 protected: 140 struct Entry { 141 nsXULPrototypeElement* mPrototype; 142 nsIContent* mElement; 143 int32_t mIndex; 144 Entry* mNext; 145 }; 146 147 Entry* mTop; 148 int32_t mDepth; 149 150 public: 151 ContextStack(); 152 ~ContextStack(); 153 154 int32_t Depth() { return mDepth; } 155 156 nsresult Push(nsXULPrototypeElement* aPrototype, nsIContent* aElement); 157 nsresult Pop(); 158 nsresult Peek(nsXULPrototypeElement** aPrototype, nsIContent** aElement, 159 int32_t* aIndex); 160 161 nsresult SetTopIndex(int32_t aIndex); 162 163 void Traverse(nsCycleCollectionTraversalCallback& aCallback, 164 const char* aName, uint32_t aFlags = 0); 165 void Clear(); 166 167 // Cycle collector helpers for ContextStack. 168 friend void ImplCycleCollectionUnlink( 169 PrototypeDocumentContentSink::ContextStack& aField) { 170 aField.Clear(); 171 } 172 173 friend void ImplCycleCollectionTraverse( 174 nsCycleCollectionTraversalCallback& aCallback, 175 PrototypeDocumentContentSink::ContextStack& aField, const char* aName, 176 uint32_t aFlags = 0) { 177 aField.Traverse(aCallback, aName, aFlags); 178 } 179 }; 180 181 friend class ContextStack; 182 ContextStack mContextStack; 183 184 /** 185 * The current prototype that we are walking to construct the 186 * content model. 187 */ 188 RefPtr<nsXULPrototypeDocument> mCurrentPrototype; 189 nsresult CreateAndInsertPI(const nsXULPrototypePI* aProtoPI); 190 nsresult ExecuteScript(nsXULPrototypeScript* aScript); 191 nsresult LoadScript(nsXULPrototypeScript* aScriptProto, bool* aBlock); 192 193 /** 194 * A wrapper around ResumeWalkInternal to report walking errors. 195 */ 196 nsresult ResumeWalk(); 197 198 /** 199 * Resume (or initiate) an interrupted (or newly prepared) 200 * prototype walk. 201 */ 202 nsresult ResumeWalkInternal(); 203 204 /** 205 * Called at the end of ResumeWalk(), from StyleSheetLoaded(), 206 * and from DocumentL10n. 207 * If walking, stylesheets and l10n are not blocking, it 208 * will trigger `DoneWalking()`. 209 */ 210 nsresult MaybeDoneWalking(); 211 212 /** 213 * Called from `MaybeDoneWalking()`. 214 * Expects that both the prototype document walk is complete and 215 * all referenced stylesheets finished loading. 216 */ 217 nsresult DoneWalking(); 218 219 /** 220 * Create a delegate content model element from a prototype. 221 * Note that the resulting content node is not bound to any tree 222 */ 223 nsresult CreateElementFromPrototype(nsXULPrototypeElement* aPrototype, 224 Element** aResult, nsIContent* aParent); 225 /** 226 * Prepare to walk the current prototype. 227 */ 228 nsresult PrepareToWalk(); 229 /** 230 * Creates a processing instruction based on aProtoPI and inserts 231 * it to the DOM. 232 */ 233 nsresult CreateAndInsertPI(const nsXULPrototypePI* aProtoPI, nsINode* aParent, 234 bool aInProlog); 235 236 /** 237 * Inserts the passed <?xml-stylesheet ?> PI at the specified 238 * index. Loads and applies the associated stylesheet 239 * asynchronously. 240 * The prototype document walk can happen before the stylesheets 241 * are loaded, but the final steps in the load process (see 242 * DoneWalking()) are not run before all the stylesheets are done 243 * loading. 244 */ 245 nsresult InsertXMLStylesheetPI(const nsXULPrototypePI* aProtoPI, 246 nsINode* aParent, 247 XMLStylesheetProcessingInstruction* aPINode); 248 void CloseElement(Element* aElement, bool aHadChildren); 249 }; 250 251 } // namespace mozilla::dom 252 253 #endif // mozilla_dom_PrototypeDocumentContentSink_h__