nsXMLFragmentContentSink.cpp (12610B)
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 #include "mozilla/css/Loader.h" 8 #include "mozilla/dom/Document.h" 9 #include "mozilla/dom/DocumentFragment.h" 10 #include "mozilla/dom/NodeInfo.h" 11 #include "mozilla/dom/ProcessingInstruction.h" 12 #include "mozilla/dom/ScriptLoader.h" 13 #include "nsCOMPtr.h" 14 #include "nsContentCreatorFunctions.h" 15 #include "nsContentSink.h" 16 #include "nsCycleCollectionParticipant.h" 17 #include "nsError.h" 18 #include "nsGkAtoms.h" 19 #include "nsHashKeys.h" 20 #include "nsIContent.h" 21 #include "nsIDocShell.h" 22 #include "nsIExpatSink.h" 23 #include "nsIFragmentContentSink.h" 24 #include "nsIScriptError.h" 25 #include "nsIXMLContentSink.h" 26 #include "nsTArray.h" 27 #include "nsTHashtable.h" 28 #include "nsXMLContentSink.h" 29 30 using namespace mozilla::dom; 31 32 class nsXMLFragmentContentSink : public nsXMLContentSink, 33 public nsIFragmentContentSink { 34 public: 35 nsXMLFragmentContentSink(); 36 37 // nsISupports 38 NS_DECL_ISUPPORTS_INHERITED 39 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXMLFragmentContentSink, 40 nsXMLContentSink) 41 42 // nsIExpatSink 43 NS_IMETHOD HandleDoctypeDecl(const nsAString& aSubset, const nsAString& aName, 44 const nsAString& aSystemId, 45 const nsAString& aPublicId, 46 nsISupports* aCatalogData) override; 47 NS_IMETHOD HandleProcessingInstruction(const char16_t* aTarget, 48 const char16_t* aData) override; 49 NS_IMETHOD HandleXMLDeclaration(const char16_t* aVersion, 50 const char16_t* aEncoding, 51 int32_t aStandalone) override; 52 NS_IMETHOD ReportError(const char16_t* aErrorText, 53 const char16_t* aSourceText, nsIScriptError* aError, 54 bool* aRetval) override; 55 56 // nsIContentSink 57 NS_IMETHOD WillBuildModel() override; 58 NS_IMETHOD DidBuildModel(bool aTerminated) override; 59 virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override; 60 virtual nsISupports* GetTarget() override; 61 NS_IMETHOD DidProcessATokenImpl(); 62 63 // nsIXMLContentSink 64 65 // nsIFragmentContentSink 66 NS_IMETHOD FinishFragmentParsing(DocumentFragment** aFragment) override; 67 NS_IMETHOD SetTargetDocument(Document* aDocument) override; 68 NS_IMETHOD WillBuildContent() override; 69 NS_IMETHOD DidBuildContent() override; 70 NS_IMETHOD IgnoreFirstContainer() override; 71 NS_IMETHOD SetPreventScriptExecution(bool aPreventScriptExecution) override; 72 73 protected: 74 virtual ~nsXMLFragmentContentSink(); 75 76 virtual bool SetDocElement(int32_t aNameSpaceID, nsAtom* aTagName, 77 nsIContent* aContent) override; 78 virtual nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount, 79 mozilla::dom::NodeInfo* aNodeInfo, 80 uint32_t aLineNumber, uint32_t aColumnNumber, 81 nsIContent** aResult, bool* aAppendContent, 82 mozilla::dom::FromParser aFromParser) override; 83 virtual nsresult CloseElement(nsIContent* aContent) override; 84 85 virtual void MaybeStartLayout(bool aIgnorePendingSheets) override; 86 87 // nsContentSink overrides 88 virtual nsresult ProcessStyleLinkFromHeader( 89 const nsAString& aHref, bool aAlternate, const nsAString& aTitle, 90 const nsAString& aIntegrity, const nsAString& aType, 91 const nsAString& aMedia, const nsAString& aReferrerPolicy, 92 const nsAString& aFetchPriority) override; 93 94 // nsXMLContentSink overrides 95 virtual nsresult MaybeProcessXSLTLink( 96 ProcessingInstruction* aProcessingInstruction, const nsAString& aHref, 97 bool aAlternate, const nsAString& aTitle, const nsAString& aType, 98 const nsAString& aMedia, const nsAString& aReferrerPolicy, 99 bool* aWasXSLT = nullptr) override; 100 101 nsCOMPtr<Document> mTargetDocument; 102 // the fragment 103 RefPtr<DocumentFragment> mRoot; 104 bool mParseError; 105 }; 106 107 static nsresult NewXMLFragmentContentSinkHelper( 108 nsIFragmentContentSink** aResult) { 109 nsXMLFragmentContentSink* it = new nsXMLFragmentContentSink(); 110 111 NS_ADDREF(*aResult = it); 112 113 return NS_OK; 114 } 115 116 nsresult NS_NewXMLFragmentContentSink(nsIFragmentContentSink** aResult) { 117 return NewXMLFragmentContentSinkHelper(aResult); 118 } 119 120 nsXMLFragmentContentSink::nsXMLFragmentContentSink() : mParseError(false) { 121 mRunsToCompletion = true; 122 } 123 124 nsXMLFragmentContentSink::~nsXMLFragmentContentSink() = default; 125 126 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLFragmentContentSink) 127 NS_INTERFACE_MAP_ENTRY(nsIFragmentContentSink) 128 NS_INTERFACE_MAP_END_INHERITING(nsXMLContentSink) 129 130 NS_IMPL_ADDREF_INHERITED(nsXMLFragmentContentSink, nsXMLContentSink) 131 NS_IMPL_RELEASE_INHERITED(nsXMLFragmentContentSink, nsXMLContentSink) 132 133 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsXMLFragmentContentSink, nsXMLContentSink, 134 mTargetDocument, mRoot) 135 136 NS_IMETHODIMP 137 nsXMLFragmentContentSink::WillBuildModel() { 138 if (mRoot) { 139 return NS_OK; 140 } 141 142 mState = eXMLContentSinkState_InDocumentElement; 143 144 NS_ASSERTION(mTargetDocument, "Need a document!"); 145 146 mRoot = new (mNodeInfoManager) DocumentFragment(mNodeInfoManager); 147 148 return NS_OK; 149 } 150 151 NS_IMETHODIMP 152 nsXMLFragmentContentSink::DidBuildModel(bool aTerminated) { 153 // Drop our reference to the parser to get rid of a circular 154 // reference. 155 mParser = nullptr; 156 157 return NS_OK; 158 } 159 160 void nsXMLFragmentContentSink::SetDocumentCharset( 161 NotNull<const Encoding*> aEncoding) { 162 MOZ_ASSERT_UNREACHABLE("fragments shouldn't set charset"); 163 } 164 165 nsISupports* nsXMLFragmentContentSink::GetTarget() { 166 return ToSupports(mTargetDocument); 167 } 168 169 //////////////////////////////////////////////////////////////////////// 170 171 bool nsXMLFragmentContentSink::SetDocElement(int32_t aNameSpaceID, 172 nsAtom* aTagName, 173 nsIContent* aContent) { 174 // this is a fragment, not a document 175 return false; 176 } 177 178 nsresult nsXMLFragmentContentSink::CreateElement( 179 const char16_t** aAtts, uint32_t aAttsCount, 180 mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber, 181 uint32_t aColumnNumber, nsIContent** aResult, bool* aAppendContent, 182 FromParser /*aFromParser*/) { 183 // Claim to not be coming from parser, since we don't do any of the 184 // fancy CloseElement stuff. 185 nsresult rv = nsXMLContentSink::CreateElement( 186 aAtts, aAttsCount, aNodeInfo, aLineNumber, aColumnNumber, aResult, 187 aAppendContent, NOT_FROM_PARSER); 188 189 // When we aren't grabbing all of the content we, never open a doc 190 // element, we run into trouble on the first element, so we don't append, 191 // and simply push this onto the content stack. 192 if (mContentStack.Length() == 0) { 193 *aAppendContent = false; 194 } 195 196 return rv; 197 } 198 199 nsresult nsXMLFragmentContentSink::CloseElement(nsIContent* aContent) { 200 // don't do fancy stuff in nsXMLContentSink 201 if (mPreventScriptExecution && (aContent->IsHTMLElement(nsGkAtoms::script) || 202 aContent->IsSVGElement(nsGkAtoms::script))) { 203 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent); 204 if (sele) { 205 sele->PreventExecution(); 206 } else { 207 NS_ASSERTION(nsNameSpaceManager::GetInstance()->mSVGDisabled, 208 "Script did QI correctly, but wasn't a disabled SVG!"); 209 } 210 } 211 return NS_OK; 212 } 213 214 void nsXMLFragmentContentSink::MaybeStartLayout(bool aIgnorePendingSheets) {} 215 216 //////////////////////////////////////////////////////////////////////// 217 218 NS_IMETHODIMP 219 nsXMLFragmentContentSink::HandleDoctypeDecl(const nsAString& aSubset, 220 const nsAString& aName, 221 const nsAString& aSystemId, 222 const nsAString& aPublicId, 223 nsISupports* aCatalogData) { 224 MOZ_ASSERT_UNREACHABLE("fragments shouldn't have doctype declarations"); 225 226 return NS_OK; 227 } 228 229 NS_IMETHODIMP 230 nsXMLFragmentContentSink::HandleProcessingInstruction(const char16_t* aTarget, 231 const char16_t* aData) { 232 FlushText(); 233 234 const nsDependentString target(aTarget); 235 const nsDependentString data(aData); 236 237 RefPtr<ProcessingInstruction> node = 238 NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data); 239 240 // no special processing here. that should happen when the fragment moves 241 // into the document 242 return AddContentAsLeaf(node); 243 } 244 245 NS_IMETHODIMP 246 nsXMLFragmentContentSink::HandleXMLDeclaration(const char16_t* aVersion, 247 const char16_t* aEncoding, 248 int32_t aStandalone) { 249 MOZ_ASSERT_UNREACHABLE("fragments shouldn't have XML declarations"); 250 return NS_OK; 251 } 252 253 NS_IMETHODIMP 254 nsXMLFragmentContentSink::ReportError(const char16_t* aErrorText, 255 const char16_t* aSourceText, 256 nsIScriptError* aError, bool* _retval) { 257 MOZ_ASSERT(aError && aSourceText && aErrorText, "Check arguments!!!"); 258 259 // The expat driver should report the error. 260 *_retval = true; 261 262 mParseError = true; 263 264 #ifdef DEBUG 265 // Report the error to stderr. 266 fprintf(stderr, "\n%s\n%s\n\n", NS_LossyConvertUTF16toASCII(aErrorText).get(), 267 NS_LossyConvertUTF16toASCII(aSourceText).get()); 268 #endif 269 270 // The following code is similar to the cleanup in 271 // nsXMLContentSink::ReportError() 272 mState = eXMLContentSinkState_InProlog; 273 274 // Clear the current content 275 while (mRoot->GetLastChild()) { 276 mRoot->GetLastChild()->Remove(); 277 } 278 279 // Clear any buffered-up text we have. It's enough to set the length to 0. 280 // The buffer itself is allocated when we're created and deleted in our 281 // destructor, so don't mess with it. 282 mTextLength = 0; 283 284 return NS_OK; 285 } 286 287 nsresult nsXMLFragmentContentSink::ProcessStyleLinkFromHeader( 288 const nsAString& aHref, bool aAlternate, const nsAString& aTitle, 289 const nsAString& aIntegrity, const nsAString& aType, 290 const nsAString& aMedia, const nsAString& aReferrerPolicy, 291 const nsAString& aFetchPriority) 292 293 { 294 MOZ_ASSERT_UNREACHABLE("Shouldn't have headers for a fragment sink"); 295 return NS_OK; 296 } 297 298 nsresult nsXMLFragmentContentSink::MaybeProcessXSLTLink( 299 ProcessingInstruction* aProcessingInstruction, const nsAString& aHref, 300 bool aAlternate, const nsAString& aTitle, const nsAString& aType, 301 const nsAString& aMedia, const nsAString& aReferrerPolicy, bool* aWasXSLT) { 302 MOZ_ASSERT(!aWasXSLT, "Our one caller doesn't care about whether we're XSLT"); 303 return NS_OK; 304 } 305 306 //////////////////////////////////////////////////////////////////////// 307 308 NS_IMETHODIMP 309 nsXMLFragmentContentSink::FinishFragmentParsing(DocumentFragment** aFragment) { 310 mTargetDocument = nullptr; 311 mNodeInfoManager = nullptr; 312 mScriptLoader = nullptr; 313 mContentStack.Clear(); 314 mDocumentURI = nullptr; 315 mDocShell = nullptr; 316 mDocElement = nullptr; 317 mCurrentHead = nullptr; 318 if (mParseError) { 319 // XXX PARSE_ERR from DOM3 Load and Save would be more appropriate 320 mRoot = nullptr; 321 mParseError = false; 322 *aFragment = nullptr; 323 return NS_ERROR_DOM_SYNTAX_ERR; 324 } 325 326 mRoot.forget(aFragment); 327 return NS_OK; 328 } 329 330 NS_IMETHODIMP 331 nsXMLFragmentContentSink::SetTargetDocument(Document* aTargetDocument) { 332 NS_ENSURE_ARG_POINTER(aTargetDocument); 333 334 mTargetDocument = aTargetDocument; 335 mNodeInfoManager = aTargetDocument->NodeInfoManager(); 336 337 return NS_OK; 338 } 339 340 NS_IMETHODIMP 341 nsXMLFragmentContentSink::WillBuildContent() { 342 PushContent(mRoot); 343 344 return NS_OK; 345 } 346 347 NS_IMETHODIMP 348 nsXMLFragmentContentSink::DidBuildContent() { 349 // Note: we need to FlushText() here because if we don't, we might not get 350 // an end element to do it for us, so make sure. 351 if (!mParseError) { 352 FlushText(); 353 } 354 PopContent(); 355 356 return NS_OK; 357 } 358 359 NS_IMETHODIMP 360 nsXMLFragmentContentSink::DidProcessATokenImpl() { return NS_OK; } 361 362 NS_IMETHODIMP 363 nsXMLFragmentContentSink::IgnoreFirstContainer() { 364 MOZ_ASSERT_UNREACHABLE("XML isn't as broken as HTML"); 365 return NS_ERROR_FAILURE; 366 } 367 368 NS_IMETHODIMP 369 nsXMLFragmentContentSink::SetPreventScriptExecution(bool aPrevent) { 370 mPreventScriptExecution = aPrevent; 371 return NS_OK; 372 }