Line data Source code
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/. */
5 :
6 :
7 : #include "nsXULPrototypeDocument.h"
8 : #include "XULDocument.h"
9 :
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 "nsDOMCID.h"
26 : #include "nsNodeInfoManager.h"
27 : #include "nsContentUtils.h"
28 : #include "nsCCUncollectableMarker.h"
29 : #include "xpcpublic.h"
30 : #include "mozilla/dom/BindingUtils.h"
31 :
32 : using mozilla::dom::DestroyProtoAndIfaceCache;
33 : using mozilla::dom::XULDocument;
34 :
35 : uint32_t nsXULPrototypeDocument::gRefCnt;
36 :
37 : //----------------------------------------------------------------------
38 : //
39 : // ctors, dtors, n' stuff
40 : //
41 :
42 6 : nsXULPrototypeDocument::nsXULPrototypeDocument()
43 : : mRoot(nullptr),
44 : mLoaded(false),
45 : mCCGeneration(0),
46 6 : mGCNumber(0)
47 : {
48 6 : ++gRefCnt;
49 6 : }
50 :
51 :
52 : nsresult
53 6 : nsXULPrototypeDocument::Init()
54 : {
55 6 : mNodeInfoManager = new nsNodeInfoManager();
56 6 : return mNodeInfoManager->Init(nullptr);
57 : }
58 :
59 0 : nsXULPrototypeDocument::~nsXULPrototypeDocument()
60 : {
61 0 : if (mRoot)
62 0 : mRoot->ReleaseSubtree();
63 0 : }
64 :
65 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeDocument)
66 :
67 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULPrototypeDocument)
68 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototypeWaiters)
69 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
70 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeDocument)
71 0 : if (nsCCUncollectableMarker::InGeneration(cb, tmp->mCCGeneration)) {
72 0 : return NS_SUCCESS_INTERRUPTED_TRAVERSE;
73 : }
74 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
75 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
76 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototypeWaiters)
77 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
78 :
79 6 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPrototypeDocument)
80 0 : NS_INTERFACE_MAP_ENTRY(nsISerializable)
81 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
82 0 : NS_INTERFACE_MAP_END
83 :
84 25 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULPrototypeDocument)
85 11 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULPrototypeDocument)
86 :
87 : NS_IMETHODIMP
88 6 : NS_NewXULPrototypeDocument(nsXULPrototypeDocument** aResult)
89 : {
90 6 : *aResult = nullptr;
91 : RefPtr<nsXULPrototypeDocument> doc =
92 12 : new nsXULPrototypeDocument();
93 :
94 6 : nsresult rv = doc->Init();
95 6 : if (NS_FAILED(rv)) {
96 0 : return rv;
97 : }
98 :
99 6 : doc.forget(aResult);
100 6 : return rv;
101 : }
102 :
103 : //----------------------------------------------------------------------
104 : //
105 : // nsISerializable methods
106 : //
107 :
108 : NS_IMETHODIMP
109 6 : nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
110 : {
111 : nsresult rv;
112 :
113 12 : nsCOMPtr<nsISupports> supports;
114 6 : rv = aStream->ReadObject(true, getter_AddRefs(supports));
115 6 : mURI = do_QueryInterface(supports);
116 :
117 : uint32_t count, i;
118 12 : nsCOMPtr<nsIURI> styleOverlayURI;
119 :
120 6 : nsresult tmp = aStream->Read32(&count);
121 6 : if (NS_FAILED(tmp)) {
122 0 : return tmp;
123 : }
124 6 : if (NS_FAILED(rv)) {
125 0 : return rv;
126 : }
127 :
128 6 : for (i = 0; i < count; ++i) {
129 0 : tmp = aStream->ReadObject(true, getter_AddRefs(supports));
130 0 : if (NS_FAILED(tmp)) {
131 0 : rv = tmp;
132 : }
133 0 : styleOverlayURI = do_QueryInterface(supports);
134 0 : mStyleSheetReferences.AppendObject(styleOverlayURI);
135 : }
136 :
137 :
138 : // nsIPrincipal mNodeInfoManager->mPrincipal
139 12 : nsCOMPtr<nsIPrincipal> principal;
140 6 : tmp = aStream->ReadObject(true, getter_AddRefs(supports));
141 6 : principal = do_QueryInterface(supports);
142 6 : if (NS_FAILED(tmp)) {
143 0 : rv = tmp;
144 : }
145 : // Better safe than sorry....
146 6 : mNodeInfoManager->SetDocumentPrincipal(principal);
147 :
148 6 : mRoot = new nsXULPrototypeElement();
149 :
150 : // mozilla::dom::NodeInfo table
151 12 : nsTArray<RefPtr<mozilla::dom::NodeInfo>> nodeInfos;
152 :
153 6 : tmp = aStream->Read32(&count);
154 6 : if (NS_FAILED(tmp)) {
155 0 : rv = tmp;
156 : }
157 12 : nsAutoString namespaceURI, prefixStr, localName;
158 : bool prefixIsNull;
159 12 : nsCOMPtr<nsIAtom> prefix;
160 401 : for (i = 0; i < count; ++i) {
161 395 : tmp = aStream->ReadString(namespaceURI);
162 395 : if (NS_FAILED(tmp)) {
163 0 : rv = tmp;
164 : }
165 395 : tmp = aStream->ReadBoolean(&prefixIsNull);
166 395 : if (NS_FAILED(tmp)) {
167 0 : rv = tmp;
168 : }
169 395 : if (prefixIsNull) {
170 379 : prefix = nullptr;
171 : } else {
172 16 : tmp = aStream->ReadString(prefixStr);
173 16 : if (NS_FAILED(tmp)) {
174 0 : rv = tmp;
175 : }
176 16 : prefix = NS_Atomize(prefixStr);
177 : }
178 395 : tmp = aStream->ReadString(localName);
179 395 : if (NS_FAILED(tmp)) {
180 0 : rv = tmp;
181 : }
182 :
183 790 : RefPtr<mozilla::dom::NodeInfo> nodeInfo;
184 : // Using UINT16_MAX here as we don't know which nodeinfos will be
185 : // used for attributes and which for elements. And that doesn't really
186 : // matter.
187 395 : tmp = mNodeInfoManager->GetNodeInfo(localName, prefix, namespaceURI,
188 : UINT16_MAX,
189 790 : getter_AddRefs(nodeInfo));
190 395 : if (NS_FAILED(tmp)) {
191 0 : rv = tmp;
192 : }
193 395 : nodeInfos.AppendElement(nodeInfo);
194 : }
195 :
196 : // Document contents
197 : uint32_t type;
198 24 : while (NS_SUCCEEDED(rv)) {
199 15 : tmp = aStream->Read32(&type);
200 15 : if (NS_FAILED(tmp)) {
201 0 : rv = tmp;
202 : }
203 :
204 15 : if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_PI) {
205 18 : RefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
206 :
207 9 : tmp = pi->Deserialize(aStream, this, mURI, &nodeInfos);
208 9 : if (NS_FAILED(tmp)) {
209 0 : rv = tmp;
210 : }
211 9 : tmp = AddProcessingInstruction(pi);
212 9 : if (NS_FAILED(tmp)) {
213 0 : rv = tmp;
214 : }
215 6 : } else if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_Element) {
216 6 : tmp = mRoot->Deserialize(aStream, this, mURI, &nodeInfos);
217 6 : if (NS_FAILED(tmp)) {
218 0 : rv = tmp;
219 : }
220 6 : break;
221 : } else {
222 0 : NS_NOTREACHED("Unexpected prototype node type");
223 0 : rv = NS_ERROR_FAILURE;
224 0 : break;
225 : }
226 : }
227 6 : tmp = NotifyLoadDone();
228 6 : if (NS_FAILED(tmp)) {
229 0 : rv = tmp;
230 : }
231 :
232 6 : return rv;
233 : }
234 :
235 : static nsresult
236 0 : GetNodeInfos(nsXULPrototypeElement* aPrototype,
237 : nsTArray<RefPtr<mozilla::dom::NodeInfo>>& aArray)
238 : {
239 0 : if (aArray.IndexOf(aPrototype->mNodeInfo) == aArray.NoIndex) {
240 0 : aArray.AppendElement(aPrototype->mNodeInfo);
241 : }
242 :
243 : // Search attributes
244 : uint32_t i;
245 0 : for (i = 0; i < aPrototype->mNumAttributes; ++i) {
246 0 : RefPtr<mozilla::dom::NodeInfo> ni;
247 0 : nsAttrName* name = &aPrototype->mAttributes[i].mName;
248 0 : if (name->IsAtom()) {
249 : ni = aPrototype->mNodeInfo->NodeInfoManager()->
250 0 : GetNodeInfo(name->Atom(), nullptr, kNameSpaceID_None,
251 0 : nsIDOMNode::ATTRIBUTE_NODE);
252 : }
253 : else {
254 0 : ni = name->NodeInfo();
255 : }
256 :
257 0 : if (aArray.IndexOf(ni) == aArray.NoIndex) {
258 0 : aArray.AppendElement(ni);
259 : }
260 : }
261 :
262 : // Search children
263 0 : for (i = 0; i < aPrototype->mChildren.Length(); ++i) {
264 0 : nsXULPrototypeNode* child = aPrototype->mChildren[i];
265 0 : if (child->mType == nsXULPrototypeNode::eType_Element) {
266 : nsresult rv =
267 0 : GetNodeInfos(static_cast<nsXULPrototypeElement*>(child), aArray);
268 0 : NS_ENSURE_SUCCESS(rv, rv);
269 : }
270 : }
271 :
272 0 : return NS_OK;
273 : }
274 :
275 : NS_IMETHODIMP
276 0 : nsXULPrototypeDocument::Write(nsIObjectOutputStream* aStream)
277 : {
278 : nsresult rv;
279 :
280 0 : rv = aStream->WriteCompoundObject(mURI, NS_GET_IID(nsIURI), true);
281 :
282 : uint32_t count;
283 :
284 0 : count = mStyleSheetReferences.Count();
285 0 : nsresult tmp = aStream->Write32(count);
286 0 : if (NS_FAILED(tmp)) {
287 0 : rv = tmp;
288 : }
289 :
290 : uint32_t i;
291 0 : for (i = 0; i < count; ++i) {
292 0 : tmp = aStream->WriteCompoundObject(mStyleSheetReferences[i],
293 0 : NS_GET_IID(nsIURI), true);
294 0 : if (NS_FAILED(tmp)) {
295 0 : rv = tmp;
296 : }
297 : }
298 :
299 : // nsIPrincipal mNodeInfoManager->mPrincipal
300 0 : tmp = aStream->WriteObject(mNodeInfoManager->DocumentPrincipal(),
301 0 : true);
302 0 : if (NS_FAILED(tmp)) {
303 0 : rv = tmp;
304 : }
305 :
306 : #ifdef DEBUG
307 : // XXX Worrisome if we're caching things without system principal.
308 0 : if (!nsContentUtils::IsSystemPrincipal(mNodeInfoManager->DocumentPrincipal())) {
309 0 : NS_WARNING("Serializing document without system principal");
310 : }
311 : #endif
312 :
313 : // mozilla::dom::NodeInfo table
314 0 : nsTArray<RefPtr<mozilla::dom::NodeInfo>> nodeInfos;
315 0 : if (mRoot) {
316 0 : tmp = GetNodeInfos(mRoot, nodeInfos);
317 0 : if (NS_FAILED(tmp)) {
318 0 : rv = tmp;
319 : }
320 : }
321 :
322 0 : uint32_t nodeInfoCount = nodeInfos.Length();
323 0 : tmp = aStream->Write32(nodeInfoCount);
324 0 : if (NS_FAILED(tmp)) {
325 0 : rv = tmp;
326 : }
327 0 : for (i = 0; i < nodeInfoCount; ++i) {
328 0 : mozilla::dom::NodeInfo *nodeInfo = nodeInfos[i];
329 0 : NS_ENSURE_TRUE(nodeInfo, NS_ERROR_FAILURE);
330 :
331 0 : nsAutoString namespaceURI;
332 0 : nodeInfo->GetNamespaceURI(namespaceURI);
333 0 : tmp = aStream->WriteWStringZ(namespaceURI.get());
334 0 : if (NS_FAILED(tmp)) {
335 0 : rv = tmp;
336 : }
337 :
338 0 : nsAutoString prefix;
339 0 : nodeInfo->GetPrefix(prefix);
340 0 : bool nullPrefix = DOMStringIsNull(prefix);
341 0 : tmp = aStream->WriteBoolean(nullPrefix);
342 0 : if (NS_FAILED(tmp)) {
343 0 : rv = tmp;
344 : }
345 0 : if (!nullPrefix) {
346 0 : tmp = aStream->WriteWStringZ(prefix.get());
347 0 : if (NS_FAILED(tmp)) {
348 0 : rv = tmp;
349 : }
350 : }
351 :
352 0 : nsAutoString localName;
353 0 : nodeInfo->GetName(localName);
354 0 : tmp = aStream->WriteWStringZ(localName.get());
355 0 : if (NS_FAILED(tmp)) {
356 0 : rv = tmp;
357 : }
358 : }
359 :
360 : // Now serialize the document contents
361 0 : count = mProcessingInstructions.Length();
362 0 : for (i = 0; i < count; ++i) {
363 0 : nsXULPrototypePI* pi = mProcessingInstructions[i];
364 0 : tmp = pi->Serialize(aStream, this, &nodeInfos);
365 0 : if (NS_FAILED(tmp)) {
366 0 : rv = tmp;
367 : }
368 : }
369 :
370 0 : if (mRoot) {
371 0 : tmp = mRoot->Serialize(aStream, this, &nodeInfos);
372 0 : if (NS_FAILED(tmp)) {
373 0 : rv = tmp;
374 : }
375 : }
376 :
377 0 : return rv;
378 : }
379 :
380 :
381 : //----------------------------------------------------------------------
382 : //
383 :
384 : nsresult
385 0 : nsXULPrototypeDocument::InitPrincipal(nsIURI* aURI, nsIPrincipal* aPrincipal)
386 : {
387 0 : NS_ENSURE_ARG_POINTER(aURI);
388 :
389 0 : mURI = aURI;
390 0 : mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
391 0 : return NS_OK;
392 : }
393 :
394 :
395 : nsIURI*
396 67 : nsXULPrototypeDocument::GetURI()
397 : {
398 67 : NS_ASSERTION(mURI, "null URI");
399 67 : return mURI;
400 : }
401 :
402 :
403 : nsXULPrototypeElement*
404 6 : nsXULPrototypeDocument::GetRootElement()
405 : {
406 6 : return mRoot;
407 : }
408 :
409 :
410 : void
411 0 : nsXULPrototypeDocument::SetRootElement(nsXULPrototypeElement* aElement)
412 : {
413 0 : mRoot = aElement;
414 0 : }
415 :
416 : nsresult
417 9 : nsXULPrototypeDocument::AddProcessingInstruction(nsXULPrototypePI* aPI)
418 : {
419 9 : NS_PRECONDITION(aPI, "null ptr");
420 9 : if (!mProcessingInstructions.AppendElement(aPI)) {
421 0 : return NS_ERROR_OUT_OF_MEMORY;
422 : }
423 9 : return NS_OK;
424 : }
425 :
426 : const nsTArray<RefPtr<nsXULPrototypePI> >&
427 6 : nsXULPrototypeDocument::GetProcessingInstructions() const
428 : {
429 6 : return mProcessingInstructions;
430 : }
431 :
432 : void
433 0 : nsXULPrototypeDocument::AddStyleSheetReference(nsIURI* aURI)
434 : {
435 0 : NS_PRECONDITION(aURI, "null ptr");
436 0 : if (!mStyleSheetReferences.AppendObject(aURI)) {
437 : NS_WARNING("mStyleSheetReferences->AppendElement() failed."
438 0 : "Stylesheet overlay dropped.");
439 : }
440 0 : }
441 :
442 : const nsCOMArray<nsIURI>&
443 6 : nsXULPrototypeDocument::GetStyleSheetReferences() const
444 : {
445 6 : return mStyleSheetReferences;
446 : }
447 :
448 : NS_IMETHODIMP
449 0 : nsXULPrototypeDocument::GetHeaderData(nsIAtom* aField, nsAString& aData) const
450 : {
451 : // XXX Not implemented
452 0 : aData.Truncate();
453 0 : return NS_OK;
454 : }
455 :
456 :
457 : NS_IMETHODIMP
458 0 : nsXULPrototypeDocument::SetHeaderData(nsIAtom* aField, const nsAString& aData)
459 : {
460 : // XXX Not implemented
461 0 : return NS_OK;
462 : }
463 :
464 :
465 :
466 : nsIPrincipal*
467 1 : nsXULPrototypeDocument::DocumentPrincipal()
468 : {
469 1 : NS_PRECONDITION(mNodeInfoManager, "missing nodeInfoManager");
470 1 : return mNodeInfoManager->DocumentPrincipal();
471 : }
472 :
473 : void
474 0 : nsXULPrototypeDocument::SetDocumentPrincipal(nsIPrincipal* aPrincipal)
475 : {
476 0 : mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
477 0 : }
478 :
479 : void
480 0 : nsXULPrototypeDocument::MarkInCCGeneration(uint32_t aCCGeneration)
481 : {
482 0 : mCCGeneration = aCCGeneration;
483 0 : }
484 :
485 : nsNodeInfoManager*
486 0 : nsXULPrototypeDocument::GetNodeInfoManager()
487 : {
488 0 : return mNodeInfoManager;
489 : }
490 :
491 :
492 : nsresult
493 6 : nsXULPrototypeDocument::AwaitLoadDone(XULDocument* aDocument, bool* aResult)
494 : {
495 6 : nsresult rv = NS_OK;
496 :
497 6 : *aResult = mLoaded;
498 :
499 6 : if (!mLoaded) {
500 0 : rv = mPrototypeWaiters.AppendElement(aDocument)
501 0 : ? NS_OK : NS_ERROR_OUT_OF_MEMORY; // addrefs
502 : }
503 :
504 6 : return rv;
505 : }
506 :
507 :
508 : nsresult
509 6 : nsXULPrototypeDocument::NotifyLoadDone()
510 : {
511 : // Call back to each XUL document that raced to start the same
512 : // prototype document load, lost the race, but hit the XUL
513 : // prototype cache because the winner filled the cache with
514 : // the not-yet-loaded prototype object.
515 :
516 6 : nsresult rv = NS_OK;
517 :
518 6 : mLoaded = true;
519 :
520 6 : for (uint32_t i = mPrototypeWaiters.Length(); i > 0; ) {
521 0 : --i;
522 : // true means that OnPrototypeLoadDone will also
523 : // call ResumeWalk().
524 0 : rv = mPrototypeWaiters[i]->OnPrototypeLoadDone(true);
525 0 : if (NS_FAILED(rv)) break;
526 : }
527 6 : mPrototypeWaiters.Clear();
528 :
529 6 : return rv;
530 : }
531 :
532 : void
533 7 : nsXULPrototypeDocument::TraceProtos(JSTracer* aTrc, uint32_t aGCNumber)
534 : {
535 : // Only trace the protos once per GC.
536 7 : if (mGCNumber == aGCNumber) {
537 1 : return;
538 : }
539 :
540 6 : mGCNumber = aGCNumber;
541 6 : if (mRoot) {
542 6 : mRoot->TraceAllScripts(aTrc);
543 : }
544 9 : }
|