Bumping manifests a=b2g-bump
[gecko.git] / dom / xul / nsXULPrototypeDocument.cpp
blobcdf62d4db50703c29c5bfdfa7f5c95d7c9d74252
1 /* -*- Mode: C++; tab-width: 2; 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/. */
7 #include "nsXULPrototypeDocument.h"
8 #include "XULDocument.h"
10 #include "nsAString.h"
11 #include "nsIObjectInputStream.h"
12 #include "nsIObjectOutputStream.h"
13 #include "nsIPrincipal.h"
14 #include "nsJSPrincipals.h"
15 #include "nsIScriptObjectPrincipal.h"
16 #include "nsIScriptSecurityManager.h"
17 #include "nsIServiceManager.h"
18 #include "nsIArray.h"
19 #include "nsIURI.h"
20 #include "jsapi.h"
21 #include "jsfriendapi.h"
22 #include "nsString.h"
23 #include "nsIConsoleService.h"
24 #include "nsIScriptError.h"
25 #include "nsIDOMScriptObjectFactory.h"
26 #include "nsDOMCID.h"
27 #include "nsNodeInfoManager.h"
28 #include "nsContentUtils.h"
29 #include "nsCCUncollectableMarker.h"
30 #include "xpcpublic.h"
31 #include "mozilla/dom/BindingUtils.h"
33 using mozilla::dom::DestroyProtoAndIfaceCache;
34 using mozilla::dom::XULDocument;
36 uint32_t nsXULPrototypeDocument::gRefCnt;
38 //----------------------------------------------------------------------
40 // ctors, dtors, n' stuff
43 nsXULPrototypeDocument::nsXULPrototypeDocument()
44 : mRoot(nullptr),
45 mLoaded(false),
46 mCCGeneration(0),
47 mGCNumber(0)
49 ++gRefCnt;
53 nsresult
54 nsXULPrototypeDocument::Init()
56 mNodeInfoManager = new nsNodeInfoManager();
57 NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
59 return mNodeInfoManager->Init(nullptr);
62 nsXULPrototypeDocument::~nsXULPrototypeDocument()
64 if (mRoot)
65 mRoot->ReleaseSubtree();
68 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeDocument)
70 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULPrototypeDocument)
71 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototypeWaiters)
72 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
73 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeDocument)
74 if (nsCCUncollectableMarker::InGeneration(cb, tmp->mCCGeneration)) {
75 return NS_SUCCESS_INTERRUPTED_TRAVERSE;
77 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
78 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
79 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototypeWaiters)
80 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
82 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPrototypeDocument)
83 NS_INTERFACE_MAP_ENTRY(nsISerializable)
84 NS_INTERFACE_MAP_ENTRY(nsISupports)
85 NS_INTERFACE_MAP_END
87 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULPrototypeDocument)
88 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULPrototypeDocument)
90 NS_IMETHODIMP
91 NS_NewXULPrototypeDocument(nsXULPrototypeDocument** aResult)
93 *aResult = new nsXULPrototypeDocument();
94 if (! *aResult)
95 return NS_ERROR_OUT_OF_MEMORY;
97 nsresult rv;
98 rv = (*aResult)->Init();
99 if (NS_FAILED(rv)) {
100 delete *aResult;
101 *aResult = nullptr;
102 return rv;
105 NS_ADDREF(*aResult);
106 return rv;
109 //----------------------------------------------------------------------
111 // nsISerializable methods
114 NS_IMETHODIMP
115 nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
117 nsresult rv;
119 nsCOMPtr<nsISupports> supports;
120 rv = aStream->ReadObject(true, getter_AddRefs(supports));
121 mURI = do_QueryInterface(supports);
123 uint32_t count, i;
124 nsCOMPtr<nsIURI> styleOverlayURI;
126 nsresult tmp = aStream->Read32(&count);
127 if (NS_FAILED(tmp)) {
128 return tmp;
130 if (NS_FAILED(rv)) {
131 return rv;
134 for (i = 0; i < count; ++i) {
135 tmp = aStream->ReadObject(true, getter_AddRefs(supports));
136 if (NS_FAILED(tmp)) {
137 rv = tmp;
139 styleOverlayURI = do_QueryInterface(supports);
140 mStyleSheetReferences.AppendObject(styleOverlayURI);
144 // nsIPrincipal mNodeInfoManager->mPrincipal
145 nsCOMPtr<nsIPrincipal> principal;
146 tmp = aStream->ReadObject(true, getter_AddRefs(supports));
147 principal = do_QueryInterface(supports);
148 if (NS_FAILED(tmp)) {
149 rv = tmp;
151 // Better safe than sorry....
152 mNodeInfoManager->SetDocumentPrincipal(principal);
154 mRoot = new nsXULPrototypeElement();
155 if (! mRoot)
156 return NS_ERROR_OUT_OF_MEMORY;
158 // mozilla::dom::NodeInfo table
159 nsTArray<nsRefPtr<mozilla::dom::NodeInfo>> nodeInfos;
161 tmp = aStream->Read32(&count);
162 if (NS_FAILED(tmp)) {
163 rv = tmp;
165 nsAutoString namespaceURI, prefixStr, localName;
166 bool prefixIsNull;
167 nsCOMPtr<nsIAtom> prefix;
168 for (i = 0; i < count; ++i) {
169 tmp = aStream->ReadString(namespaceURI);
170 if (NS_FAILED(tmp)) {
171 rv = tmp;
173 tmp = aStream->ReadBoolean(&prefixIsNull);
174 if (NS_FAILED(tmp)) {
175 rv = tmp;
177 if (prefixIsNull) {
178 prefix = nullptr;
179 } else {
180 tmp = aStream->ReadString(prefixStr);
181 if (NS_FAILED(tmp)) {
182 rv = tmp;
184 prefix = do_GetAtom(prefixStr);
186 tmp = aStream->ReadString(localName);
187 if (NS_FAILED(tmp)) {
188 rv = tmp;
191 nsRefPtr<mozilla::dom::NodeInfo> nodeInfo;
192 // Using UINT16_MAX here as we don't know which nodeinfos will be
193 // used for attributes and which for elements. And that doesn't really
194 // matter.
195 tmp = mNodeInfoManager->GetNodeInfo(localName, prefix, namespaceURI,
196 UINT16_MAX,
197 getter_AddRefs(nodeInfo));
198 if (NS_FAILED(tmp)) {
199 rv = tmp;
201 nodeInfos.AppendElement(nodeInfo);
204 // Document contents
205 uint32_t type;
206 while (NS_SUCCEEDED(rv)) {
207 tmp = aStream->Read32(&type);
208 if (NS_FAILED(tmp)) {
209 rv = tmp;
212 if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_PI) {
213 nsRefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
214 if (! pi) {
215 rv = NS_ERROR_OUT_OF_MEMORY;
216 break;
219 tmp = pi->Deserialize(aStream, this, mURI, &nodeInfos);
220 if (NS_FAILED(tmp)) {
221 rv = tmp;
223 tmp = AddProcessingInstruction(pi);
224 if (NS_FAILED(tmp)) {
225 rv = tmp;
227 } else if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_Element) {
228 tmp = mRoot->Deserialize(aStream, this, mURI, &nodeInfos);
229 if (NS_FAILED(tmp)) {
230 rv = tmp;
232 break;
233 } else {
234 NS_NOTREACHED("Unexpected prototype node type");
235 rv = NS_ERROR_FAILURE;
236 break;
239 tmp = NotifyLoadDone();
240 if (NS_FAILED(tmp)) {
241 rv = tmp;
244 return rv;
247 static nsresult
248 GetNodeInfos(nsXULPrototypeElement* aPrototype,
249 nsTArray<nsRefPtr<mozilla::dom::NodeInfo>>& aArray)
251 if (aArray.IndexOf(aPrototype->mNodeInfo) == aArray.NoIndex) {
252 aArray.AppendElement(aPrototype->mNodeInfo);
255 // Search attributes
256 uint32_t i;
257 for (i = 0; i < aPrototype->mNumAttributes; ++i) {
258 nsRefPtr<mozilla::dom::NodeInfo> ni;
259 nsAttrName* name = &aPrototype->mAttributes[i].mName;
260 if (name->IsAtom()) {
261 ni = aPrototype->mNodeInfo->NodeInfoManager()->
262 GetNodeInfo(name->Atom(), nullptr, kNameSpaceID_None,
263 nsIDOMNode::ATTRIBUTE_NODE);
265 else {
266 ni = name->NodeInfo();
269 if (aArray.IndexOf(ni) == aArray.NoIndex) {
270 aArray.AppendElement(ni);
274 // Search children
275 for (i = 0; i < aPrototype->mChildren.Length(); ++i) {
276 nsXULPrototypeNode* child = aPrototype->mChildren[i];
277 if (child->mType == nsXULPrototypeNode::eType_Element) {
278 nsresult rv =
279 GetNodeInfos(static_cast<nsXULPrototypeElement*>(child), aArray);
280 NS_ENSURE_SUCCESS(rv, rv);
284 return NS_OK;
287 NS_IMETHODIMP
288 nsXULPrototypeDocument::Write(nsIObjectOutputStream* aStream)
290 nsresult rv;
292 rv = aStream->WriteCompoundObject(mURI, NS_GET_IID(nsIURI), true);
294 uint32_t count;
296 count = mStyleSheetReferences.Count();
297 nsresult tmp = aStream->Write32(count);
298 if (NS_FAILED(tmp)) {
299 rv = tmp;
302 uint32_t i;
303 for (i = 0; i < count; ++i) {
304 tmp = aStream->WriteCompoundObject(mStyleSheetReferences[i],
305 NS_GET_IID(nsIURI), true);
306 if (NS_FAILED(tmp)) {
307 rv = tmp;
311 // nsIPrincipal mNodeInfoManager->mPrincipal
312 tmp = aStream->WriteObject(mNodeInfoManager->DocumentPrincipal(),
313 true);
314 if (NS_FAILED(tmp)) {
315 rv = tmp;
318 #ifdef DEBUG
319 // XXX Worrisome if we're caching things without system principal.
320 if (!nsContentUtils::IsSystemPrincipal(mNodeInfoManager->DocumentPrincipal())) {
321 NS_WARNING("Serializing document without system principal");
323 #endif
325 // mozilla::dom::NodeInfo table
326 nsTArray<nsRefPtr<mozilla::dom::NodeInfo>> nodeInfos;
327 if (mRoot) {
328 tmp = GetNodeInfos(mRoot, nodeInfos);
329 if (NS_FAILED(tmp)) {
330 rv = tmp;
334 uint32_t nodeInfoCount = nodeInfos.Length();
335 tmp = aStream->Write32(nodeInfoCount);
336 if (NS_FAILED(tmp)) {
337 rv = tmp;
339 for (i = 0; i < nodeInfoCount; ++i) {
340 mozilla::dom::NodeInfo *nodeInfo = nodeInfos[i];
341 NS_ENSURE_TRUE(nodeInfo, NS_ERROR_FAILURE);
343 nsAutoString namespaceURI;
344 nodeInfo->GetNamespaceURI(namespaceURI);
345 tmp = aStream->WriteWStringZ(namespaceURI.get());
346 if (NS_FAILED(tmp)) {
347 rv = tmp;
350 nsAutoString prefix;
351 nodeInfo->GetPrefix(prefix);
352 bool nullPrefix = DOMStringIsNull(prefix);
353 tmp = aStream->WriteBoolean(nullPrefix);
354 if (NS_FAILED(tmp)) {
355 rv = tmp;
357 if (!nullPrefix) {
358 tmp = aStream->WriteWStringZ(prefix.get());
359 if (NS_FAILED(tmp)) {
360 rv = tmp;
364 nsAutoString localName;
365 nodeInfo->GetName(localName);
366 tmp = aStream->WriteWStringZ(localName.get());
367 if (NS_FAILED(tmp)) {
368 rv = tmp;
372 // Now serialize the document contents
373 count = mProcessingInstructions.Length();
374 for (i = 0; i < count; ++i) {
375 nsXULPrototypePI* pi = mProcessingInstructions[i];
376 tmp = pi->Serialize(aStream, this, &nodeInfos);
377 if (NS_FAILED(tmp)) {
378 rv = tmp;
382 if (mRoot) {
383 tmp = mRoot->Serialize(aStream, this, &nodeInfos);
384 if (NS_FAILED(tmp)) {
385 rv = tmp;
389 return rv;
393 //----------------------------------------------------------------------
396 nsresult
397 nsXULPrototypeDocument::InitPrincipal(nsIURI* aURI, nsIPrincipal* aPrincipal)
399 NS_ENSURE_ARG_POINTER(aURI);
401 mURI = aURI;
402 mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
403 return NS_OK;
407 nsIURI*
408 nsXULPrototypeDocument::GetURI()
410 NS_ASSERTION(mURI, "null URI");
411 return mURI;
415 nsXULPrototypeElement*
416 nsXULPrototypeDocument::GetRootElement()
418 return mRoot;
422 void
423 nsXULPrototypeDocument::SetRootElement(nsXULPrototypeElement* aElement)
425 mRoot = aElement;
428 nsresult
429 nsXULPrototypeDocument::AddProcessingInstruction(nsXULPrototypePI* aPI)
431 NS_PRECONDITION(aPI, "null ptr");
432 if (!mProcessingInstructions.AppendElement(aPI)) {
433 return NS_ERROR_OUT_OF_MEMORY;
435 return NS_OK;
438 const nsTArray<nsRefPtr<nsXULPrototypePI> >&
439 nsXULPrototypeDocument::GetProcessingInstructions() const
441 return mProcessingInstructions;
444 void
445 nsXULPrototypeDocument::AddStyleSheetReference(nsIURI* aURI)
447 NS_PRECONDITION(aURI, "null ptr");
448 if (!mStyleSheetReferences.AppendObject(aURI)) {
449 NS_WARNING("mStyleSheetReferences->AppendElement() failed."
450 "Stylesheet overlay dropped.");
454 const nsCOMArray<nsIURI>&
455 nsXULPrototypeDocument::GetStyleSheetReferences() const
457 return mStyleSheetReferences;
460 NS_IMETHODIMP
461 nsXULPrototypeDocument::GetHeaderData(nsIAtom* aField, nsAString& aData) const
463 // XXX Not implemented
464 aData.Truncate();
465 return NS_OK;
469 NS_IMETHODIMP
470 nsXULPrototypeDocument::SetHeaderData(nsIAtom* aField, const nsAString& aData)
472 // XXX Not implemented
473 return NS_OK;
478 nsIPrincipal*
479 nsXULPrototypeDocument::DocumentPrincipal()
481 NS_PRECONDITION(mNodeInfoManager, "missing nodeInfoManager");
482 return mNodeInfoManager->DocumentPrincipal();
485 void
486 nsXULPrototypeDocument::SetDocumentPrincipal(nsIPrincipal* aPrincipal)
488 mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
491 void
492 nsXULPrototypeDocument::MarkInCCGeneration(uint32_t aCCGeneration)
494 mCCGeneration = aCCGeneration;
497 nsNodeInfoManager*
498 nsXULPrototypeDocument::GetNodeInfoManager()
500 return mNodeInfoManager;
504 nsresult
505 nsXULPrototypeDocument::AwaitLoadDone(XULDocument* aDocument, bool* aResult)
507 nsresult rv = NS_OK;
509 *aResult = mLoaded;
511 if (!mLoaded) {
512 rv = mPrototypeWaiters.AppendElement(aDocument)
513 ? NS_OK : NS_ERROR_OUT_OF_MEMORY; // addrefs
516 return rv;
520 nsresult
521 nsXULPrototypeDocument::NotifyLoadDone()
523 // Call back to each XUL document that raced to start the same
524 // prototype document load, lost the race, but hit the XUL
525 // prototype cache because the winner filled the cache with
526 // the not-yet-loaded prototype object.
528 nsresult rv = NS_OK;
530 mLoaded = true;
532 for (uint32_t i = mPrototypeWaiters.Length(); i > 0; ) {
533 --i;
534 // true means that OnPrototypeLoadDone will also
535 // call ResumeWalk().
536 rv = mPrototypeWaiters[i]->OnPrototypeLoadDone(true);
537 if (NS_FAILED(rv)) break;
539 mPrototypeWaiters.Clear();
541 return rv;
544 void
545 nsXULPrototypeDocument::TraceProtos(JSTracer* aTrc, uint32_t aGCNumber)
547 // Only trace the protos once per GC.
548 if (mGCNumber == aGCNumber) {
549 return;
552 mGCNumber = aGCNumber;
553 if (mRoot) {
554 mRoot->TraceAllScripts(aTrc);