1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * David Hyatt <hyatt@netscape.com> (Original Author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsXBLContentSink.h"
40 #include "nsIDocument.h"
41 #include "nsBindingManager.h"
42 #include "nsIDOMNode.h"
43 #include "nsIParser.h"
44 #include "nsGkAtoms.h"
45 #include "nsINameSpaceManager.h"
46 #include "nsHTMLTokens.h"
48 #include "nsTextFragment.h"
50 #include "nsXULElement.h"
52 #include "nsXBLProtoImplProperty.h"
53 #include "nsXBLProtoImplMethod.h"
54 #include "nsXBLProtoImplField.h"
55 #include "nsXBLPrototypeBinding.h"
56 #include "nsContentUtils.h"
57 #include "nsIConsoleService.h"
58 #include "nsIScriptError.h"
59 #include "nsNodeInfoManager.h"
60 #include "nsINodeInfo.h"
61 #include "nsIPrincipal.h"
64 NS_NewXBLContentSink(nsIXMLContentSink
** aResult
,
67 nsISupports
* aContainer
)
69 NS_ENSURE_ARG_POINTER(aResult
);
72 NS_NEWXPCOM(it
, nsXBLContentSink
);
73 NS_ENSURE_TRUE(it
, NS_ERROR_OUT_OF_MEMORY
);
75 nsCOMPtr
<nsIXMLContentSink
> kungFuDeathGrip
= it
;
76 nsresult rv
= it
->Init(aDoc
, aURI
, aContainer
);
77 NS_ENSURE_SUCCESS(rv
, rv
);
79 return CallQueryInterface(it
, aResult
);
82 nsXBLContentSink::nsXBLContentSink()
83 : mState(eXBL_InDocument
),
84 mSecondaryState(eXBL_None
),
86 mIsChromeOrResource(PR_FALSE
),
87 mFoundFirstBinding(PR_FALSE
),
90 mImplementation(nsnull
),
97 mPrettyPrintXML
= PR_FALSE
;
100 nsXBLContentSink::~nsXBLContentSink()
105 nsXBLContentSink::Init(nsIDocument
* aDoc
,
107 nsISupports
* aContainer
)
110 rv
= nsXMLContentSink::Init(aDoc
, aURI
, aContainer
, nsnull
);
115 nsXBLContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets
)
121 nsXBLContentSink::FlushText(PRBool aReleaseTextNode
)
123 if (mTextLength
!= 0) {
124 const nsASingleFragmentString
& text
= Substring(mText
, mText
+mTextLength
);
125 if (mState
== eXBL_InHandlers
) {
126 NS_ASSERTION(mBinding
, "Must have binding here");
127 // Get the text and add it to the event handler.
128 if (mSecondaryState
== eXBL_InHandler
)
129 mHandler
->AppendHandlerText(text
);
133 else if (mState
== eXBL_InImplementation
) {
134 NS_ASSERTION(mBinding
, "Must have binding here");
135 if (mSecondaryState
== eXBL_InConstructor
||
136 mSecondaryState
== eXBL_InDestructor
) {
137 // Construct a method for the constructor/destructor.
138 nsXBLProtoImplMethod
* method
;
139 if (mSecondaryState
== eXBL_InConstructor
)
140 method
= mBinding
->GetConstructor();
142 method
= mBinding
->GetDestructor();
144 // Get the text and add it to the constructor/destructor.
145 method
->AppendBodyText(text
);
147 else if (mSecondaryState
== eXBL_InGetter
||
148 mSecondaryState
== eXBL_InSetter
) {
149 // Get the text and add it to the getter/setter
150 if (mSecondaryState
== eXBL_InGetter
)
151 mProperty
->AppendGetterText(text
);
153 mProperty
->AppendSetterText(text
);
155 else if (mSecondaryState
== eXBL_InBody
) {
156 // Get the text and add it to the method
158 mMethod
->AppendBodyText(text
);
160 else if (mSecondaryState
== eXBL_InField
) {
161 // Get the text and add it to the method
163 mField
->AppendFieldText(text
);
169 nsIContent
* content
= GetCurrentContent();
171 (content
->NodeInfo()->NamespaceEquals(kNameSpaceID_XBL
) ||
172 (content
->NodeInfo()->NamespaceEquals(kNameSpaceID_XUL
) &&
173 content
->Tag() != nsGkAtoms::label
&&
174 content
->Tag() != nsGkAtoms::description
))) {
176 PRBool isWS
= PR_TRUE
;
177 if (mTextLength
> 0) {
178 const PRUnichar
* cp
= mText
;
179 const PRUnichar
* end
= mText
+ mTextLength
;
181 PRUnichar ch
= *cp
++;
182 if (!XP_IS_SPACE(ch
)) {
189 if (isWS
&& mTextLength
> 0) {
191 // Make sure to drop the textnode, if any
192 return nsXMLContentSink::FlushText(aReleaseTextNode
);
197 return nsXMLContentSink::FlushText(aReleaseTextNode
);
201 nsXBLContentSink::ReportError(const PRUnichar
* aErrorText
,
202 const PRUnichar
* aSourceText
,
203 nsIScriptError
*aError
,
206 NS_PRECONDITION(aError
&& aSourceText
&& aErrorText
, "Check arguments!!!");
208 // XXX FIXME This function overrides and calls on
209 // nsXMLContentSink::ReportError, and probably should die. See bug 347826.
211 // XXX We should make sure the binding has no effect, but that it also
212 // gets destroyed properly without leaking. Perhaps we should even
213 // ensure that the content that was bound is displayed with no
217 // Report the error to stderr.
220 NS_LossyConvertUTF16toASCII(aErrorText
).get(),
221 NS_LossyConvertUTF16toASCII(aSourceText
).get());
224 // Most of what this does won't be too useful, but whatever...
225 // nsXMLContentSink::ReportError will handle the console logging.
226 return nsXMLContentSink::ReportError(aErrorText
,
233 nsXBLContentSink::ReportUnexpectedElement(nsIAtom
* aElementName
,
234 PRUint32 aLineNumber
)
236 // XXX we should really somehow stop the parse and drop the binding
237 // instead of just letting the XML sink build the content model like
240 nsAutoString elementName
;
241 aElementName
->ToString(elementName
);
243 const PRUnichar
* params
[] = { elementName
.get() };
245 return nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES
,
247 params
, NS_ARRAY_LENGTH(params
),
249 EmptyString() /* source line */,
250 aLineNumber
, 0 /* column number */,
251 nsIScriptError::errorFlag
,
256 nsXBLContentSink::AddMember(nsXBLProtoImplMember
* aMember
)
258 // Add this member to our chain.
260 mImplMember
->SetNext(aMember
); // Already have a chain. Just append to the end.
262 mImplementation
->SetMemberList(aMember
); // We're the first member in the chain.
264 mImplMember
= aMember
; // Adjust our pointer to point to the new last member in the chain.
268 nsXBLContentSink::AddField(nsXBLProtoImplField
* aField
)
270 // Add this field to our chain.
272 mImplField
->SetNext(aField
); // Already have a chain. Just append to the end.
274 mImplementation
->SetFieldList(aField
); // We're the first member in the chain.
276 mImplField
= aField
; // Adjust our pointer to point to the new last field in the chain.
280 nsXBLContentSink::HandleStartElement(const PRUnichar
*aName
,
281 const PRUnichar
**aAtts
,
284 PRUint32 aLineNumber
)
286 nsresult rv
= nsXMLContentSink::HandleStartElement(aName
,aAtts
,aAttsCount
,aIndex
,aLineNumber
);
290 if (mState
== eXBL_InBinding
&& !mBinding
) {
291 rv
= ConstructBinding();
295 // mBinding may still be null, if the binding had no id. If so,
296 // we'll deal with that later in the sink.
303 nsXBLContentSink::HandleEndElement(const PRUnichar
*aName
)
307 if (mState
!= eXBL_InDocument
) {
309 nsCOMPtr
<nsIAtom
> prefix
, localName
;
310 nsContentUtils::SplitExpatName(aName
, getter_AddRefs(prefix
),
311 getter_AddRefs(localName
), &nameSpaceID
);
313 if (nameSpaceID
== kNameSpaceID_XBL
) {
314 if (mState
== eXBL_Error
) {
315 // Check whether we've opened this tag before; we may not have if
316 // it was a real XBL tag before the error occured.
317 if (!GetCurrentContent()->NodeInfo()->Equals(localName
,
319 // OK, this tag was never opened as far as the XML sink is
320 // concerned. Just drop the HandleEndElement
324 else if (mState
== eXBL_InHandlers
) {
325 if (localName
== nsGkAtoms::handlers
) {
326 mState
= eXBL_InBinding
;
329 else if (localName
== nsGkAtoms::handler
)
330 mSecondaryState
= eXBL_None
;
333 else if (mState
== eXBL_InResources
) {
334 if (localName
== nsGkAtoms::resources
)
335 mState
= eXBL_InBinding
;
338 else if (mState
== eXBL_InImplementation
) {
339 if (localName
== nsGkAtoms::implementation
)
340 mState
= eXBL_InBinding
;
341 else if (localName
== nsGkAtoms::property
) {
342 mSecondaryState
= eXBL_None
;
345 else if (localName
== nsGkAtoms::method
) {
346 mSecondaryState
= eXBL_None
;
349 else if (localName
== nsGkAtoms::field
) {
350 mSecondaryState
= eXBL_None
;
353 else if (localName
== nsGkAtoms::constructor
||
354 localName
== nsGkAtoms::destructor
)
355 mSecondaryState
= eXBL_None
;
356 else if (localName
== nsGkAtoms::getter
||
357 localName
== nsGkAtoms::setter
)
358 mSecondaryState
= eXBL_InProperty
;
359 else if (localName
== nsGkAtoms::parameter
||
360 localName
== nsGkAtoms::body
)
361 mSecondaryState
= eXBL_InMethod
;
364 else if (mState
== eXBL_InBindings
&&
365 localName
== nsGkAtoms::bindings
) {
366 mState
= eXBL_InDocument
;
369 nsresult rv
= nsXMLContentSink::HandleEndElement(aName
);
373 if (mState
== eXBL_InBinding
&& localName
== nsGkAtoms::binding
) {
374 mState
= eXBL_InBindings
;
375 if (mBinding
) { // See comment in HandleStartElement()
376 mBinding
->Initialize();
377 mBinding
= nsnull
; // Clear our current binding ref.
385 return nsXMLContentSink::HandleEndElement(aName
);
389 nsXBLContentSink::HandleCDataSection(const PRUnichar
*aData
,
392 if (mState
== eXBL_InHandlers
|| mState
== eXBL_InImplementation
)
393 return AddText(aData
, aLength
);
394 return nsXMLContentSink::HandleCDataSection(aData
, aLength
);
397 #define ENSURE_XBL_STATE(_cond) \
399 if (!(_cond)) { ReportUnexpectedElement(aTagName, aLineNumber); return PR_TRUE; } \
403 nsXBLContentSink::OnOpenContainer(const PRUnichar
**aAtts
,
405 PRInt32 aNameSpaceID
,
407 PRUint32 aLineNumber
)
409 if (mState
== eXBL_Error
) {
413 if (aNameSpaceID
!= kNameSpaceID_XBL
) {
414 // Construct non-XBL nodes
418 PRBool ret
= PR_TRUE
;
419 if (aTagName
== nsGkAtoms::bindings
) {
420 ENSURE_XBL_STATE(mState
== eXBL_InDocument
);
422 NS_NewXBLDocumentInfo(mDocument
, &mDocInfo
);
428 mDocument
->BindingManager()->PutXBLDocumentInfo(mDocInfo
);
430 nsIURI
*uri
= mDocument
->GetDocumentURI();
432 PRBool isChrome
= PR_FALSE
;
433 PRBool isRes
= PR_FALSE
;
435 uri
->SchemeIs("chrome", &isChrome
);
436 uri
->SchemeIs("resource", &isRes
);
437 mIsChromeOrResource
= isChrome
|| isRes
;
439 nsIXBLDocumentInfo
* info
= mDocInfo
;
440 NS_RELEASE(info
); // We keep a weak ref. We've created a cycle between doc/binding manager/doc info.
441 mState
= eXBL_InBindings
;
443 else if (aTagName
== nsGkAtoms::binding
) {
444 ENSURE_XBL_STATE(mState
== eXBL_InBindings
);
445 mState
= eXBL_InBinding
;
447 else if (aTagName
== nsGkAtoms::handlers
) {
448 ENSURE_XBL_STATE(mState
== eXBL_InBinding
&& mBinding
);
449 mState
= eXBL_InHandlers
;
452 else if (aTagName
== nsGkAtoms::handler
) {
453 ENSURE_XBL_STATE(mState
== eXBL_InHandlers
);
454 mSecondaryState
= eXBL_InHandler
;
455 ConstructHandler(aAtts
, aLineNumber
);
458 else if (aTagName
== nsGkAtoms::resources
) {
459 ENSURE_XBL_STATE(mState
== eXBL_InBinding
&& mBinding
);
460 mState
= eXBL_InResources
;
461 // Note that this mState will cause us to return false, so no need
462 // to set ret to false.
464 else if (aTagName
== nsGkAtoms::stylesheet
|| aTagName
== nsGkAtoms::image
) {
465 ENSURE_XBL_STATE(mState
== eXBL_InResources
);
466 NS_ASSERTION(mBinding
, "Must have binding here");
467 ConstructResource(aAtts
, aTagName
);
469 else if (aTagName
== nsGkAtoms::implementation
) {
470 ENSURE_XBL_STATE(mState
== eXBL_InBinding
&& mBinding
);
471 mState
= eXBL_InImplementation
;
472 ConstructImplementation(aAtts
);
473 // Note that this mState will cause us to return false, so no need
474 // to set ret to false.
476 else if (aTagName
== nsGkAtoms::constructor
) {
477 ENSURE_XBL_STATE(mState
== eXBL_InImplementation
&&
478 mSecondaryState
== eXBL_None
);
479 NS_ASSERTION(mBinding
, "Must have binding here");
481 mSecondaryState
= eXBL_InConstructor
;
482 nsXBLProtoImplAnonymousMethod
* newMethod
=
483 new nsXBLProtoImplAnonymousMethod();
485 newMethod
->SetLineNumber(aLineNumber
);
486 mBinding
->SetConstructor(newMethod
);
487 AddMember(newMethod
);
490 else if (aTagName
== nsGkAtoms::destructor
) {
491 ENSURE_XBL_STATE(mState
== eXBL_InImplementation
&&
492 mSecondaryState
== eXBL_None
);
493 NS_ASSERTION(mBinding
, "Must have binding here");
494 mSecondaryState
= eXBL_InDestructor
;
495 nsXBLProtoImplAnonymousMethod
* newMethod
=
496 new nsXBLProtoImplAnonymousMethod();
498 newMethod
->SetLineNumber(aLineNumber
);
499 mBinding
->SetDestructor(newMethod
);
500 AddMember(newMethod
);
503 else if (aTagName
== nsGkAtoms::field
) {
504 ENSURE_XBL_STATE(mState
== eXBL_InImplementation
&&
505 mSecondaryState
== eXBL_None
);
506 NS_ASSERTION(mBinding
, "Must have binding here");
507 mSecondaryState
= eXBL_InField
;
508 ConstructField(aAtts
, aLineNumber
);
510 else if (aTagName
== nsGkAtoms::property
) {
511 ENSURE_XBL_STATE(mState
== eXBL_InImplementation
&&
512 mSecondaryState
== eXBL_None
);
513 NS_ASSERTION(mBinding
, "Must have binding here");
514 mSecondaryState
= eXBL_InProperty
;
515 ConstructProperty(aAtts
);
517 else if (aTagName
== nsGkAtoms::getter
) {
518 ENSURE_XBL_STATE(mSecondaryState
== eXBL_InProperty
&& mProperty
);
519 NS_ASSERTION(mState
== eXBL_InImplementation
, "Unexpected state");
520 mProperty
->SetGetterLineNumber(aLineNumber
);
521 mSecondaryState
= eXBL_InGetter
;
523 else if (aTagName
== nsGkAtoms::setter
) {
524 ENSURE_XBL_STATE(mSecondaryState
== eXBL_InProperty
&& mProperty
);
525 NS_ASSERTION(mState
== eXBL_InImplementation
, "Unexpected state");
526 mProperty
->SetSetterLineNumber(aLineNumber
);
527 mSecondaryState
= eXBL_InSetter
;
529 else if (aTagName
== nsGkAtoms::method
) {
530 ENSURE_XBL_STATE(mState
== eXBL_InImplementation
&&
531 mSecondaryState
== eXBL_None
);
532 NS_ASSERTION(mBinding
, "Must have binding here");
533 mSecondaryState
= eXBL_InMethod
;
534 ConstructMethod(aAtts
);
536 else if (aTagName
== nsGkAtoms::parameter
) {
537 ENSURE_XBL_STATE(mSecondaryState
== eXBL_InMethod
&& mMethod
);
538 NS_ASSERTION(mState
== eXBL_InImplementation
, "Unexpected state");
539 ConstructParameter(aAtts
);
541 else if (aTagName
== nsGkAtoms::body
) {
542 ENSURE_XBL_STATE(mSecondaryState
== eXBL_InMethod
&& mMethod
);
543 NS_ASSERTION(mState
== eXBL_InImplementation
, "Unexpected state");
544 // stash away the line number
545 mMethod
->SetLineNumber(aLineNumber
);
546 mSecondaryState
= eXBL_InBody
;
549 return ret
&& mState
!= eXBL_InResources
&& mState
!= eXBL_InImplementation
;
552 #undef ENSURE_XBL_STATE
555 nsXBLContentSink::ConstructBinding()
557 nsCOMPtr
<nsIContent
> binding
= GetCurrentContent();
559 binding
->GetAttr(kNameSpaceID_None
, nsGkAtoms::id
, id
);
560 NS_ConvertUTF16toUTF8
cid(id
);
564 if (!cid
.IsEmpty()) {
565 mBinding
= new nsXBLPrototypeBinding();
567 return NS_ERROR_OUT_OF_MEMORY
;
569 rv
= mBinding
->Init(cid
, mDocInfo
, binding
);
570 if (NS_SUCCEEDED(rv
) &&
571 NS_SUCCEEDED(mDocInfo
->SetPrototypeBinding(cid
, mBinding
))) {
572 if (!mFoundFirstBinding
) {
573 mFoundFirstBinding
= PR_TRUE
;
574 mDocInfo
->SetFirstPrototypeBinding(mBinding
);
576 binding
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::id
, PR_FALSE
);
587 FindValue(const PRUnichar
**aAtts
, nsIAtom
*aAtom
, const PRUnichar
**aResult
)
589 nsCOMPtr
<nsIAtom
> prefix
, localName
;
590 for (; *aAtts
; aAtts
+= 2) {
592 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
593 getter_AddRefs(localName
), &nameSpaceID
);
595 // Is this attribute one of the ones we care about?
596 if (nameSpaceID
== kNameSpaceID_None
&& localName
== aAtom
) {
607 nsXBLContentSink::ConstructHandler(const PRUnichar
**aAtts
, PRUint32 aLineNumber
)
609 const PRUnichar
* event
= nsnull
;
610 const PRUnichar
* modifiers
= nsnull
;
611 const PRUnichar
* button
= nsnull
;
612 const PRUnichar
* clickcount
= nsnull
;
613 const PRUnichar
* keycode
= nsnull
;
614 const PRUnichar
* charcode
= nsnull
;
615 const PRUnichar
* phase
= nsnull
;
616 const PRUnichar
* command
= nsnull
;
617 const PRUnichar
* action
= nsnull
;
618 const PRUnichar
* group
= nsnull
;
619 const PRUnichar
* preventdefault
= nsnull
;
620 const PRUnichar
* allowuntrusted
= nsnull
;
622 nsCOMPtr
<nsIAtom
> prefix
, localName
;
623 for (; *aAtts
; aAtts
+= 2) {
625 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
626 getter_AddRefs(localName
), &nameSpaceID
);
628 if (nameSpaceID
!= kNameSpaceID_None
) {
632 // Is this attribute one of the ones we care about?
633 if (localName
== nsGkAtoms::event
)
635 else if (localName
== nsGkAtoms::modifiers
)
636 modifiers
= aAtts
[1];
637 else if (localName
== nsGkAtoms::button
)
639 else if (localName
== nsGkAtoms::clickcount
)
640 clickcount
= aAtts
[1];
641 else if (localName
== nsGkAtoms::keycode
)
643 else if (localName
== nsGkAtoms::key
|| localName
== nsGkAtoms::charcode
)
645 else if (localName
== nsGkAtoms::phase
)
647 else if (localName
== nsGkAtoms::command
)
649 else if (localName
== nsGkAtoms::action
)
651 else if (localName
== nsGkAtoms::group
)
653 else if (localName
== nsGkAtoms::preventdefault
)
654 preventdefault
= aAtts
[1];
655 else if (localName
== nsGkAtoms::allowuntrusted
)
656 allowuntrusted
= aAtts
[1];
659 if (command
&& !mIsChromeOrResource
) {
660 // Make sure the XBL doc is chrome or resource if we have a command
663 nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES
,
664 "CommandNotInChrome", nsnull
, 0,
666 EmptyString() /* source line */,
667 aLineNumber
, 0 /* column number */,
668 nsIScriptError::errorFlag
,
670 return; // Don't even make this handler.
673 // All of our pointers are now filled in. Construct our handler with all of
675 nsXBLPrototypeHandler
* newHandler
;
676 newHandler
= new nsXBLPrototypeHandler(event
, phase
, action
, command
,
677 keycode
, charcode
, modifiers
, button
,
678 clickcount
, group
, preventdefault
,
679 allowuntrusted
, mBinding
, aLineNumber
);
682 // Add this handler to our chain of handlers.
684 // Already have a chain. Just append to the end.
685 mHandler
->SetNextHandler(newHandler
);
688 // We're the first handler in the chain.
689 mBinding
->SetPrototypeHandlers(newHandler
);
691 // Adjust our mHandler pointer to point to the new last handler in the
693 mHandler
= newHandler
;
700 nsXBLContentSink::ConstructResource(const PRUnichar
**aAtts
,
701 nsIAtom
* aResourceType
)
706 const PRUnichar
* src
= nsnull
;
707 if (FindValue(aAtts
, nsGkAtoms::src
, &src
)) {
708 mBinding
->AddResource(aResourceType
, nsDependentString(src
));
713 nsXBLContentSink::ConstructImplementation(const PRUnichar
**aAtts
)
715 mImplementation
= nsnull
;
716 mImplMember
= nsnull
;
722 const PRUnichar
* name
= nsnull
;
724 nsCOMPtr
<nsIAtom
> prefix
, localName
;
725 for (; *aAtts
; aAtts
+= 2) {
727 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
728 getter_AddRefs(localName
), &nameSpaceID
);
730 if (nameSpaceID
!= kNameSpaceID_None
) {
734 // Is this attribute one of the ones we care about?
735 if (localName
== nsGkAtoms::name
) {
738 else if (localName
== nsGkAtoms::implements
) {
739 // Only allow implementation of interfaces via XBL if the principal of
740 // our XBL document has UniversalXPConnect privileges. No principal
743 // XXX this api is so badly tied to JS it's not even funny. We don't
744 // have a concept of enabling capabilities on a per-principal basis,
745 // but only on a per-principal-and-JS-stackframe basis! So for now
746 // this is basically equivalent to testing that we have the system
747 // principal, since there is no JS stackframe in sight here...
748 PRBool hasUniversalXPConnect
;
749 nsresult rv
= mDocument
->NodePrincipal()->
750 IsCapabilityEnabled("UniversalXPConnect", nsnull
,
751 &hasUniversalXPConnect
);
752 if (NS_SUCCEEDED(rv
) && hasUniversalXPConnect
) {
753 mBinding
->ConstructInterfaceTable(nsDependentString(aAtts
[1]));
758 NS_NewXBLProtoImpl(mBinding
, name
, &mImplementation
);
762 nsXBLContentSink::ConstructField(const PRUnichar
**aAtts
, PRUint32 aLineNumber
)
764 const PRUnichar
* name
= nsnull
;
765 const PRUnichar
* readonly
= nsnull
;
767 nsCOMPtr
<nsIAtom
> prefix
, localName
;
768 for (; *aAtts
; aAtts
+= 2) {
770 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
771 getter_AddRefs(localName
), &nameSpaceID
);
773 if (nameSpaceID
!= kNameSpaceID_None
) {
777 // Is this attribute one of the ones we care about?
778 if (localName
== nsGkAtoms::name
) {
781 else if (localName
== nsGkAtoms::readonly
) {
787 // All of our pointers are now filled in. Construct our field with all of
789 mField
= new nsXBLProtoImplField(name
, readonly
);
791 mField
->SetLineNumber(aLineNumber
);
798 nsXBLContentSink::ConstructProperty(const PRUnichar
**aAtts
)
800 const PRUnichar
* name
= nsnull
;
801 const PRUnichar
* readonly
= nsnull
;
802 const PRUnichar
* onget
= nsnull
;
803 const PRUnichar
* onset
= nsnull
;
805 nsCOMPtr
<nsIAtom
> prefix
, localName
;
806 for (; *aAtts
; aAtts
+= 2) {
808 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
809 getter_AddRefs(localName
), &nameSpaceID
);
811 if (nameSpaceID
!= kNameSpaceID_None
) {
815 // Is this attribute one of the ones we care about?
816 if (localName
== nsGkAtoms::name
) {
819 else if (localName
== nsGkAtoms::readonly
) {
822 else if (localName
== nsGkAtoms::onget
) {
825 else if (localName
== nsGkAtoms::onset
) {
831 // All of our pointers are now filled in. Construct our property with all of
833 mProperty
= new nsXBLProtoImplProperty(name
, onget
, onset
, readonly
);
835 AddMember(mProperty
);
841 nsXBLContentSink::ConstructMethod(const PRUnichar
**aAtts
)
845 const PRUnichar
* name
= nsnull
;
846 if (FindValue(aAtts
, nsGkAtoms::name
, &name
)) {
847 mMethod
= new nsXBLProtoImplMethod(name
);
856 nsXBLContentSink::ConstructParameter(const PRUnichar
**aAtts
)
861 const PRUnichar
* name
= nsnull
;
862 if (FindValue(aAtts
, nsGkAtoms::name
, &name
)) {
863 mMethod
->AddParameter(nsDependentString(name
));
868 nsXBLContentSink::CreateElement(const PRUnichar
** aAtts
, PRUint32 aAttsCount
,
869 nsINodeInfo
* aNodeInfo
, PRUint32 aLineNumber
,
870 nsIContent
** aResult
, PRBool
* aAppendContent
,
874 if (!aNodeInfo
->NamespaceEquals(kNameSpaceID_XUL
)) {
876 return nsXMLContentSink::CreateElement(aAtts
, aAttsCount
, aNodeInfo
,
877 aLineNumber
, aResult
,
878 aAppendContent
, aFromParser
);
882 *aAppendContent
= PR_TRUE
;
883 nsRefPtr
<nsXULPrototypeElement
> prototype
= new nsXULPrototypeElement();
885 return NS_ERROR_OUT_OF_MEMORY
;
887 prototype
->mNodeInfo
= aNodeInfo
;
888 // XXX - we need to do exactly what the XUL content-sink does (eg,
889 // look for 'type', 'version' etc attributes)
890 prototype
->mScriptTypeID
= nsIProgrammingLanguage::JAVASCRIPT
;
892 AddAttributesToXULPrototype(aAtts
, aAttsCount
, prototype
);
894 return nsXULElement::Create(prototype
, mDocument
, PR_FALSE
, aResult
);
899 nsXBLContentSink::AddAttributes(const PRUnichar
** aAtts
,
900 nsIContent
* aContent
)
902 if (aContent
->IsNodeOfType(nsINode::eXUL
))
903 return NS_OK
; // Nothing to do, since the proto already has the attrs.
905 return nsXMLContentSink::AddAttributes(aAtts
, aContent
);
910 nsXBLContentSink::AddAttributesToXULPrototype(const PRUnichar
**aAtts
,
912 nsXULPrototypeElement
* aElement
)
914 // Add tag attributes to the element
917 // Create storage for the attributes
918 nsXULPrototypeAttribute
* attrs
= nsnull
;
919 if (aAttsCount
> 0) {
920 attrs
= new nsXULPrototypeAttribute
[aAttsCount
];
922 return NS_ERROR_OUT_OF_MEMORY
;
925 aElement
->mAttributes
= attrs
;
926 aElement
->mNumAttributes
= aAttsCount
;
928 // Copy the attributes into the prototype
929 nsCOMPtr
<nsIAtom
> prefix
, localName
;
932 for (i
= 0; i
< aAttsCount
; ++i
) {
934 nsContentUtils::SplitExpatName(aAtts
[i
* 2], getter_AddRefs(prefix
),
935 getter_AddRefs(localName
), &nameSpaceID
);
937 if (nameSpaceID
== kNameSpaceID_None
) {
938 attrs
[i
].mName
.SetTo(localName
);
941 nsCOMPtr
<nsINodeInfo
> ni
;
942 ni
= mNodeInfoManager
->GetNodeInfo(localName
, prefix
, nameSpaceID
);
943 attrs
[i
].mName
.SetTo(ni
);
946 rv
= aElement
->SetAttrAt(i
, nsDependentString(aAtts
[i
* 2 + 1]),
948 NS_ENSURE_SUCCESS(rv
, rv
);