|
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 #include "mozilla/ArrayUtils.h" |
|
7 |
|
8 #include "nsCOMPtr.h" |
|
9 #include "nsIAtom.h" |
|
10 #include "nsIInputStream.h" |
|
11 #include "nsNameSpaceManager.h" |
|
12 #include "nsIURI.h" |
|
13 #include "nsIURL.h" |
|
14 #include "nsIChannel.h" |
|
15 #include "nsXPIDLString.h" |
|
16 #include "nsReadableUtils.h" |
|
17 #include "nsNetUtil.h" |
|
18 #include "plstr.h" |
|
19 #include "nsContentCreatorFunctions.h" |
|
20 #include "nsIDocument.h" |
|
21 #include "nsIXMLContentSink.h" |
|
22 #include "nsContentCID.h" |
|
23 #include "mozilla/dom/XMLDocument.h" |
|
24 #include "nsXBLService.h" |
|
25 #include "nsXBLBinding.h" |
|
26 #include "nsXBLPrototypeBinding.h" |
|
27 #include "nsXBLContentSink.h" |
|
28 #include "xptinfo.h" |
|
29 #include "nsIInterfaceInfoManager.h" |
|
30 #include "nsIDocumentObserver.h" |
|
31 #include "nsGkAtoms.h" |
|
32 #include "nsXBLProtoImpl.h" |
|
33 #include "nsCRT.h" |
|
34 #include "nsContentUtils.h" |
|
35 #include "nsTextFragment.h" |
|
36 #include "nsTextNode.h" |
|
37 #include "nsIInterfaceInfo.h" |
|
38 #include "nsIScriptError.h" |
|
39 |
|
40 #include "nsIStyleRuleProcessor.h" |
|
41 #include "nsXBLResourceLoader.h" |
|
42 #include "mozilla/dom/CDATASection.h" |
|
43 #include "mozilla/dom/Comment.h" |
|
44 #include "mozilla/dom/Element.h" |
|
45 |
|
46 #ifdef MOZ_XUL |
|
47 #include "nsXULElement.h" |
|
48 #endif |
|
49 |
|
50 using namespace mozilla; |
|
51 using namespace mozilla::dom; |
|
52 |
|
53 // Helper Classes ===================================================================== |
|
54 |
|
55 // nsXBLAttributeEntry and helpers. This class is used to efficiently handle |
|
56 // attribute changes in anonymous content. |
|
57 |
|
58 class nsXBLAttributeEntry { |
|
59 public: |
|
60 nsXBLAttributeEntry(nsIAtom* aSrcAtom, nsIAtom* aDstAtom, |
|
61 int32_t aDstNameSpace, nsIContent* aContent) |
|
62 : mElement(aContent), |
|
63 mSrcAttribute(aSrcAtom), |
|
64 mDstAttribute(aDstAtom), |
|
65 mDstNameSpace(aDstNameSpace), |
|
66 mNext(nullptr) { } |
|
67 |
|
68 ~nsXBLAttributeEntry() { |
|
69 NS_CONTENT_DELETE_LIST_MEMBER(nsXBLAttributeEntry, this, mNext); |
|
70 } |
|
71 |
|
72 nsIAtom* GetSrcAttribute() { return mSrcAttribute; } |
|
73 nsIAtom* GetDstAttribute() { return mDstAttribute; } |
|
74 int32_t GetDstNameSpace() { return mDstNameSpace; } |
|
75 |
|
76 nsIContent* GetElement() { return mElement; } |
|
77 |
|
78 nsXBLAttributeEntry* GetNext() { return mNext; } |
|
79 void SetNext(nsXBLAttributeEntry* aEntry) { mNext = aEntry; } |
|
80 |
|
81 protected: |
|
82 nsIContent* mElement; |
|
83 |
|
84 nsCOMPtr<nsIAtom> mSrcAttribute; |
|
85 nsCOMPtr<nsIAtom> mDstAttribute; |
|
86 int32_t mDstNameSpace; |
|
87 nsXBLAttributeEntry* mNext; |
|
88 }; |
|
89 |
|
90 // ============================================================================= |
|
91 |
|
92 // Implementation ///////////////////////////////////////////////////////////////// |
|
93 |
|
94 // Constructors/Destructors |
|
95 nsXBLPrototypeBinding::nsXBLPrototypeBinding() |
|
96 : mImplementation(nullptr), |
|
97 mBaseBinding(nullptr), |
|
98 mInheritStyle(true), |
|
99 mCheckedBaseProto(false), |
|
100 mKeyHandlersRegistered(false), |
|
101 mChromeOnlyContent(false), |
|
102 mResources(nullptr), |
|
103 mBaseNameSpaceID(kNameSpaceID_None) |
|
104 { |
|
105 MOZ_COUNT_CTOR(nsXBLPrototypeBinding); |
|
106 } |
|
107 |
|
108 nsresult |
|
109 nsXBLPrototypeBinding::Init(const nsACString& aID, |
|
110 nsXBLDocumentInfo* aInfo, |
|
111 nsIContent* aElement, |
|
112 bool aFirstBinding) |
|
113 { |
|
114 nsresult rv = aInfo->DocumentURI()->Clone(getter_AddRefs(mBindingURI)); |
|
115 NS_ENSURE_SUCCESS(rv, rv); |
|
116 |
|
117 // The binding URI might be an immutable URI (e.g. for about: URIs). In that case, |
|
118 // we'll fail in SetRef below, but that doesn't matter much for now. |
|
119 if (aFirstBinding) { |
|
120 rv = mBindingURI->Clone(getter_AddRefs(mAlternateBindingURI)); |
|
121 NS_ENSURE_SUCCESS(rv, rv); |
|
122 } |
|
123 mBindingURI->SetRef(aID); |
|
124 |
|
125 mXBLDocInfoWeak = aInfo; |
|
126 |
|
127 // aElement will be null when reading from the cache, but the element will |
|
128 // still be set later. |
|
129 if (aElement) { |
|
130 SetBindingElement(aElement); |
|
131 } |
|
132 return NS_OK; |
|
133 } |
|
134 |
|
135 bool nsXBLPrototypeBinding::CompareBindingURI(nsIURI* aURI) const |
|
136 { |
|
137 bool equal = false; |
|
138 mBindingURI->Equals(aURI, &equal); |
|
139 if (!equal && mAlternateBindingURI) { |
|
140 mAlternateBindingURI->Equals(aURI, &equal); |
|
141 } |
|
142 return equal; |
|
143 } |
|
144 |
|
145 void |
|
146 nsXBLPrototypeBinding::Traverse(nsCycleCollectionTraversalCallback &cb) const |
|
147 { |
|
148 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "proto mBinding"); |
|
149 cb.NoteXPCOMChild(mBinding); |
|
150 if (mResources) { |
|
151 mResources->Traverse(cb); |
|
152 } |
|
153 ImplCycleCollectionTraverse(cb, mInterfaceTable, "proto mInterfaceTable"); |
|
154 } |
|
155 |
|
156 void |
|
157 nsXBLPrototypeBinding::UnlinkJSObjects() |
|
158 { |
|
159 if (mImplementation) |
|
160 mImplementation->UnlinkJSObjects(); |
|
161 } |
|
162 |
|
163 void |
|
164 nsXBLPrototypeBinding::Trace(const TraceCallbacks& aCallbacks, void *aClosure) const |
|
165 { |
|
166 if (mImplementation) |
|
167 mImplementation->Trace(aCallbacks, aClosure); |
|
168 } |
|
169 |
|
170 void |
|
171 nsXBLPrototypeBinding::Initialize() |
|
172 { |
|
173 nsIContent* content = GetImmediateChild(nsGkAtoms::content); |
|
174 if (content) { |
|
175 ConstructAttributeTable(content); |
|
176 } |
|
177 } |
|
178 |
|
179 nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void) |
|
180 { |
|
181 delete mImplementation; |
|
182 MOZ_COUNT_DTOR(nsXBLPrototypeBinding); |
|
183 } |
|
184 |
|
185 void |
|
186 nsXBLPrototypeBinding::SetBasePrototype(nsXBLPrototypeBinding* aBinding) |
|
187 { |
|
188 if (mBaseBinding == aBinding) |
|
189 return; |
|
190 |
|
191 if (mBaseBinding) { |
|
192 NS_ERROR("Base XBL prototype binding is already defined!"); |
|
193 return; |
|
194 } |
|
195 |
|
196 mBaseBinding = aBinding; |
|
197 } |
|
198 |
|
199 void |
|
200 nsXBLPrototypeBinding::SetBindingElement(nsIContent* aElement) |
|
201 { |
|
202 mBinding = aElement; |
|
203 if (mBinding->AttrValueIs(kNameSpaceID_None, nsGkAtoms::inheritstyle, |
|
204 nsGkAtoms::_false, eCaseMatters)) |
|
205 mInheritStyle = false; |
|
206 |
|
207 mChromeOnlyContent = mBinding->AttrValueIs(kNameSpaceID_None, |
|
208 nsGkAtoms::chromeOnlyContent, |
|
209 nsGkAtoms::_true, eCaseMatters); |
|
210 } |
|
211 |
|
212 bool |
|
213 nsXBLPrototypeBinding::GetAllowScripts() const |
|
214 { |
|
215 return mXBLDocInfoWeak->GetScriptAccess(); |
|
216 } |
|
217 |
|
218 bool |
|
219 nsXBLPrototypeBinding::LoadResources() |
|
220 { |
|
221 if (mResources) { |
|
222 bool result; |
|
223 mResources->LoadResources(&result); |
|
224 return result; |
|
225 } |
|
226 |
|
227 return true; |
|
228 } |
|
229 |
|
230 nsresult |
|
231 nsXBLPrototypeBinding::AddResource(nsIAtom* aResourceType, const nsAString& aSrc) |
|
232 { |
|
233 if (!mResources) { |
|
234 mResources = new nsXBLPrototypeResources(this); |
|
235 } |
|
236 |
|
237 mResources->AddResource(aResourceType, aSrc); |
|
238 return NS_OK; |
|
239 } |
|
240 |
|
241 nsresult |
|
242 nsXBLPrototypeBinding::FlushSkinSheets() |
|
243 { |
|
244 if (mResources) |
|
245 return mResources->FlushSkinSheets(); |
|
246 return NS_OK; |
|
247 } |
|
248 |
|
249 nsresult |
|
250 nsXBLPrototypeBinding::BindingAttached(nsIContent* aBoundElement) |
|
251 { |
|
252 if (mImplementation && mImplementation->CompiledMembers() && |
|
253 mImplementation->mConstructor) |
|
254 return mImplementation->mConstructor->Execute(aBoundElement); |
|
255 return NS_OK; |
|
256 } |
|
257 |
|
258 nsresult |
|
259 nsXBLPrototypeBinding::BindingDetached(nsIContent* aBoundElement) |
|
260 { |
|
261 if (mImplementation && mImplementation->CompiledMembers() && |
|
262 mImplementation->mDestructor) |
|
263 return mImplementation->mDestructor->Execute(aBoundElement); |
|
264 return NS_OK; |
|
265 } |
|
266 |
|
267 nsXBLProtoImplAnonymousMethod* |
|
268 nsXBLPrototypeBinding::GetConstructor() |
|
269 { |
|
270 if (mImplementation) |
|
271 return mImplementation->mConstructor; |
|
272 |
|
273 return nullptr; |
|
274 } |
|
275 |
|
276 nsXBLProtoImplAnonymousMethod* |
|
277 nsXBLPrototypeBinding::GetDestructor() |
|
278 { |
|
279 if (mImplementation) |
|
280 return mImplementation->mDestructor; |
|
281 |
|
282 return nullptr; |
|
283 } |
|
284 |
|
285 nsresult |
|
286 nsXBLPrototypeBinding::SetConstructor(nsXBLProtoImplAnonymousMethod* aMethod) |
|
287 { |
|
288 if (!mImplementation) |
|
289 return NS_ERROR_FAILURE; |
|
290 mImplementation->mConstructor = aMethod; |
|
291 return NS_OK; |
|
292 } |
|
293 |
|
294 nsresult |
|
295 nsXBLPrototypeBinding::SetDestructor(nsXBLProtoImplAnonymousMethod* aMethod) |
|
296 { |
|
297 if (!mImplementation) |
|
298 return NS_ERROR_FAILURE; |
|
299 mImplementation->mDestructor = aMethod; |
|
300 return NS_OK; |
|
301 } |
|
302 |
|
303 nsresult |
|
304 nsXBLPrototypeBinding::InstallImplementation(nsXBLBinding* aBinding) |
|
305 { |
|
306 if (mImplementation) |
|
307 return mImplementation->InstallImplementation(this, aBinding); |
|
308 return NS_OK; |
|
309 } |
|
310 |
|
311 // XXXbz this duplicates lots of SetAttrs |
|
312 void |
|
313 nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute, |
|
314 int32_t aNameSpaceID, |
|
315 bool aRemoveFlag, |
|
316 nsIContent* aChangedElement, |
|
317 nsIContent* aAnonymousContent, |
|
318 bool aNotify) |
|
319 { |
|
320 if (!mAttributeTable) |
|
321 return; |
|
322 |
|
323 InnerAttributeTable *attributesNS = mAttributeTable->Get(aNameSpaceID); |
|
324 if (!attributesNS) |
|
325 return; |
|
326 |
|
327 nsXBLAttributeEntry* xblAttr = attributesNS->Get(aAttribute); |
|
328 if (!xblAttr) |
|
329 return; |
|
330 |
|
331 // Iterate over the elements in the array. |
|
332 nsCOMPtr<nsIContent> content = GetImmediateChild(nsGkAtoms::content); |
|
333 while (xblAttr) { |
|
334 nsIContent* element = xblAttr->GetElement(); |
|
335 |
|
336 nsCOMPtr<nsIContent> realElement = LocateInstance(aChangedElement, content, |
|
337 aAnonymousContent, |
|
338 element); |
|
339 |
|
340 if (realElement) { |
|
341 // Hold a strong reference here so that the atom doesn't go away during |
|
342 // UnsetAttr. |
|
343 nsCOMPtr<nsIAtom> dstAttr = xblAttr->GetDstAttribute(); |
|
344 int32_t dstNs = xblAttr->GetDstNameSpace(); |
|
345 |
|
346 if (aRemoveFlag) |
|
347 realElement->UnsetAttr(dstNs, dstAttr, aNotify); |
|
348 else { |
|
349 bool attrPresent = true; |
|
350 nsAutoString value; |
|
351 // Check to see if the src attribute is xbl:text. If so, then we need to obtain the |
|
352 // children of the real element and get the text nodes' values. |
|
353 if (aAttribute == nsGkAtoms::text && aNameSpaceID == kNameSpaceID_XBL) { |
|
354 if (!nsContentUtils::GetNodeTextContent(aChangedElement, false, value)) { |
|
355 NS_RUNTIMEABORT("OOM"); |
|
356 } |
|
357 value.StripChar(char16_t('\n')); |
|
358 value.StripChar(char16_t('\r')); |
|
359 nsAutoString stripVal(value); |
|
360 stripVal.StripWhitespace(); |
|
361 if (stripVal.IsEmpty()) |
|
362 attrPresent = false; |
|
363 } |
|
364 else { |
|
365 attrPresent = aChangedElement->GetAttr(aNameSpaceID, aAttribute, value); |
|
366 } |
|
367 |
|
368 if (attrPresent) |
|
369 realElement->SetAttr(dstNs, dstAttr, value, aNotify); |
|
370 } |
|
371 |
|
372 // See if we're the <html> tag in XUL, and see if value is being |
|
373 // set or unset on us. We may also be a tag that is having |
|
374 // xbl:text set on us. |
|
375 |
|
376 if ((dstAttr == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) || |
|
377 (realElement->NodeInfo()->Equals(nsGkAtoms::html, |
|
378 kNameSpaceID_XUL) && |
|
379 dstAttr == nsGkAtoms::value)) { |
|
380 // Flush out all our kids. |
|
381 uint32_t childCount = realElement->GetChildCount(); |
|
382 for (uint32_t i = 0; i < childCount; i++) |
|
383 realElement->RemoveChildAt(0, aNotify); |
|
384 |
|
385 if (!aRemoveFlag) { |
|
386 // Construct a new text node and insert it. |
|
387 nsAutoString value; |
|
388 aChangedElement->GetAttr(aNameSpaceID, aAttribute, value); |
|
389 if (!value.IsEmpty()) { |
|
390 nsRefPtr<nsTextNode> textContent = |
|
391 new nsTextNode(realElement->NodeInfo()->NodeInfoManager()); |
|
392 |
|
393 textContent->SetText(value, true); |
|
394 realElement->AppendChildTo(textContent, true); |
|
395 } |
|
396 } |
|
397 } |
|
398 } |
|
399 |
|
400 xblAttr = xblAttr->GetNext(); |
|
401 } |
|
402 } |
|
403 |
|
404 void |
|
405 nsXBLPrototypeBinding::SetBaseTag(int32_t aNamespaceID, nsIAtom* aTag) |
|
406 { |
|
407 mBaseNameSpaceID = aNamespaceID; |
|
408 mBaseTag = aTag; |
|
409 } |
|
410 |
|
411 nsIAtom* |
|
412 nsXBLPrototypeBinding::GetBaseTag(int32_t* aNamespaceID) |
|
413 { |
|
414 if (mBaseTag) { |
|
415 *aNamespaceID = mBaseNameSpaceID; |
|
416 return mBaseTag; |
|
417 } |
|
418 |
|
419 return nullptr; |
|
420 } |
|
421 |
|
422 bool |
|
423 nsXBLPrototypeBinding::ImplementsInterface(REFNSIID aIID) const |
|
424 { |
|
425 // Check our IID table. |
|
426 return !!mInterfaceTable.GetWeak(aIID); |
|
427 } |
|
428 |
|
429 // Internal helpers /////////////////////////////////////////////////////////////////////// |
|
430 |
|
431 nsIContent* |
|
432 nsXBLPrototypeBinding::GetImmediateChild(nsIAtom* aTag) |
|
433 { |
|
434 for (nsIContent* child = mBinding->GetFirstChild(); |
|
435 child; |
|
436 child = child->GetNextSibling()) { |
|
437 if (child->NodeInfo()->Equals(aTag, kNameSpaceID_XBL)) { |
|
438 return child; |
|
439 } |
|
440 } |
|
441 |
|
442 return nullptr; |
|
443 } |
|
444 |
|
445 nsresult |
|
446 nsXBLPrototypeBinding::InitClass(const nsCString& aClassName, |
|
447 JSContext * aContext, |
|
448 JS::Handle<JSObject*> aScriptObject, |
|
449 JS::MutableHandle<JSObject*> aClassObject, |
|
450 bool* aNew) |
|
451 { |
|
452 return nsXBLBinding::DoInitJSClass(aContext, aScriptObject, |
|
453 aClassName, this, aClassObject, aNew); |
|
454 } |
|
455 |
|
456 nsIContent* |
|
457 nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement, |
|
458 nsIContent* aTemplRoot, |
|
459 nsIContent* aCopyRoot, |
|
460 nsIContent* aTemplChild) |
|
461 { |
|
462 // XXX We will get in trouble if the binding instantiation deviates from the template |
|
463 // in the prototype. |
|
464 if (aTemplChild == aTemplRoot || !aTemplChild) |
|
465 return nullptr; |
|
466 |
|
467 nsIContent* templParent = aTemplChild->GetParent(); |
|
468 |
|
469 // We may be disconnected from our parent during cycle collection. |
|
470 if (!templParent) |
|
471 return nullptr; |
|
472 |
|
473 nsIContent *copyParent = |
|
474 templParent == aTemplRoot ? aCopyRoot : |
|
475 LocateInstance(aBoundElement, aTemplRoot, aCopyRoot, templParent); |
|
476 |
|
477 if (!copyParent) |
|
478 return nullptr; |
|
479 |
|
480 return copyParent->GetChildAt(templParent->IndexOf(aTemplChild)); |
|
481 } |
|
482 |
|
483 struct nsXBLAttrChangeData |
|
484 { |
|
485 nsXBLPrototypeBinding* mProto; |
|
486 nsIContent* mBoundElement; |
|
487 nsIContent* mContent; |
|
488 int32_t mSrcNamespace; |
|
489 |
|
490 nsXBLAttrChangeData(nsXBLPrototypeBinding* aProto, |
|
491 nsIContent* aElt, nsIContent* aContent) |
|
492 :mProto(aProto), mBoundElement(aElt), mContent(aContent) {} |
|
493 }; |
|
494 |
|
495 // XXXbz this duplicates lots of AttributeChanged |
|
496 static PLDHashOperator |
|
497 SetAttrs(nsISupports* aKey, nsXBLAttributeEntry* aEntry, void* aClosure) |
|
498 { |
|
499 nsXBLAttrChangeData* changeData = static_cast<nsXBLAttrChangeData*>(aClosure); |
|
500 |
|
501 nsIAtom* src = aEntry->GetSrcAttribute(); |
|
502 int32_t srcNs = changeData->mSrcNamespace; |
|
503 nsAutoString value; |
|
504 bool attrPresent = true; |
|
505 |
|
506 if (src == nsGkAtoms::text && srcNs == kNameSpaceID_XBL) { |
|
507 if (!nsContentUtils::GetNodeTextContent(changeData->mBoundElement, false, |
|
508 value)) { |
|
509 NS_RUNTIMEABORT("OOM"); |
|
510 } |
|
511 value.StripChar(char16_t('\n')); |
|
512 value.StripChar(char16_t('\r')); |
|
513 nsAutoString stripVal(value); |
|
514 stripVal.StripWhitespace(); |
|
515 |
|
516 if (stripVal.IsEmpty()) |
|
517 attrPresent = false; |
|
518 } |
|
519 else { |
|
520 attrPresent = changeData->mBoundElement->GetAttr(srcNs, src, value); |
|
521 } |
|
522 |
|
523 if (attrPresent) { |
|
524 nsIContent* content = |
|
525 changeData->mProto->GetImmediateChild(nsGkAtoms::content); |
|
526 |
|
527 nsXBLAttributeEntry* curr = aEntry; |
|
528 while (curr) { |
|
529 nsIAtom* dst = curr->GetDstAttribute(); |
|
530 int32_t dstNs = curr->GetDstNameSpace(); |
|
531 nsIContent* element = curr->GetElement(); |
|
532 |
|
533 nsIContent *realElement = |
|
534 changeData->mProto->LocateInstance(changeData->mBoundElement, content, |
|
535 changeData->mContent, element); |
|
536 |
|
537 if (realElement) { |
|
538 realElement->SetAttr(dstNs, dst, value, false); |
|
539 |
|
540 // XXXndeakin shouldn't this be done in lieu of SetAttr? |
|
541 if ((dst == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) || |
|
542 (realElement->NodeInfo()->Equals(nsGkAtoms::html, |
|
543 kNameSpaceID_XUL) && |
|
544 dst == nsGkAtoms::value && !value.IsEmpty())) { |
|
545 |
|
546 nsRefPtr<nsTextNode> textContent = |
|
547 new nsTextNode(realElement->NodeInfo()->NodeInfoManager()); |
|
548 |
|
549 textContent->SetText(value, false); |
|
550 realElement->AppendChildTo(textContent, false); |
|
551 } |
|
552 } |
|
553 |
|
554 curr = curr->GetNext(); |
|
555 } |
|
556 } |
|
557 |
|
558 return PL_DHASH_NEXT; |
|
559 } |
|
560 |
|
561 static PLDHashOperator |
|
562 SetAttrsNS(const uint32_t &aNamespace, |
|
563 nsXBLPrototypeBinding::InnerAttributeTable* aXBLAttributes, |
|
564 void* aClosure) |
|
565 { |
|
566 if (aXBLAttributes && aClosure) { |
|
567 nsXBLAttrChangeData* changeData = static_cast<nsXBLAttrChangeData*>(aClosure); |
|
568 changeData->mSrcNamespace = aNamespace; |
|
569 aXBLAttributes->EnumerateRead(SetAttrs, aClosure); |
|
570 } |
|
571 return PL_DHASH_NEXT; |
|
572 } |
|
573 |
|
574 void |
|
575 nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent) |
|
576 { |
|
577 if (mAttributeTable) { |
|
578 nsXBLAttrChangeData data(this, aBoundElement, aAnonymousContent); |
|
579 mAttributeTable->EnumerateRead(SetAttrsNS, &data); |
|
580 } |
|
581 } |
|
582 |
|
583 nsIStyleRuleProcessor* |
|
584 nsXBLPrototypeBinding::GetRuleProcessor() |
|
585 { |
|
586 if (mResources) { |
|
587 return mResources->mRuleProcessor; |
|
588 } |
|
589 |
|
590 return nullptr; |
|
591 } |
|
592 |
|
593 nsXBLPrototypeResources::sheet_array_type* |
|
594 nsXBLPrototypeBinding::GetOrCreateStyleSheets() |
|
595 { |
|
596 if (!mResources) { |
|
597 mResources = new nsXBLPrototypeResources(this); |
|
598 } |
|
599 |
|
600 return &mResources->mStyleSheetList; |
|
601 } |
|
602 |
|
603 nsXBLPrototypeResources::sheet_array_type* |
|
604 nsXBLPrototypeBinding::GetStyleSheets() |
|
605 { |
|
606 if (mResources) { |
|
607 return &mResources->mStyleSheetList; |
|
608 } |
|
609 |
|
610 return nullptr; |
|
611 } |
|
612 |
|
613 void |
|
614 nsXBLPrototypeBinding::EnsureAttributeTable() |
|
615 { |
|
616 if (!mAttributeTable) { |
|
617 mAttributeTable = new nsClassHashtable<nsUint32HashKey, InnerAttributeTable>(4); |
|
618 } |
|
619 } |
|
620 |
|
621 void |
|
622 nsXBLPrototypeBinding::AddToAttributeTable(int32_t aSourceNamespaceID, nsIAtom* aSourceTag, |
|
623 int32_t aDestNamespaceID, nsIAtom* aDestTag, |
|
624 nsIContent* aContent) |
|
625 { |
|
626 InnerAttributeTable* attributesNS = mAttributeTable->Get(aSourceNamespaceID); |
|
627 if (!attributesNS) { |
|
628 attributesNS = new InnerAttributeTable(4); |
|
629 mAttributeTable->Put(aSourceNamespaceID, attributesNS); |
|
630 } |
|
631 |
|
632 nsXBLAttributeEntry* xblAttr = |
|
633 new nsXBLAttributeEntry(aSourceTag, aDestTag, aDestNamespaceID, aContent); |
|
634 |
|
635 nsXBLAttributeEntry* entry = attributesNS->Get(aSourceTag); |
|
636 if (!entry) { |
|
637 attributesNS->Put(aSourceTag, xblAttr); |
|
638 } else { |
|
639 while (entry->GetNext()) |
|
640 entry = entry->GetNext(); |
|
641 entry->SetNext(xblAttr); |
|
642 } |
|
643 } |
|
644 |
|
645 void |
|
646 nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement) |
|
647 { |
|
648 // Don't add entries for <children> elements, since those will get |
|
649 // removed from the DOM when we construct the insertion point table. |
|
650 if (!aElement->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) { |
|
651 nsAutoString inherits; |
|
652 aElement->GetAttr(kNameSpaceID_XBL, nsGkAtoms::inherits, inherits); |
|
653 |
|
654 if (!inherits.IsEmpty()) { |
|
655 EnsureAttributeTable(); |
|
656 |
|
657 // The user specified at least one attribute. |
|
658 char* str = ToNewCString(inherits); |
|
659 char* newStr; |
|
660 // XXX We should use a strtok function that tokenizes PRUnichars |
|
661 // so that we don't have to convert from Unicode to ASCII and then back |
|
662 |
|
663 char* token = nsCRT::strtok( str, ", ", &newStr ); |
|
664 while( token != nullptr ) { |
|
665 // Build an atom out of this attribute. |
|
666 nsCOMPtr<nsIAtom> atom; |
|
667 int32_t atomNsID = kNameSpaceID_None; |
|
668 nsCOMPtr<nsIAtom> attribute; |
|
669 int32_t attributeNsID = kNameSpaceID_None; |
|
670 |
|
671 // Figure out if this token contains a :. |
|
672 nsAutoString attrTok; attrTok.AssignWithConversion(token); |
|
673 int32_t index = attrTok.Find("=", true); |
|
674 nsresult rv; |
|
675 if (index != -1) { |
|
676 // This attribute maps to something different. |
|
677 nsAutoString left, right; |
|
678 attrTok.Left(left, index); |
|
679 attrTok.Right(right, attrTok.Length()-index-1); |
|
680 |
|
681 rv = nsContentUtils::SplitQName(aElement, left, &attributeNsID, |
|
682 getter_AddRefs(attribute)); |
|
683 if (NS_FAILED(rv)) |
|
684 return; |
|
685 |
|
686 rv = nsContentUtils::SplitQName(aElement, right, &atomNsID, |
|
687 getter_AddRefs(atom)); |
|
688 if (NS_FAILED(rv)) |
|
689 return; |
|
690 } |
|
691 else { |
|
692 nsAutoString tok; |
|
693 tok.AssignWithConversion(token); |
|
694 rv = nsContentUtils::SplitQName(aElement, tok, &atomNsID, |
|
695 getter_AddRefs(atom)); |
|
696 if (NS_FAILED(rv)) |
|
697 return; |
|
698 attribute = atom; |
|
699 attributeNsID = atomNsID; |
|
700 } |
|
701 |
|
702 AddToAttributeTable(atomNsID, atom, attributeNsID, attribute, aElement); |
|
703 |
|
704 // Now remove the inherits attribute from the element so that it doesn't |
|
705 // show up on clones of the element. It is used |
|
706 // by the template only, and we don't need it anymore. |
|
707 // XXXdwh Don't do this for XUL elements, since it faults them into heavyweight |
|
708 // elements. Should nuke from the prototype instead. |
|
709 // aElement->UnsetAttr(kNameSpaceID_XBL, nsGkAtoms::inherits, false); |
|
710 |
|
711 token = nsCRT::strtok( newStr, ", ", &newStr ); |
|
712 } |
|
713 |
|
714 nsMemory::Free(str); |
|
715 } |
|
716 } |
|
717 |
|
718 // Recur into our children. |
|
719 for (nsIContent* child = aElement->GetFirstChild(); |
|
720 child; |
|
721 child = child->GetNextSibling()) { |
|
722 ConstructAttributeTable(child); |
|
723 } |
|
724 } |
|
725 |
|
726 nsresult |
|
727 nsXBLPrototypeBinding::ConstructInterfaceTable(const nsAString& aImpls) |
|
728 { |
|
729 if (!aImpls.IsEmpty()) { |
|
730 // Obtain the interface info manager that can tell us the IID |
|
731 // for a given interface name. |
|
732 nsCOMPtr<nsIInterfaceInfoManager> |
|
733 infoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); |
|
734 if (!infoManager) |
|
735 return NS_ERROR_FAILURE; |
|
736 |
|
737 // The user specified at least one attribute. |
|
738 NS_ConvertUTF16toUTF8 utf8impl(aImpls); |
|
739 char* str = utf8impl.BeginWriting(); |
|
740 char* newStr; |
|
741 // XXX We should use a strtok function that tokenizes PRUnichars |
|
742 // so that we don't have to convert from Unicode to ASCII and then back |
|
743 |
|
744 char* token = nsCRT::strtok( str, ", ", &newStr ); |
|
745 while( token != nullptr ) { |
|
746 // get the InterfaceInfo for the name |
|
747 nsCOMPtr<nsIInterfaceInfo> iinfo; |
|
748 infoManager->GetInfoForName(token, getter_AddRefs(iinfo)); |
|
749 |
|
750 if (iinfo) { |
|
751 // obtain an IID. |
|
752 const nsIID* iid = nullptr; |
|
753 iinfo->GetIIDShared(&iid); |
|
754 |
|
755 if (iid) { |
|
756 // We found a valid iid. Add it to our table. |
|
757 mInterfaceTable.Put(*iid, mBinding); |
|
758 |
|
759 // this block adds the parent interfaces of each interface |
|
760 // defined in the xbl definition (implements="nsI...") |
|
761 nsCOMPtr<nsIInterfaceInfo> parentInfo; |
|
762 // if it has a parent, add it to the table |
|
763 while (NS_SUCCEEDED(iinfo->GetParent(getter_AddRefs(parentInfo))) && parentInfo) { |
|
764 // get the iid |
|
765 parentInfo->GetIIDShared(&iid); |
|
766 |
|
767 // don't add nsISupports to the table |
|
768 if (!iid || iid->Equals(NS_GET_IID(nsISupports))) |
|
769 break; |
|
770 |
|
771 // add the iid to the table |
|
772 mInterfaceTable.Put(*iid, mBinding); |
|
773 |
|
774 // look for the next parent |
|
775 iinfo = parentInfo; |
|
776 } |
|
777 } |
|
778 } |
|
779 |
|
780 token = nsCRT::strtok( newStr, ", ", &newStr ); |
|
781 } |
|
782 } |
|
783 |
|
784 return NS_OK; |
|
785 } |
|
786 |
|
787 nsresult |
|
788 nsXBLPrototypeBinding::AddResourceListener(nsIContent* aBoundElement) |
|
789 { |
|
790 if (!mResources) |
|
791 return NS_ERROR_FAILURE; // Makes no sense to add a listener when the binding |
|
792 // has no resources. |
|
793 |
|
794 mResources->AddResourceListener(aBoundElement); |
|
795 return NS_OK; |
|
796 } |
|
797 |
|
798 void |
|
799 nsXBLPrototypeBinding::CreateKeyHandlers() |
|
800 { |
|
801 nsXBLPrototypeHandler* curr = mPrototypeHandler; |
|
802 while (curr) { |
|
803 nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName(); |
|
804 if (eventAtom == nsGkAtoms::keyup || |
|
805 eventAtom == nsGkAtoms::keydown || |
|
806 eventAtom == nsGkAtoms::keypress) { |
|
807 uint8_t phase = curr->GetPhase(); |
|
808 uint8_t type = curr->GetType(); |
|
809 |
|
810 int32_t count = mKeyHandlers.Count(); |
|
811 int32_t i; |
|
812 nsXBLKeyEventHandler* handler = nullptr; |
|
813 for (i = 0; i < count; ++i) { |
|
814 handler = mKeyHandlers[i]; |
|
815 if (handler->Matches(eventAtom, phase, type)) |
|
816 break; |
|
817 } |
|
818 |
|
819 if (i == count) { |
|
820 nsRefPtr<nsXBLKeyEventHandler> newHandler; |
|
821 NS_NewXBLKeyEventHandler(eventAtom, phase, type, |
|
822 getter_AddRefs(newHandler)); |
|
823 if (newHandler) |
|
824 mKeyHandlers.AppendObject(newHandler); |
|
825 handler = newHandler; |
|
826 } |
|
827 |
|
828 if (handler) |
|
829 handler->AddProtoHandler(curr); |
|
830 } |
|
831 |
|
832 curr = curr->GetNextHandler(); |
|
833 } |
|
834 } |
|
835 |
|
836 class XBLPrototypeSetupCleanup |
|
837 { |
|
838 public: |
|
839 XBLPrototypeSetupCleanup(nsXBLDocumentInfo* aDocInfo, const nsACString& aID) |
|
840 : mDocInfo(aDocInfo), mID(aID) {} |
|
841 |
|
842 ~XBLPrototypeSetupCleanup() |
|
843 { |
|
844 if (mDocInfo) { |
|
845 mDocInfo->RemovePrototypeBinding(mID); |
|
846 } |
|
847 } |
|
848 |
|
849 void Disconnect() |
|
850 { |
|
851 mDocInfo = nullptr; |
|
852 } |
|
853 |
|
854 nsXBLDocumentInfo* mDocInfo; |
|
855 nsAutoCString mID; |
|
856 }; |
|
857 |
|
858 nsresult |
|
859 nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream, |
|
860 nsXBLDocumentInfo* aDocInfo, |
|
861 nsIDocument* aDocument, |
|
862 uint8_t aFlags) |
|
863 { |
|
864 mInheritStyle = (aFlags & XBLBinding_Serialize_InheritStyle) ? true : false; |
|
865 mChromeOnlyContent = |
|
866 (aFlags & XBLBinding_Serialize_ChromeOnlyContent) ? true : false; |
|
867 |
|
868 // nsXBLContentSink::ConstructBinding doesn't create a binding with an empty |
|
869 // id, so we don't here either. |
|
870 nsAutoCString id; |
|
871 nsresult rv = aStream->ReadCString(id); |
|
872 |
|
873 NS_ENSURE_SUCCESS(rv, rv); |
|
874 NS_ENSURE_TRUE(!id.IsEmpty(), NS_ERROR_FAILURE); |
|
875 |
|
876 nsAutoCString baseBindingURI; |
|
877 rv = aStream->ReadCString(baseBindingURI); |
|
878 NS_ENSURE_SUCCESS(rv, rv); |
|
879 mCheckedBaseProto = true; |
|
880 |
|
881 if (!baseBindingURI.IsEmpty()) { |
|
882 rv = NS_NewURI(getter_AddRefs(mBaseBindingURI), baseBindingURI); |
|
883 NS_ENSURE_SUCCESS(rv, rv); |
|
884 } |
|
885 |
|
886 rv = ReadNamespace(aStream, mBaseNameSpaceID); |
|
887 NS_ENSURE_SUCCESS(rv, rv); |
|
888 |
|
889 nsAutoString baseTag; |
|
890 rv = aStream->ReadString(baseTag); |
|
891 NS_ENSURE_SUCCESS(rv, rv); |
|
892 if (!baseTag.IsEmpty()) { |
|
893 mBaseTag = do_GetAtom(baseTag); |
|
894 } |
|
895 |
|
896 aDocument->CreateElem(NS_LITERAL_STRING("binding"), nullptr, kNameSpaceID_XBL, |
|
897 getter_AddRefs(mBinding)); |
|
898 |
|
899 nsCOMPtr<nsIContent> child; |
|
900 rv = ReadContentNode(aStream, aDocument, aDocument->NodeInfoManager(), getter_AddRefs(child)); |
|
901 NS_ENSURE_SUCCESS(rv, rv); |
|
902 |
|
903 Element* rootElement = aDocument->GetRootElement(); |
|
904 if (rootElement) |
|
905 rootElement->AppendChildTo(mBinding, false); |
|
906 |
|
907 if (child) { |
|
908 mBinding->AppendChildTo(child, false); |
|
909 } |
|
910 |
|
911 uint32_t interfaceCount; |
|
912 rv = aStream->Read32(&interfaceCount); |
|
913 NS_ENSURE_SUCCESS(rv, rv); |
|
914 |
|
915 for (; interfaceCount > 0; interfaceCount--) { |
|
916 nsIID iid; |
|
917 aStream->ReadID(&iid); |
|
918 mInterfaceTable.Put(iid, mBinding); |
|
919 } |
|
920 |
|
921 AutoSafeJSContext cx; |
|
922 JS::Rooted<JSObject*> compilationGlobal(cx, xpc::GetCompilationScope()); |
|
923 NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED); |
|
924 JSAutoCompartment ac(cx, compilationGlobal); |
|
925 |
|
926 bool isFirstBinding = aFlags & XBLBinding_Serialize_IsFirstBinding; |
|
927 rv = Init(id, aDocInfo, nullptr, isFirstBinding); |
|
928 NS_ENSURE_SUCCESS(rv, rv); |
|
929 |
|
930 // We need to set the prototype binding before reading the nsXBLProtoImpl, |
|
931 // as it may be retrieved within. |
|
932 rv = aDocInfo->SetPrototypeBinding(id, this); |
|
933 NS_ENSURE_SUCCESS(rv, rv); |
|
934 |
|
935 XBLPrototypeSetupCleanup cleanup(aDocInfo, id); |
|
936 |
|
937 nsAutoCString className; |
|
938 rv = aStream->ReadCString(className); |
|
939 NS_ENSURE_SUCCESS(rv, rv); |
|
940 |
|
941 if (!className.IsEmpty()) { |
|
942 nsXBLProtoImpl* impl; // NS_NewXBLProtoImpl will set mImplementation for us |
|
943 NS_NewXBLProtoImpl(this, NS_ConvertUTF8toUTF16(className).get(), &impl); |
|
944 |
|
945 // This needs to happen after SetPrototypeBinding as calls are made to |
|
946 // retrieve the mapped bindings from within here. However, if an error |
|
947 // occurs, the mapping should be removed again so that we don't keep an |
|
948 // invalid binding around. |
|
949 rv = mImplementation->Read(aStream, this); |
|
950 NS_ENSURE_SUCCESS(rv, rv); |
|
951 } |
|
952 |
|
953 // Next read in the handlers. |
|
954 nsXBLPrototypeHandler* previousHandler = nullptr; |
|
955 |
|
956 do { |
|
957 XBLBindingSerializeDetails type; |
|
958 rv = aStream->Read8(&type); |
|
959 NS_ENSURE_SUCCESS(rv, rv); |
|
960 |
|
961 if (type == XBLBinding_Serialize_NoMoreItems) |
|
962 break; |
|
963 |
|
964 NS_ASSERTION((type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Handler, |
|
965 "invalid handler type"); |
|
966 |
|
967 nsXBLPrototypeHandler* handler = new nsXBLPrototypeHandler(this); |
|
968 rv = handler->Read(aStream); |
|
969 if (NS_FAILED(rv)) { |
|
970 delete handler; |
|
971 return rv; |
|
972 } |
|
973 |
|
974 if (previousHandler) { |
|
975 previousHandler->SetNextHandler(handler); |
|
976 } |
|
977 else { |
|
978 SetPrototypeHandlers(handler); |
|
979 } |
|
980 previousHandler = handler; |
|
981 } while (1); |
|
982 |
|
983 if (mBinding) { |
|
984 while (true) { |
|
985 XBLBindingSerializeDetails type; |
|
986 rv = aStream->Read8(&type); |
|
987 NS_ENSURE_SUCCESS(rv, rv); |
|
988 |
|
989 if (type != XBLBinding_Serialize_Attribute) { |
|
990 break; |
|
991 } |
|
992 |
|
993 int32_t attrNamespace; |
|
994 rv = ReadNamespace(aStream, attrNamespace); |
|
995 NS_ENSURE_SUCCESS(rv, rv); |
|
996 |
|
997 nsAutoString attrPrefix, attrName, attrValue; |
|
998 rv = aStream->ReadString(attrPrefix); |
|
999 NS_ENSURE_SUCCESS(rv, rv); |
|
1000 |
|
1001 rv = aStream->ReadString(attrName); |
|
1002 NS_ENSURE_SUCCESS(rv, rv); |
|
1003 |
|
1004 rv = aStream->ReadString(attrValue); |
|
1005 NS_ENSURE_SUCCESS(rv, rv); |
|
1006 |
|
1007 nsCOMPtr<nsIAtom> atomPrefix = do_GetAtom(attrPrefix); |
|
1008 nsCOMPtr<nsIAtom> atomName = do_GetAtom(attrName); |
|
1009 mBinding->SetAttr(attrNamespace, atomName, atomPrefix, attrValue, false); |
|
1010 } |
|
1011 } |
|
1012 |
|
1013 // Finally, read in the resources. |
|
1014 while (true) { |
|
1015 XBLBindingSerializeDetails type; |
|
1016 rv = aStream->Read8(&type); |
|
1017 NS_ENSURE_SUCCESS(rv, rv); |
|
1018 |
|
1019 if (type == XBLBinding_Serialize_NoMoreItems) |
|
1020 break; |
|
1021 |
|
1022 NS_ASSERTION((type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Stylesheet || |
|
1023 (type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Image, "invalid resource type"); |
|
1024 |
|
1025 nsAutoString src; |
|
1026 rv = aStream->ReadString(src); |
|
1027 NS_ENSURE_SUCCESS(rv, rv); |
|
1028 |
|
1029 AddResource(type == XBLBinding_Serialize_Stylesheet ? nsGkAtoms::stylesheet : |
|
1030 nsGkAtoms::image, src); |
|
1031 } |
|
1032 |
|
1033 if (isFirstBinding) { |
|
1034 aDocInfo->SetFirstPrototypeBinding(this); |
|
1035 } |
|
1036 |
|
1037 cleanup.Disconnect(); |
|
1038 return NS_OK; |
|
1039 } |
|
1040 |
|
1041 // static |
|
1042 nsresult |
|
1043 nsXBLPrototypeBinding::ReadNewBinding(nsIObjectInputStream* aStream, |
|
1044 nsXBLDocumentInfo* aDocInfo, |
|
1045 nsIDocument* aDocument, |
|
1046 uint8_t aFlags) |
|
1047 { |
|
1048 // If the Read() succeeds, |binding| will end up being owned by aDocInfo's |
|
1049 // binding table. Otherwise, we must manually delete it. |
|
1050 nsXBLPrototypeBinding* binding = new nsXBLPrototypeBinding(); |
|
1051 nsresult rv = binding->Read(aStream, aDocInfo, aDocument, aFlags); |
|
1052 if (NS_FAILED(rv)) { |
|
1053 delete binding; |
|
1054 } |
|
1055 return rv; |
|
1056 } |
|
1057 |
|
1058 static PLDHashOperator |
|
1059 WriteInterfaceID(const nsIID& aKey, nsIContent* aData, void* aClosure) |
|
1060 { |
|
1061 // We can just write out the ids. The cache will be invalidated when a |
|
1062 // different build is used, so we don't need to worry about ids changing. |
|
1063 static_cast<nsIObjectOutputStream *>(aClosure)->WriteID(aKey); |
|
1064 return PL_DHASH_NEXT; |
|
1065 } |
|
1066 |
|
1067 nsresult |
|
1068 nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream) |
|
1069 { |
|
1070 // This writes out the binding. Note that mCheckedBaseProto, |
|
1071 // mKeyHandlersRegistered and mKeyHandlers are not serialized as they are |
|
1072 // computed on demand. |
|
1073 |
|
1074 AutoSafeJSContext cx; |
|
1075 JS::Rooted<JSObject*> compilationGlobal(cx, xpc::GetCompilationScope()); |
|
1076 NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED); |
|
1077 JSAutoCompartment ac(cx, compilationGlobal); |
|
1078 |
|
1079 uint8_t flags = mInheritStyle ? XBLBinding_Serialize_InheritStyle : 0; |
|
1080 |
|
1081 // mAlternateBindingURI is only set on the first binding. |
|
1082 if (mAlternateBindingURI) { |
|
1083 flags |= XBLBinding_Serialize_IsFirstBinding; |
|
1084 } |
|
1085 |
|
1086 if (mChromeOnlyContent) { |
|
1087 flags |= XBLBinding_Serialize_ChromeOnlyContent; |
|
1088 } |
|
1089 |
|
1090 nsresult rv = aStream->Write8(flags); |
|
1091 NS_ENSURE_SUCCESS(rv, rv); |
|
1092 |
|
1093 nsAutoCString id; |
|
1094 mBindingURI->GetRef(id); |
|
1095 rv = aStream->WriteStringZ(id.get()); |
|
1096 NS_ENSURE_SUCCESS(rv, rv); |
|
1097 |
|
1098 // write out the extends and display attribute values |
|
1099 nsAutoCString extends; |
|
1100 ResolveBaseBinding(); |
|
1101 if (mBaseBindingURI) |
|
1102 mBaseBindingURI->GetSpec(extends); |
|
1103 |
|
1104 rv = aStream->WriteStringZ(extends.get()); |
|
1105 NS_ENSURE_SUCCESS(rv, rv); |
|
1106 |
|
1107 rv = WriteNamespace(aStream, mBaseNameSpaceID); |
|
1108 NS_ENSURE_SUCCESS(rv, rv); |
|
1109 |
|
1110 nsAutoString baseTag; |
|
1111 if (mBaseTag) { |
|
1112 mBaseTag->ToString(baseTag); |
|
1113 } |
|
1114 rv = aStream->WriteWStringZ(baseTag.get()); |
|
1115 NS_ENSURE_SUCCESS(rv, rv); |
|
1116 |
|
1117 nsIContent* content = GetImmediateChild(nsGkAtoms::content); |
|
1118 if (content) { |
|
1119 rv = WriteContentNode(aStream, content); |
|
1120 NS_ENSURE_SUCCESS(rv, rv); |
|
1121 } |
|
1122 else { |
|
1123 // Write a marker to indicate that there is no content. |
|
1124 rv = aStream->Write8(XBLBinding_Serialize_NoContent); |
|
1125 NS_ENSURE_SUCCESS(rv, rv); |
|
1126 } |
|
1127 |
|
1128 // Enumerate and write out the implemented interfaces. |
|
1129 rv = aStream->Write32(mInterfaceTable.Count()); |
|
1130 NS_ENSURE_SUCCESS(rv, rv); |
|
1131 |
|
1132 mInterfaceTable.EnumerateRead(WriteInterfaceID, aStream); |
|
1133 |
|
1134 // Write out the implementation details. |
|
1135 if (mImplementation) { |
|
1136 rv = mImplementation->Write(aStream, this); |
|
1137 NS_ENSURE_SUCCESS(rv, rv); |
|
1138 } |
|
1139 else { |
|
1140 // Write out an empty classname. This indicates that the binding does not |
|
1141 // define an implementation. |
|
1142 rv = aStream->WriteWStringZ(EmptyString().get()); |
|
1143 NS_ENSURE_SUCCESS(rv, rv); |
|
1144 } |
|
1145 |
|
1146 // Write out the handlers. |
|
1147 nsXBLPrototypeHandler* handler = mPrototypeHandler; |
|
1148 while (handler) { |
|
1149 rv = handler->Write(aStream); |
|
1150 NS_ENSURE_SUCCESS(rv, rv); |
|
1151 |
|
1152 handler = handler->GetNextHandler(); |
|
1153 } |
|
1154 |
|
1155 aStream->Write8(XBLBinding_Serialize_NoMoreItems); |
|
1156 NS_ENSURE_SUCCESS(rv, rv); |
|
1157 |
|
1158 if (mBinding) { |
|
1159 uint32_t attributes = mBinding->GetAttrCount(); |
|
1160 nsAutoString attrValue; |
|
1161 for (uint32_t i = 0; i < attributes; ++i) { |
|
1162 const nsAttrName* attr = mBinding->GetAttrNameAt(i); |
|
1163 nsDependentAtomString attrName = attr->LocalName(); |
|
1164 mBinding->GetAttr(attr->NamespaceID(), attr->LocalName(), attrValue); |
|
1165 rv = aStream->Write8(XBLBinding_Serialize_Attribute); |
|
1166 NS_ENSURE_SUCCESS(rv, rv); |
|
1167 |
|
1168 rv = WriteNamespace(aStream, attr->NamespaceID()); |
|
1169 NS_ENSURE_SUCCESS(rv, rv); |
|
1170 |
|
1171 nsIAtom* prefix = attr->GetPrefix(); |
|
1172 nsAutoString prefixString; |
|
1173 if (prefix) { |
|
1174 prefix->ToString(prefixString); |
|
1175 } |
|
1176 |
|
1177 rv = aStream->WriteWStringZ(prefixString.get()); |
|
1178 NS_ENSURE_SUCCESS(rv, rv); |
|
1179 |
|
1180 rv = aStream->WriteWStringZ(attrName.get()); |
|
1181 NS_ENSURE_SUCCESS(rv, rv); |
|
1182 |
|
1183 rv = aStream->WriteWStringZ(attrValue.get()); |
|
1184 NS_ENSURE_SUCCESS(rv, rv); |
|
1185 } |
|
1186 } |
|
1187 |
|
1188 aStream->Write8(XBLBinding_Serialize_NoMoreItems); |
|
1189 NS_ENSURE_SUCCESS(rv, rv); |
|
1190 |
|
1191 // Write out the resources |
|
1192 if (mResources) { |
|
1193 rv = mResources->Write(aStream); |
|
1194 NS_ENSURE_SUCCESS(rv, rv); |
|
1195 } |
|
1196 |
|
1197 // Write out an end mark at the end. |
|
1198 return aStream->Write8(XBLBinding_Serialize_NoMoreItems); |
|
1199 } |
|
1200 |
|
1201 nsresult |
|
1202 nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream, |
|
1203 nsIDocument* aDocument, |
|
1204 nsNodeInfoManager* aNim, |
|
1205 nsIContent** aContent) |
|
1206 { |
|
1207 *aContent = nullptr; |
|
1208 |
|
1209 int32_t namespaceID; |
|
1210 nsresult rv = ReadNamespace(aStream, namespaceID); |
|
1211 NS_ENSURE_SUCCESS(rv, rv); |
|
1212 |
|
1213 // There is no content to read so just return. |
|
1214 if (namespaceID == XBLBinding_Serialize_NoContent) |
|
1215 return NS_OK; |
|
1216 |
|
1217 nsCOMPtr<nsIContent> content; |
|
1218 |
|
1219 // If this is a text type, just read the string and return. |
|
1220 if (namespaceID == XBLBinding_Serialize_TextNode || |
|
1221 namespaceID == XBLBinding_Serialize_CDATANode || |
|
1222 namespaceID == XBLBinding_Serialize_CommentNode) { |
|
1223 switch (namespaceID) { |
|
1224 case XBLBinding_Serialize_TextNode: |
|
1225 content = new nsTextNode(aNim); |
|
1226 break; |
|
1227 case XBLBinding_Serialize_CDATANode: |
|
1228 content = new CDATASection(aNim); |
|
1229 break; |
|
1230 case XBLBinding_Serialize_CommentNode: |
|
1231 content = new Comment(aNim); |
|
1232 break; |
|
1233 default: |
|
1234 break; |
|
1235 } |
|
1236 |
|
1237 nsAutoString text; |
|
1238 rv = aStream->ReadString(text); |
|
1239 NS_ENSURE_SUCCESS(rv, rv); |
|
1240 |
|
1241 content->SetText(text, false); |
|
1242 content.swap(*aContent); |
|
1243 return NS_OK; |
|
1244 } |
|
1245 |
|
1246 // Otherwise, it's an element, so read its tag, attributes and children. |
|
1247 nsAutoString prefix, tag; |
|
1248 rv = aStream->ReadString(prefix); |
|
1249 NS_ENSURE_SUCCESS(rv, rv); |
|
1250 |
|
1251 nsCOMPtr<nsIAtom> prefixAtom; |
|
1252 if (!prefix.IsEmpty()) |
|
1253 prefixAtom = do_GetAtom(prefix); |
|
1254 |
|
1255 rv = aStream->ReadString(tag); |
|
1256 NS_ENSURE_SUCCESS(rv, rv); |
|
1257 |
|
1258 nsCOMPtr<nsIAtom> tagAtom = do_GetAtom(tag); |
|
1259 nsCOMPtr<nsINodeInfo> nodeInfo = |
|
1260 aNim->GetNodeInfo(tagAtom, prefixAtom, namespaceID, nsIDOMNode::ELEMENT_NODE); |
|
1261 |
|
1262 uint32_t attrCount; |
|
1263 rv = aStream->Read32(&attrCount); |
|
1264 NS_ENSURE_SUCCESS(rv, rv); |
|
1265 |
|
1266 // Create XUL prototype elements, or regular elements for other namespaces. |
|
1267 // This needs to match the code in nsXBLContentSink::CreateElement. |
|
1268 #ifdef MOZ_XUL |
|
1269 if (namespaceID == kNameSpaceID_XUL) { |
|
1270 nsIURI* documentURI = aDocument->GetDocumentURI(); |
|
1271 |
|
1272 nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement(); |
|
1273 NS_ENSURE_TRUE(prototype, NS_ERROR_OUT_OF_MEMORY); |
|
1274 |
|
1275 prototype->mNodeInfo = nodeInfo; |
|
1276 |
|
1277 nsXULPrototypeAttribute* attrs = nullptr; |
|
1278 if (attrCount > 0) { |
|
1279 attrs = new nsXULPrototypeAttribute[attrCount]; |
|
1280 } |
|
1281 |
|
1282 prototype->mAttributes = attrs; |
|
1283 prototype->mNumAttributes = attrCount; |
|
1284 |
|
1285 for (uint32_t i = 0; i < attrCount; i++) { |
|
1286 rv = ReadNamespace(aStream, namespaceID); |
|
1287 NS_ENSURE_SUCCESS(rv, rv); |
|
1288 |
|
1289 nsAutoString prefix, name, val; |
|
1290 rv = aStream->ReadString(prefix); |
|
1291 NS_ENSURE_SUCCESS(rv, rv); |
|
1292 rv = aStream->ReadString(name); |
|
1293 NS_ENSURE_SUCCESS(rv, rv); |
|
1294 rv = aStream->ReadString(val); |
|
1295 NS_ENSURE_SUCCESS(rv, rv); |
|
1296 |
|
1297 nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(name); |
|
1298 if (namespaceID == kNameSpaceID_None) { |
|
1299 attrs[i].mName.SetTo(nameAtom); |
|
1300 } |
|
1301 else { |
|
1302 nsCOMPtr<nsIAtom> prefixAtom; |
|
1303 if (!prefix.IsEmpty()) |
|
1304 prefixAtom = do_GetAtom(prefix); |
|
1305 |
|
1306 nsCOMPtr<nsINodeInfo> ni = |
|
1307 aNim->GetNodeInfo(nameAtom, prefixAtom, |
|
1308 namespaceID, nsIDOMNode::ATTRIBUTE_NODE); |
|
1309 attrs[i].mName.SetTo(ni); |
|
1310 } |
|
1311 |
|
1312 rv = prototype->SetAttrAt(i, val, documentURI); |
|
1313 NS_ENSURE_SUCCESS(rv, rv); |
|
1314 } |
|
1315 |
|
1316 nsCOMPtr<Element> result; |
|
1317 nsresult rv = |
|
1318 nsXULElement::Create(prototype, aDocument, false, false, getter_AddRefs(result)); |
|
1319 NS_ENSURE_SUCCESS(rv, rv); |
|
1320 content = result; |
|
1321 } |
|
1322 else { |
|
1323 #endif |
|
1324 nsCOMPtr<Element> element; |
|
1325 NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), NOT_FROM_PARSER); |
|
1326 content = element; |
|
1327 |
|
1328 for (uint32_t i = 0; i < attrCount; i++) { |
|
1329 rv = ReadNamespace(aStream, namespaceID); |
|
1330 NS_ENSURE_SUCCESS(rv, rv); |
|
1331 |
|
1332 nsAutoString prefix, name, val; |
|
1333 rv = aStream->ReadString(prefix); |
|
1334 NS_ENSURE_SUCCESS(rv, rv); |
|
1335 rv = aStream->ReadString(name); |
|
1336 NS_ENSURE_SUCCESS(rv, rv); |
|
1337 rv = aStream->ReadString(val); |
|
1338 NS_ENSURE_SUCCESS(rv, rv); |
|
1339 |
|
1340 nsCOMPtr<nsIAtom> prefixAtom; |
|
1341 if (!prefix.IsEmpty()) |
|
1342 prefixAtom = do_GetAtom(prefix); |
|
1343 |
|
1344 nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(name); |
|
1345 content->SetAttr(namespaceID, nameAtom, prefixAtom, val, false); |
|
1346 } |
|
1347 |
|
1348 #ifdef MOZ_XUL |
|
1349 } |
|
1350 #endif |
|
1351 |
|
1352 // Now read the attribute forwarding entries (xbl:inherits) |
|
1353 |
|
1354 int32_t srcNamespaceID, destNamespaceID; |
|
1355 rv = ReadNamespace(aStream, srcNamespaceID); |
|
1356 NS_ENSURE_SUCCESS(rv, rv); |
|
1357 |
|
1358 while (srcNamespaceID != XBLBinding_Serialize_NoMoreAttributes) { |
|
1359 nsAutoString srcAttribute, destAttribute; |
|
1360 rv = aStream->ReadString(srcAttribute); |
|
1361 NS_ENSURE_SUCCESS(rv, rv); |
|
1362 rv = ReadNamespace(aStream, destNamespaceID); |
|
1363 NS_ENSURE_SUCCESS(rv, rv); |
|
1364 rv = aStream->ReadString(destAttribute); |
|
1365 NS_ENSURE_SUCCESS(rv, rv); |
|
1366 |
|
1367 nsCOMPtr<nsIAtom> srcAtom = do_GetAtom(srcAttribute); |
|
1368 nsCOMPtr<nsIAtom> destAtom = do_GetAtom(destAttribute); |
|
1369 |
|
1370 EnsureAttributeTable(); |
|
1371 AddToAttributeTable(srcNamespaceID, srcAtom, destNamespaceID, destAtom, content); |
|
1372 |
|
1373 rv = ReadNamespace(aStream, srcNamespaceID); |
|
1374 NS_ENSURE_SUCCESS(rv, rv); |
|
1375 } |
|
1376 |
|
1377 // Finally, read in the child nodes. |
|
1378 uint32_t childCount; |
|
1379 rv = aStream->Read32(&childCount); |
|
1380 NS_ENSURE_SUCCESS(rv, rv); |
|
1381 |
|
1382 for (uint32_t i = 0; i < childCount; i++) { |
|
1383 nsCOMPtr<nsIContent> child; |
|
1384 ReadContentNode(aStream, aDocument, aNim, getter_AddRefs(child)); |
|
1385 |
|
1386 // Child may be null if this was a comment for example and can just be ignored. |
|
1387 if (child) { |
|
1388 content->AppendChildTo(child, false); |
|
1389 } |
|
1390 } |
|
1391 |
|
1392 content.swap(*aContent); |
|
1393 return NS_OK; |
|
1394 } |
|
1395 |
|
1396 // This structure holds information about a forwarded attribute that needs to be |
|
1397 // written out. This is used because we need several fields passed within the |
|
1398 // enumeration closure. |
|
1399 struct WriteAttributeData |
|
1400 { |
|
1401 nsXBLPrototypeBinding* binding; |
|
1402 nsIObjectOutputStream* stream; |
|
1403 nsIContent* content; |
|
1404 int32_t srcNamespace; |
|
1405 |
|
1406 WriteAttributeData(nsXBLPrototypeBinding* aBinding, |
|
1407 nsIObjectOutputStream* aStream, |
|
1408 nsIContent* aContent) |
|
1409 : binding(aBinding), stream(aStream), content(aContent) |
|
1410 { } |
|
1411 }; |
|
1412 |
|
1413 static PLDHashOperator |
|
1414 WriteAttribute(nsISupports* aKey, nsXBLAttributeEntry* aEntry, void* aClosure) |
|
1415 { |
|
1416 WriteAttributeData* data = static_cast<WriteAttributeData *>(aClosure); |
|
1417 nsIObjectOutputStream* stream = data->stream; |
|
1418 const int32_t srcNamespace = data->srcNamespace; |
|
1419 |
|
1420 do { |
|
1421 if (aEntry->GetElement() == data->content) { |
|
1422 data->binding->WriteNamespace(stream, srcNamespace); |
|
1423 stream->WriteWStringZ(nsDependentAtomString(aEntry->GetSrcAttribute()).get()); |
|
1424 data->binding->WriteNamespace(stream, aEntry->GetDstNameSpace()); |
|
1425 stream->WriteWStringZ(nsDependentAtomString(aEntry->GetDstAttribute()).get()); |
|
1426 } |
|
1427 |
|
1428 aEntry = aEntry->GetNext(); |
|
1429 } while (aEntry); |
|
1430 |
|
1431 return PL_DHASH_NEXT; |
|
1432 } |
|
1433 |
|
1434 // WriteAttributeNS is the callback to enumerate over the attribute |
|
1435 // forwarding entries. Since these are stored in a hash of hashes, |
|
1436 // we need to iterate over the inner hashes, calling WriteAttribute |
|
1437 // to do the actual work. |
|
1438 static PLDHashOperator |
|
1439 WriteAttributeNS(const uint32_t &aNamespace, |
|
1440 nsXBLPrototypeBinding::InnerAttributeTable* aXBLAttributes, |
|
1441 void* aClosure) |
|
1442 { |
|
1443 WriteAttributeData* data = static_cast<WriteAttributeData *>(aClosure); |
|
1444 data->srcNamespace = aNamespace; |
|
1445 aXBLAttributes->EnumerateRead(WriteAttribute, data); |
|
1446 |
|
1447 return PL_DHASH_NEXT; |
|
1448 } |
|
1449 |
|
1450 nsresult |
|
1451 nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream, |
|
1452 nsIContent* aNode) |
|
1453 { |
|
1454 nsresult rv; |
|
1455 |
|
1456 if (!aNode->IsElement()) { |
|
1457 // Text is writen out as a single byte for the type, followed by the text. |
|
1458 uint8_t type = XBLBinding_Serialize_NoContent; |
|
1459 switch (aNode->NodeType()) { |
|
1460 case nsIDOMNode::TEXT_NODE: |
|
1461 type = XBLBinding_Serialize_TextNode; |
|
1462 break; |
|
1463 case nsIDOMNode::CDATA_SECTION_NODE: |
|
1464 type = XBLBinding_Serialize_CDATANode; |
|
1465 break; |
|
1466 case nsIDOMNode::COMMENT_NODE: |
|
1467 type = XBLBinding_Serialize_CommentNode; |
|
1468 break; |
|
1469 default: |
|
1470 break; |
|
1471 } |
|
1472 |
|
1473 rv = aStream->Write8(type); |
|
1474 NS_ENSURE_SUCCESS(rv, rv); |
|
1475 |
|
1476 nsAutoString content; |
|
1477 aNode->GetText()->AppendTo(content); |
|
1478 return aStream->WriteWStringZ(content.get()); |
|
1479 } |
|
1480 |
|
1481 // Otherwise, this is an element. |
|
1482 |
|
1483 // Write the namespace id followed by the tag name |
|
1484 rv = WriteNamespace(aStream, aNode->GetNameSpaceID()); |
|
1485 NS_ENSURE_SUCCESS(rv, rv); |
|
1486 |
|
1487 nsAutoString prefixStr; |
|
1488 aNode->NodeInfo()->GetPrefix(prefixStr); |
|
1489 rv = aStream->WriteWStringZ(prefixStr.get()); |
|
1490 NS_ENSURE_SUCCESS(rv, rv); |
|
1491 |
|
1492 rv = aStream->WriteWStringZ(nsDependentAtomString(aNode->Tag()).get()); |
|
1493 NS_ENSURE_SUCCESS(rv, rv); |
|
1494 |
|
1495 // Write attributes |
|
1496 uint32_t count = aNode->GetAttrCount(); |
|
1497 rv = aStream->Write32(count); |
|
1498 NS_ENSURE_SUCCESS(rv, rv); |
|
1499 |
|
1500 uint32_t i; |
|
1501 for (i = 0; i < count; i++) { |
|
1502 // Write out the namespace id, the namespace prefix, the local tag name, |
|
1503 // and the value, in that order. |
|
1504 |
|
1505 const nsAttrName* attr = aNode->GetAttrNameAt(i); |
|
1506 |
|
1507 // XXXndeakin don't write out xbl:inherits? |
|
1508 int32_t namespaceID = attr->NamespaceID(); |
|
1509 rv = WriteNamespace(aStream, namespaceID); |
|
1510 NS_ENSURE_SUCCESS(rv, rv); |
|
1511 |
|
1512 nsAutoString prefixStr; |
|
1513 nsIAtom* prefix = attr->GetPrefix(); |
|
1514 if (prefix) |
|
1515 prefix->ToString(prefixStr); |
|
1516 rv = aStream->WriteWStringZ(prefixStr.get()); |
|
1517 NS_ENSURE_SUCCESS(rv, rv); |
|
1518 |
|
1519 rv = aStream->WriteWStringZ(nsDependentAtomString(attr->LocalName()).get()); |
|
1520 NS_ENSURE_SUCCESS(rv, rv); |
|
1521 |
|
1522 nsAutoString val; |
|
1523 aNode->GetAttr(attr->NamespaceID(), attr->LocalName(), val); |
|
1524 rv = aStream->WriteWStringZ(val.get()); |
|
1525 NS_ENSURE_SUCCESS(rv, rv); |
|
1526 } |
|
1527 |
|
1528 // Write out the attribute fowarding information |
|
1529 if (mAttributeTable) { |
|
1530 WriteAttributeData data(this, aStream, aNode); |
|
1531 mAttributeTable->EnumerateRead(WriteAttributeNS, &data); |
|
1532 } |
|
1533 rv = aStream->Write8(XBLBinding_Serialize_NoMoreAttributes); |
|
1534 NS_ENSURE_SUCCESS(rv, rv); |
|
1535 |
|
1536 // Finally, write out the child nodes. |
|
1537 count = aNode->GetChildCount(); |
|
1538 rv = aStream->Write32(count); |
|
1539 NS_ENSURE_SUCCESS(rv, rv); |
|
1540 |
|
1541 for (i = 0; i < count; i++) { |
|
1542 rv = WriteContentNode(aStream, aNode->GetChildAt(i)); |
|
1543 NS_ENSURE_SUCCESS(rv, rv); |
|
1544 } |
|
1545 |
|
1546 return NS_OK; |
|
1547 } |
|
1548 |
|
1549 nsresult |
|
1550 nsXBLPrototypeBinding::ReadNamespace(nsIObjectInputStream* aStream, |
|
1551 int32_t& aNameSpaceID) |
|
1552 { |
|
1553 uint8_t namespaceID; |
|
1554 nsresult rv = aStream->Read8(&namespaceID); |
|
1555 NS_ENSURE_SUCCESS(rv, rv); |
|
1556 |
|
1557 if (namespaceID == XBLBinding_Serialize_CustomNamespace) { |
|
1558 nsAutoString namesp; |
|
1559 rv = aStream->ReadString(namesp); |
|
1560 NS_ENSURE_SUCCESS(rv, rv); |
|
1561 |
|
1562 nsContentUtils::NameSpaceManager()->RegisterNameSpace(namesp, aNameSpaceID); |
|
1563 } |
|
1564 else { |
|
1565 aNameSpaceID = namespaceID; |
|
1566 } |
|
1567 |
|
1568 return NS_OK; |
|
1569 } |
|
1570 |
|
1571 nsresult |
|
1572 nsXBLPrototypeBinding::WriteNamespace(nsIObjectOutputStream* aStream, |
|
1573 int32_t aNameSpaceID) |
|
1574 { |
|
1575 // Namespaces are stored as a single byte id for well-known namespaces. |
|
1576 // This saves time and space as other namespaces aren't very common in |
|
1577 // XBL. If another namespace is used however, the namespace id will be |
|
1578 // XBLBinding_Serialize_CustomNamespace and the string namespace written |
|
1579 // out directly afterwards. |
|
1580 nsresult rv; |
|
1581 |
|
1582 if (aNameSpaceID <= kNameSpaceID_LastBuiltin) { |
|
1583 rv = aStream->Write8((int8_t)aNameSpaceID); |
|
1584 NS_ENSURE_SUCCESS(rv, rv); |
|
1585 } |
|
1586 else { |
|
1587 rv = aStream->Write8(XBLBinding_Serialize_CustomNamespace); |
|
1588 NS_ENSURE_SUCCESS(rv, rv); |
|
1589 |
|
1590 nsAutoString namesp; |
|
1591 nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, namesp); |
|
1592 aStream->WriteWStringZ(namesp.get()); |
|
1593 } |
|
1594 |
|
1595 return NS_OK; |
|
1596 } |
|
1597 |
|
1598 |
|
1599 bool CheckTagNameWhiteList(int32_t aNameSpaceID, nsIAtom *aTagName) |
|
1600 { |
|
1601 static nsIContent::AttrValuesArray kValidXULTagNames[] = { |
|
1602 &nsGkAtoms::autorepeatbutton, &nsGkAtoms::box, &nsGkAtoms::browser, |
|
1603 &nsGkAtoms::button, &nsGkAtoms::hbox, &nsGkAtoms::image, &nsGkAtoms::menu, |
|
1604 &nsGkAtoms::menubar, &nsGkAtoms::menuitem, &nsGkAtoms::menupopup, |
|
1605 &nsGkAtoms::row, &nsGkAtoms::slider, &nsGkAtoms::spacer, |
|
1606 &nsGkAtoms::splitter, &nsGkAtoms::text, &nsGkAtoms::tree, nullptr}; |
|
1607 |
|
1608 uint32_t i; |
|
1609 if (aNameSpaceID == kNameSpaceID_XUL) { |
|
1610 for (i = 0; kValidXULTagNames[i]; ++i) { |
|
1611 if (aTagName == *(kValidXULTagNames[i])) { |
|
1612 return true; |
|
1613 } |
|
1614 } |
|
1615 } |
|
1616 else if (aNameSpaceID == kNameSpaceID_SVG && |
|
1617 aTagName == nsGkAtoms::generic_) { |
|
1618 return true; |
|
1619 } |
|
1620 |
|
1621 return false; |
|
1622 } |
|
1623 |
|
1624 nsresult |
|
1625 nsXBLPrototypeBinding::ResolveBaseBinding() |
|
1626 { |
|
1627 if (mCheckedBaseProto) |
|
1628 return NS_OK; |
|
1629 mCheckedBaseProto = true; |
|
1630 |
|
1631 nsCOMPtr<nsIDocument> doc = mXBLDocInfoWeak->GetDocument(); |
|
1632 |
|
1633 // Check for the presence of 'extends' and 'display' attributes |
|
1634 nsAutoString display, extends; |
|
1635 mBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::extends, extends); |
|
1636 if (extends.IsEmpty()) |
|
1637 return NS_OK; |
|
1638 |
|
1639 mBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::display, display); |
|
1640 bool hasDisplay = !display.IsEmpty(); |
|
1641 |
|
1642 nsAutoString value(extends); |
|
1643 |
|
1644 // Now slice 'em up to see what we've got. |
|
1645 nsAutoString prefix; |
|
1646 int32_t offset; |
|
1647 if (hasDisplay) { |
|
1648 offset = display.FindChar(':'); |
|
1649 if (-1 != offset) { |
|
1650 display.Left(prefix, offset); |
|
1651 display.Cut(0, offset+1); |
|
1652 } |
|
1653 } |
|
1654 else { |
|
1655 offset = extends.FindChar(':'); |
|
1656 if (-1 != offset) { |
|
1657 extends.Left(prefix, offset); |
|
1658 extends.Cut(0, offset+1); |
|
1659 display = extends; |
|
1660 } |
|
1661 } |
|
1662 |
|
1663 nsAutoString nameSpace; |
|
1664 |
|
1665 if (!prefix.IsEmpty()) { |
|
1666 mBinding->LookupNamespaceURI(prefix, nameSpace); |
|
1667 if (!nameSpace.IsEmpty()) { |
|
1668 int32_t nameSpaceID = |
|
1669 nsContentUtils::NameSpaceManager()->GetNameSpaceID(nameSpace); |
|
1670 |
|
1671 nsCOMPtr<nsIAtom> tagName = do_GetAtom(display); |
|
1672 // Check the white list |
|
1673 if (!CheckTagNameWhiteList(nameSpaceID, tagName)) { |
|
1674 const char16_t* params[] = { display.get() }; |
|
1675 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, |
|
1676 NS_LITERAL_CSTRING("XBL"), nullptr, |
|
1677 nsContentUtils::eXBL_PROPERTIES, |
|
1678 "InvalidExtendsBinding", |
|
1679 params, ArrayLength(params), |
|
1680 doc->GetDocumentURI()); |
|
1681 NS_ASSERTION(!nsXBLService::IsChromeOrResourceURI(doc->GetDocumentURI()), |
|
1682 "Invalid extends value"); |
|
1683 return NS_ERROR_ILLEGAL_VALUE; |
|
1684 } |
|
1685 |
|
1686 SetBaseTag(nameSpaceID, tagName); |
|
1687 } |
|
1688 } |
|
1689 |
|
1690 if (hasDisplay || nameSpace.IsEmpty()) { |
|
1691 mBinding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::extends, false); |
|
1692 mBinding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::display, false); |
|
1693 |
|
1694 return NS_NewURI(getter_AddRefs(mBaseBindingURI), value, |
|
1695 doc->GetDocumentCharacterSet().get(), |
|
1696 doc->GetDocBaseURI()); |
|
1697 } |
|
1698 |
|
1699 return NS_OK; |
|
1700 } |