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/. */
6 #include "mozilla/ArrayUtils.h"
8 #include "nsXBLContentSink.h"
9 #include "nsIDocument.h"
10 #include "nsBindingManager.h"
11 #include "nsIDOMNode.h"
12 #include "nsGkAtoms.h"
13 #include "nsNameSpaceManager.h"
15 #include "nsTextFragment.h"
17 #include "nsXULElement.h"
19 #include "nsXBLProtoImplProperty.h"
20 #include "nsXBLProtoImplMethod.h"
21 #include "nsXBLProtoImplField.h"
22 #include "nsXBLPrototypeBinding.h"
23 #include "nsContentUtils.h"
24 #include "nsIConsoleService.h"
25 #include "nsIScriptError.h"
26 #include "nsNodeInfoManager.h"
27 #include "nsIPrincipal.h"
28 #include "mozilla/dom/Element.h"
30 using namespace mozilla
;
31 using namespace mozilla::dom
;
34 NS_NewXBLContentSink(nsIXMLContentSink
** aResult
,
37 nsISupports
* aContainer
)
39 NS_ENSURE_ARG_POINTER(aResult
);
41 nsXBLContentSink
* it
= new nsXBLContentSink();
42 NS_ENSURE_TRUE(it
, NS_ERROR_OUT_OF_MEMORY
);
44 nsCOMPtr
<nsIXMLContentSink
> kungFuDeathGrip
= it
;
45 nsresult rv
= it
->Init(aDoc
, aURI
, aContainer
);
46 NS_ENSURE_SUCCESS(rv
, rv
);
48 return CallQueryInterface(it
, aResult
);
51 nsXBLContentSink::nsXBLContentSink()
52 : mState(eXBL_InDocument
),
53 mSecondaryState(eXBL_None
),
55 mIsChromeOrResource(false),
56 mFoundFirstBinding(false),
59 mImplementation(nullptr),
66 mPrettyPrintXML
= false;
69 nsXBLContentSink::~nsXBLContentSink()
74 nsXBLContentSink::Init(nsIDocument
* aDoc
,
76 nsISupports
* aContainer
)
79 rv
= nsXMLContentSink::Init(aDoc
, aURI
, aContainer
, nullptr);
84 nsXBLContentSink::MaybeStartLayout(bool aIgnorePendingSheets
)
90 nsXBLContentSink::FlushText(bool aReleaseTextNode
)
92 if (mTextLength
!= 0) {
93 const nsASingleFragmentString
& text
= Substring(mText
, mText
+mTextLength
);
94 if (mState
== eXBL_InHandlers
) {
95 NS_ASSERTION(mBinding
, "Must have binding here");
96 // Get the text and add it to the event handler.
97 if (mSecondaryState
== eXBL_InHandler
)
98 mHandler
->AppendHandlerText(text
);
102 else if (mState
== eXBL_InImplementation
) {
103 NS_ASSERTION(mBinding
, "Must have binding here");
104 if (mSecondaryState
== eXBL_InConstructor
||
105 mSecondaryState
== eXBL_InDestructor
) {
106 // Construct a method for the constructor/destructor.
107 nsXBLProtoImplMethod
* method
;
108 if (mSecondaryState
== eXBL_InConstructor
)
109 method
= mBinding
->GetConstructor();
111 method
= mBinding
->GetDestructor();
113 // Get the text and add it to the constructor/destructor.
114 method
->AppendBodyText(text
);
116 else if (mSecondaryState
== eXBL_InGetter
||
117 mSecondaryState
== eXBL_InSetter
) {
118 // Get the text and add it to the getter/setter
119 if (mSecondaryState
== eXBL_InGetter
)
120 mProperty
->AppendGetterText(text
);
122 mProperty
->AppendSetterText(text
);
124 else if (mSecondaryState
== eXBL_InBody
) {
125 // Get the text and add it to the method
127 mMethod
->AppendBodyText(text
);
129 else if (mSecondaryState
== eXBL_InField
) {
130 // Get the text and add it to the method
132 mField
->AppendFieldText(text
);
138 nsIContent
* content
= GetCurrentContent();
140 (content
->NodeInfo()->NamespaceEquals(kNameSpaceID_XBL
) ||
141 (content
->NodeInfo()->NamespaceEquals(kNameSpaceID_XUL
) &&
142 content
->Tag() != nsGkAtoms::label
&&
143 content
->Tag() != nsGkAtoms::description
))) {
146 if (mTextLength
> 0) {
147 const char16_t
* cp
= mText
;
148 const char16_t
* end
= mText
+ mTextLength
;
151 if (!dom::IsSpaceCharacter(ch
)) {
158 if (isWS
&& mTextLength
> 0) {
160 // Make sure to drop the textnode, if any
161 return nsXMLContentSink::FlushText(aReleaseTextNode
);
166 return nsXMLContentSink::FlushText(aReleaseTextNode
);
170 nsXBLContentSink::ReportError(const char16_t
* aErrorText
,
171 const char16_t
* aSourceText
,
172 nsIScriptError
*aError
,
175 NS_PRECONDITION(aError
&& aSourceText
&& aErrorText
, "Check arguments!!!");
177 // XXX FIXME This function overrides and calls on
178 // nsXMLContentSink::ReportError, and probably should die. See bug 347826.
180 // XXX We should make sure the binding has no effect, but that it also
181 // gets destroyed properly without leaking. Perhaps we should even
182 // ensure that the content that was bound is displayed with no
186 // Report the error to stderr.
189 NS_LossyConvertUTF16toASCII(aErrorText
).get(),
190 NS_LossyConvertUTF16toASCII(aSourceText
).get());
193 // Most of what this does won't be too useful, but whatever...
194 // nsXMLContentSink::ReportError will handle the console logging.
195 return nsXMLContentSink::ReportError(aErrorText
,
202 nsXBLContentSink::ReportUnexpectedElement(nsIAtom
* aElementName
,
203 uint32_t aLineNumber
)
205 // XXX we should really somehow stop the parse and drop the binding
206 // instead of just letting the XML sink build the content model like
209 nsAutoString elementName
;
210 aElementName
->ToString(elementName
);
212 const char16_t
* params
[] = { elementName
.get() };
214 return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag
,
215 NS_LITERAL_CSTRING("XBL Content Sink"),
217 nsContentUtils::eXBL_PROPERTIES
,
219 params
, ArrayLength(params
),
221 EmptyString() /* source line */,
226 nsXBLContentSink::AddMember(nsXBLProtoImplMember
* aMember
)
228 // Add this member to our chain.
230 mImplMember
->SetNext(aMember
); // Already have a chain. Just append to the end.
232 mImplementation
->SetMemberList(aMember
); // We're the first member in the chain.
234 mImplMember
= aMember
; // Adjust our pointer to point to the new last member in the chain.
238 nsXBLContentSink::AddField(nsXBLProtoImplField
* aField
)
240 // Add this field to our chain.
242 mImplField
->SetNext(aField
); // Already have a chain. Just append to the end.
244 mImplementation
->SetFieldList(aField
); // We're the first member in the chain.
246 mImplField
= aField
; // Adjust our pointer to point to the new last field in the chain.
250 nsXBLContentSink::HandleStartElement(const char16_t
*aName
,
251 const char16_t
**aAtts
,
253 uint32_t aLineNumber
)
255 nsresult rv
= nsXMLContentSink::HandleStartElement(aName
, aAtts
, aAttsCount
,
260 if (mState
== eXBL_InBinding
&& !mBinding
) {
261 rv
= ConstructBinding(aLineNumber
);
265 // mBinding may still be null, if the binding had no id. If so,
266 // we'll deal with that later in the sink.
273 nsXBLContentSink::HandleEndElement(const char16_t
*aName
)
277 if (mState
!= eXBL_InDocument
) {
279 nsCOMPtr
<nsIAtom
> prefix
, localName
;
280 nsContentUtils::SplitExpatName(aName
, getter_AddRefs(prefix
),
281 getter_AddRefs(localName
), &nameSpaceID
);
283 if (nameSpaceID
== kNameSpaceID_XBL
) {
284 if (mState
== eXBL_Error
) {
285 // Check whether we've opened this tag before; we may not have if
286 // it was a real XBL tag before the error occurred.
287 if (!GetCurrentContent()->NodeInfo()->Equals(localName
,
289 // OK, this tag was never opened as far as the XML sink is
290 // concerned. Just drop the HandleEndElement
294 else if (mState
== eXBL_InHandlers
) {
295 if (localName
== nsGkAtoms::handlers
) {
296 mState
= eXBL_InBinding
;
299 else if (localName
== nsGkAtoms::handler
)
300 mSecondaryState
= eXBL_None
;
303 else if (mState
== eXBL_InResources
) {
304 if (localName
== nsGkAtoms::resources
)
305 mState
= eXBL_InBinding
;
308 else if (mState
== eXBL_InImplementation
) {
309 if (localName
== nsGkAtoms::implementation
)
310 mState
= eXBL_InBinding
;
311 else if (localName
== nsGkAtoms::property
) {
312 mSecondaryState
= eXBL_None
;
315 else if (localName
== nsGkAtoms::method
) {
316 mSecondaryState
= eXBL_None
;
319 else if (localName
== nsGkAtoms::field
) {
320 mSecondaryState
= eXBL_None
;
323 else if (localName
== nsGkAtoms::constructor
||
324 localName
== nsGkAtoms::destructor
)
325 mSecondaryState
= eXBL_None
;
326 else if (localName
== nsGkAtoms::getter
||
327 localName
== nsGkAtoms::setter
)
328 mSecondaryState
= eXBL_InProperty
;
329 else if (localName
== nsGkAtoms::parameter
||
330 localName
== nsGkAtoms::body
)
331 mSecondaryState
= eXBL_InMethod
;
334 else if (mState
== eXBL_InBindings
&&
335 localName
== nsGkAtoms::bindings
) {
336 mState
= eXBL_InDocument
;
339 nsresult rv
= nsXMLContentSink::HandleEndElement(aName
);
343 if (mState
== eXBL_InBinding
&& localName
== nsGkAtoms::binding
) {
344 mState
= eXBL_InBindings
;
345 if (mBinding
) { // See comment in HandleStartElement()
346 mBinding
->Initialize();
347 mBinding
= nullptr; // Clear our current binding ref.
355 return nsXMLContentSink::HandleEndElement(aName
);
359 nsXBLContentSink::HandleCDataSection(const char16_t
*aData
,
362 if (mState
== eXBL_InHandlers
|| mState
== eXBL_InImplementation
)
363 return AddText(aData
, aLength
);
364 return nsXMLContentSink::HandleCDataSection(aData
, aLength
);
367 #define ENSURE_XBL_STATE(_cond) \
369 if (!(_cond)) { ReportUnexpectedElement(aTagName, aLineNumber); return true; } \
373 nsXBLContentSink::OnOpenContainer(const char16_t
**aAtts
,
375 int32_t aNameSpaceID
,
377 uint32_t aLineNumber
)
379 if (mState
== eXBL_Error
) {
383 if (aNameSpaceID
!= kNameSpaceID_XBL
) {
384 // Construct non-XBL nodes
389 if (aTagName
== nsGkAtoms::bindings
) {
390 ENSURE_XBL_STATE(mState
== eXBL_InDocument
);
392 NS_ASSERTION(mDocument
, "Must have a document!");
393 nsRefPtr
<nsXBLDocumentInfo
> info
= new nsXBLDocumentInfo(mDocument
);
395 // We keep a weak ref. We're creating a cycle between doc/binding manager/doc info.
403 mDocument
->BindingManager()->PutXBLDocumentInfo(mDocInfo
);
405 nsIURI
*uri
= mDocument
->GetDocumentURI();
407 bool isChrome
= false;
410 uri
->SchemeIs("chrome", &isChrome
);
411 uri
->SchemeIs("resource", &isRes
);
412 mIsChromeOrResource
= isChrome
|| isRes
;
414 mState
= eXBL_InBindings
;
416 else if (aTagName
== nsGkAtoms::binding
) {
417 ENSURE_XBL_STATE(mState
== eXBL_InBindings
);
418 mState
= eXBL_InBinding
;
420 else if (aTagName
== nsGkAtoms::handlers
) {
421 ENSURE_XBL_STATE(mState
== eXBL_InBinding
&& mBinding
);
422 mState
= eXBL_InHandlers
;
425 else if (aTagName
== nsGkAtoms::handler
) {
426 ENSURE_XBL_STATE(mState
== eXBL_InHandlers
);
427 mSecondaryState
= eXBL_InHandler
;
428 ConstructHandler(aAtts
, aLineNumber
);
431 else if (aTagName
== nsGkAtoms::resources
) {
432 ENSURE_XBL_STATE(mState
== eXBL_InBinding
&& mBinding
);
433 mState
= eXBL_InResources
;
434 // Note that this mState will cause us to return false, so no need
435 // to set ret to false.
437 else if (aTagName
== nsGkAtoms::stylesheet
|| aTagName
== nsGkAtoms::image
) {
438 ENSURE_XBL_STATE(mState
== eXBL_InResources
);
439 NS_ASSERTION(mBinding
, "Must have binding here");
440 ConstructResource(aAtts
, aTagName
);
442 else if (aTagName
== nsGkAtoms::implementation
) {
443 ENSURE_XBL_STATE(mState
== eXBL_InBinding
&& mBinding
);
444 mState
= eXBL_InImplementation
;
445 ConstructImplementation(aAtts
);
446 // Note that this mState will cause us to return false, so no need
447 // to set ret to false.
449 else if (aTagName
== nsGkAtoms::constructor
) {
450 ENSURE_XBL_STATE(mState
== eXBL_InImplementation
&&
451 mSecondaryState
== eXBL_None
);
452 NS_ASSERTION(mBinding
, "Must have binding here");
454 mSecondaryState
= eXBL_InConstructor
;
456 if (!mCurrentBindingID
.IsEmpty()) {
457 name
.Assign(mCurrentBindingID
);
458 name
.AppendLiteral("_XBL_Constructor");
460 name
.AppendLiteral("XBL_Constructor");
462 nsXBLProtoImplAnonymousMethod
* newMethod
=
463 new nsXBLProtoImplAnonymousMethod(name
.get());
465 newMethod
->SetLineNumber(aLineNumber
);
466 mBinding
->SetConstructor(newMethod
);
467 AddMember(newMethod
);
470 else if (aTagName
== nsGkAtoms::destructor
) {
471 ENSURE_XBL_STATE(mState
== eXBL_InImplementation
&&
472 mSecondaryState
== eXBL_None
);
473 NS_ASSERTION(mBinding
, "Must have binding here");
474 mSecondaryState
= eXBL_InDestructor
;
476 if (!mCurrentBindingID
.IsEmpty()) {
477 name
.Assign(mCurrentBindingID
);
478 name
.AppendLiteral("_XBL_Destructor");
480 name
.AppendLiteral("XBL_Destructor");
482 nsXBLProtoImplAnonymousMethod
* newMethod
=
483 new nsXBLProtoImplAnonymousMethod(name
.get());
485 newMethod
->SetLineNumber(aLineNumber
);
486 mBinding
->SetDestructor(newMethod
);
487 AddMember(newMethod
);
490 else if (aTagName
== nsGkAtoms::field
) {
491 ENSURE_XBL_STATE(mState
== eXBL_InImplementation
&&
492 mSecondaryState
== eXBL_None
);
493 NS_ASSERTION(mBinding
, "Must have binding here");
494 mSecondaryState
= eXBL_InField
;
495 ConstructField(aAtts
, aLineNumber
);
497 else if (aTagName
== nsGkAtoms::property
) {
498 ENSURE_XBL_STATE(mState
== eXBL_InImplementation
&&
499 mSecondaryState
== eXBL_None
);
500 NS_ASSERTION(mBinding
, "Must have binding here");
501 mSecondaryState
= eXBL_InProperty
;
502 ConstructProperty(aAtts
, aLineNumber
);
504 else if (aTagName
== nsGkAtoms::getter
) {
505 ENSURE_XBL_STATE(mSecondaryState
== eXBL_InProperty
&& mProperty
);
506 NS_ASSERTION(mState
== eXBL_InImplementation
, "Unexpected state");
507 mProperty
->SetGetterLineNumber(aLineNumber
);
508 mSecondaryState
= eXBL_InGetter
;
510 else if (aTagName
== nsGkAtoms::setter
) {
511 ENSURE_XBL_STATE(mSecondaryState
== eXBL_InProperty
&& mProperty
);
512 NS_ASSERTION(mState
== eXBL_InImplementation
, "Unexpected state");
513 mProperty
->SetSetterLineNumber(aLineNumber
);
514 mSecondaryState
= eXBL_InSetter
;
516 else if (aTagName
== nsGkAtoms::method
) {
517 ENSURE_XBL_STATE(mState
== eXBL_InImplementation
&&
518 mSecondaryState
== eXBL_None
);
519 NS_ASSERTION(mBinding
, "Must have binding here");
520 mSecondaryState
= eXBL_InMethod
;
521 ConstructMethod(aAtts
);
523 else if (aTagName
== nsGkAtoms::parameter
) {
524 ENSURE_XBL_STATE(mSecondaryState
== eXBL_InMethod
&& mMethod
);
525 NS_ASSERTION(mState
== eXBL_InImplementation
, "Unexpected state");
526 ConstructParameter(aAtts
);
528 else if (aTagName
== nsGkAtoms::body
) {
529 ENSURE_XBL_STATE(mSecondaryState
== eXBL_InMethod
&& mMethod
);
530 NS_ASSERTION(mState
== eXBL_InImplementation
, "Unexpected state");
531 // stash away the line number
532 mMethod
->SetLineNumber(aLineNumber
);
533 mSecondaryState
= eXBL_InBody
;
536 return ret
&& mState
!= eXBL_InResources
&& mState
!= eXBL_InImplementation
;
539 #undef ENSURE_XBL_STATE
542 nsXBLContentSink::ConstructBinding(uint32_t aLineNumber
)
544 nsCOMPtr
<nsIContent
> binding
= GetCurrentContent();
545 binding
->GetAttr(kNameSpaceID_None
, nsGkAtoms::id
, mCurrentBindingID
);
546 NS_ConvertUTF16toUTF8
cid(mCurrentBindingID
);
550 // Don't create a binding with no id. nsXBLPrototypeBinding::Read also
551 // performs this check.
552 if (!cid
.IsEmpty()) {
553 mBinding
= new nsXBLPrototypeBinding();
555 return NS_ERROR_OUT_OF_MEMORY
;
557 rv
= mBinding
->Init(cid
, mDocInfo
, binding
, !mFoundFirstBinding
);
558 if (NS_SUCCEEDED(rv
) &&
559 NS_SUCCEEDED(mDocInfo
->SetPrototypeBinding(cid
, mBinding
))) {
560 if (!mFoundFirstBinding
) {
561 mFoundFirstBinding
= true;
562 mDocInfo
->SetFirstPrototypeBinding(mBinding
);
564 binding
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::id
, false);
570 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag
,
571 NS_LITERAL_CSTRING("XBL Content Sink"), nullptr,
572 nsContentUtils::eXBL_PROPERTIES
,
573 "MissingIdAttr", nullptr, 0,
583 FindValue(const char16_t
**aAtts
, nsIAtom
*aAtom
, const char16_t
**aResult
)
585 nsCOMPtr
<nsIAtom
> prefix
, localName
;
586 for (; *aAtts
; aAtts
+= 2) {
588 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
589 getter_AddRefs(localName
), &nameSpaceID
);
591 // Is this attribute one of the ones we care about?
592 if (nameSpaceID
== kNameSpaceID_None
&& localName
== aAtom
) {
603 nsXBLContentSink::ConstructHandler(const char16_t
**aAtts
, uint32_t aLineNumber
)
605 const char16_t
* event
= nullptr;
606 const char16_t
* modifiers
= nullptr;
607 const char16_t
* button
= nullptr;
608 const char16_t
* clickcount
= nullptr;
609 const char16_t
* keycode
= nullptr;
610 const char16_t
* charcode
= nullptr;
611 const char16_t
* phase
= nullptr;
612 const char16_t
* command
= nullptr;
613 const char16_t
* action
= nullptr;
614 const char16_t
* group
= nullptr;
615 const char16_t
* preventdefault
= nullptr;
616 const char16_t
* allowuntrusted
= nullptr;
618 nsCOMPtr
<nsIAtom
> prefix
, localName
;
619 for (; *aAtts
; aAtts
+= 2) {
621 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
622 getter_AddRefs(localName
), &nameSpaceID
);
624 if (nameSpaceID
!= kNameSpaceID_None
) {
628 // Is this attribute one of the ones we care about?
629 if (localName
== nsGkAtoms::event
)
631 else if (localName
== nsGkAtoms::modifiers
)
632 modifiers
= aAtts
[1];
633 else if (localName
== nsGkAtoms::button
)
635 else if (localName
== nsGkAtoms::clickcount
)
636 clickcount
= aAtts
[1];
637 else if (localName
== nsGkAtoms::keycode
)
639 else if (localName
== nsGkAtoms::key
|| localName
== nsGkAtoms::charcode
)
641 else if (localName
== nsGkAtoms::phase
)
643 else if (localName
== nsGkAtoms::command
)
645 else if (localName
== nsGkAtoms::action
)
647 else if (localName
== nsGkAtoms::group
)
649 else if (localName
== nsGkAtoms::preventdefault
)
650 preventdefault
= aAtts
[1];
651 else if (localName
== nsGkAtoms::allowuntrusted
)
652 allowuntrusted
= aAtts
[1];
655 if (command
&& !mIsChromeOrResource
) {
656 // Make sure the XBL doc is chrome or resource if we have a command
659 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag
,
660 NS_LITERAL_CSTRING("XBL Content Sink"),
662 nsContentUtils::eXBL_PROPERTIES
,
663 "CommandNotInChrome", nullptr, 0,
665 EmptyString() /* source line */,
667 return; // Don't even make this handler.
670 // All of our pointers are now filled in. Construct our handler with all of
672 nsXBLPrototypeHandler
* newHandler
;
673 newHandler
= new nsXBLPrototypeHandler(event
, phase
, action
, command
,
674 keycode
, charcode
, modifiers
, button
,
675 clickcount
, group
, preventdefault
,
676 allowuntrusted
, mBinding
, aLineNumber
);
679 // Add this handler to our chain of handlers.
681 // Already have a chain. Just append to the end.
682 mHandler
->SetNextHandler(newHandler
);
685 // We're the first handler in the chain.
686 mBinding
->SetPrototypeHandlers(newHandler
);
688 // Adjust our mHandler pointer to point to the new last handler in the
690 mHandler
= newHandler
;
697 nsXBLContentSink::ConstructResource(const char16_t
**aAtts
,
698 nsIAtom
* aResourceType
)
703 const char16_t
* src
= nullptr;
704 if (FindValue(aAtts
, nsGkAtoms::src
, &src
)) {
705 mBinding
->AddResource(aResourceType
, nsDependentString(src
));
710 nsXBLContentSink::ConstructImplementation(const char16_t
**aAtts
)
712 mImplementation
= nullptr;
713 mImplMember
= nullptr;
714 mImplField
= nullptr;
719 const char16_t
* name
= nullptr;
721 nsCOMPtr
<nsIAtom
> prefix
, localName
;
722 for (; *aAtts
; aAtts
+= 2) {
724 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
725 getter_AddRefs(localName
), &nameSpaceID
);
727 if (nameSpaceID
!= kNameSpaceID_None
) {
731 // Is this attribute one of the ones we care about?
732 if (localName
== nsGkAtoms::name
) {
735 else if (localName
== nsGkAtoms::implements
) {
736 // Only allow implementation of interfaces via XBL if the principal of
737 // our XBL document is the system principal.
738 if (nsContentUtils::IsSystemPrincipal(mDocument
->NodePrincipal())) {
739 mBinding
->ConstructInterfaceTable(nsDependentString(aAtts
[1]));
744 NS_NewXBLProtoImpl(mBinding
, name
, &mImplementation
);
748 nsXBLContentSink::ConstructField(const char16_t
**aAtts
, uint32_t aLineNumber
)
750 const char16_t
* name
= nullptr;
751 const char16_t
* readonly
= nullptr;
753 nsCOMPtr
<nsIAtom
> prefix
, localName
;
754 for (; *aAtts
; aAtts
+= 2) {
756 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
757 getter_AddRefs(localName
), &nameSpaceID
);
759 if (nameSpaceID
!= kNameSpaceID_None
) {
763 // Is this attribute one of the ones we care about?
764 if (localName
== nsGkAtoms::name
) {
767 else if (localName
== nsGkAtoms::readonly
) {
773 // All of our pointers are now filled in. Construct our field with all of
775 mField
= new nsXBLProtoImplField(name
, readonly
);
777 mField
->SetLineNumber(aLineNumber
);
784 nsXBLContentSink::ConstructProperty(const char16_t
**aAtts
, uint32_t aLineNumber
)
786 const char16_t
* name
= nullptr;
787 const char16_t
* readonly
= nullptr;
788 const char16_t
* onget
= nullptr;
789 const char16_t
* onset
= nullptr;
790 bool exposeToUntrustedContent
= false;
792 nsCOMPtr
<nsIAtom
> prefix
, localName
;
793 for (; *aAtts
; aAtts
+= 2) {
795 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
796 getter_AddRefs(localName
), &nameSpaceID
);
798 if (nameSpaceID
!= kNameSpaceID_None
) {
802 // Is this attribute one of the ones we care about?
803 if (localName
== nsGkAtoms::name
) {
806 else if (localName
== nsGkAtoms::readonly
) {
809 else if (localName
== nsGkAtoms::onget
) {
812 else if (localName
== nsGkAtoms::onset
) {
815 else if (localName
== nsGkAtoms::exposeToUntrustedContent
&&
816 nsDependentString(aAtts
[1]).EqualsLiteral("true"))
818 exposeToUntrustedContent
= true;
823 // All of our pointers are now filled in. Construct our property with all of
825 mProperty
= new nsXBLProtoImplProperty(name
, onget
, onset
, readonly
, aLineNumber
);
826 if (exposeToUntrustedContent
) {
827 mProperty
->SetExposeToUntrustedContent(true);
829 AddMember(mProperty
);
834 nsXBLContentSink::ConstructMethod(const char16_t
**aAtts
)
838 const char16_t
* name
= nullptr;
839 const char16_t
* expose
= nullptr;
840 if (FindValue(aAtts
, nsGkAtoms::name
, &name
)) {
841 mMethod
= new nsXBLProtoImplMethod(name
);
842 if (FindValue(aAtts
, nsGkAtoms::exposeToUntrustedContent
, &expose
) &&
843 nsDependentString(expose
).EqualsLiteral("true"))
845 mMethod
->SetExposeToUntrustedContent(true);
855 nsXBLContentSink::ConstructParameter(const char16_t
**aAtts
)
860 const char16_t
* name
= nullptr;
861 if (FindValue(aAtts
, nsGkAtoms::name
, &name
)) {
862 mMethod
->AddParameter(nsDependentString(name
));
867 nsXBLContentSink::CreateElement(const char16_t
** aAtts
, uint32_t aAttsCount
,
868 mozilla::dom::NodeInfo
* aNodeInfo
, uint32_t aLineNumber
,
869 nsIContent
** aResult
, bool* aAppendContent
,
870 FromParser aFromParser
)
873 if (!aNodeInfo
->NamespaceEquals(kNameSpaceID_XUL
)) {
875 return nsXMLContentSink::CreateElement(aAtts
, aAttsCount
, aNodeInfo
,
876 aLineNumber
, aResult
,
877 aAppendContent
, aFromParser
);
881 // Note that this needs to match the code in nsXBLPrototypeBinding::ReadContentNode.
883 *aAppendContent
= true;
884 nsRefPtr
<nsXULPrototypeElement
> prototype
= new nsXULPrototypeElement();
886 return NS_ERROR_OUT_OF_MEMORY
;
888 prototype
->mNodeInfo
= aNodeInfo
;
890 AddAttributesToXULPrototype(aAtts
, aAttsCount
, prototype
);
893 nsresult rv
= nsXULElement::Create(prototype
, mDocument
, false, false, &result
);
900 nsXBLContentSink::AddAttributes(const char16_t
** aAtts
,
901 nsIContent
* aContent
)
903 if (aContent
->IsXUL())
904 return NS_OK
; // Nothing to do, since the proto already has the attrs.
906 return nsXMLContentSink::AddAttributes(aAtts
, aContent
);
911 nsXBLContentSink::AddAttributesToXULPrototype(const char16_t
**aAtts
,
913 nsXULPrototypeElement
* aElement
)
915 // Add tag attributes to the element
918 // Create storage for the attributes
919 nsXULPrototypeAttribute
* attrs
= nullptr;
920 if (aAttsCount
> 0) {
921 attrs
= new nsXULPrototypeAttribute
[aAttsCount
];
923 return NS_ERROR_OUT_OF_MEMORY
;
926 aElement
->mAttributes
= attrs
;
927 aElement
->mNumAttributes
= aAttsCount
;
929 // Copy the attributes into the prototype
930 nsCOMPtr
<nsIAtom
> prefix
, localName
;
933 for (i
= 0; i
< aAttsCount
; ++i
) {
935 nsContentUtils::SplitExpatName(aAtts
[i
* 2], getter_AddRefs(prefix
),
936 getter_AddRefs(localName
), &nameSpaceID
);
938 if (nameSpaceID
== kNameSpaceID_None
) {
939 attrs
[i
].mName
.SetTo(localName
);
942 nsRefPtr
<NodeInfo
> ni
;
943 ni
= mNodeInfoManager
->GetNodeInfo(localName
, prefix
, nameSpaceID
,
944 nsIDOMNode::ATTRIBUTE_NODE
);
945 attrs
[i
].mName
.SetTo(ni
);
948 rv
= aElement
->SetAttrAt(i
, nsDependentString(aAtts
[i
* 2 + 1]),
950 NS_ENSURE_SUCCESS(rv
, rv
);