Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / content / xbl / src / nsXBLContentSink.cpp
blob7209b3102b365b3a8489e0efcd6b751907e2e031
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
13 * License.
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.
22 * Contributor(s):
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"
47 #include "nsIURI.h"
48 #include "nsTextFragment.h"
49 #ifdef MOZ_XUL
50 #include "nsXULElement.h"
51 #endif
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"
63 nsresult
64 NS_NewXBLContentSink(nsIXMLContentSink** aResult,
65 nsIDocument* aDoc,
66 nsIURI* aURI,
67 nsISupports* aContainer)
69 NS_ENSURE_ARG_POINTER(aResult);
71 nsXBLContentSink* it;
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),
85 mDocInfo(nsnull),
86 mIsChromeOrResource(PR_FALSE),
87 mFoundFirstBinding(PR_FALSE),
88 mBinding(nsnull),
89 mHandler(nsnull),
90 mImplementation(nsnull),
91 mImplMember(nsnull),
92 mImplField(nsnull),
93 mProperty(nsnull),
94 mMethod(nsnull),
95 mField(nsnull)
97 mPrettyPrintXML = PR_FALSE;
100 nsXBLContentSink::~nsXBLContentSink()
104 nsresult
105 nsXBLContentSink::Init(nsIDocument* aDoc,
106 nsIURI* aURI,
107 nsISupports* aContainer)
109 nsresult rv;
110 rv = nsXMLContentSink::Init(aDoc, aURI, aContainer, nsnull);
111 return rv;
114 void
115 nsXBLContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets)
117 return;
120 nsresult
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);
130 mTextLength = 0;
131 return NS_OK;
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();
141 else
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);
152 else
153 mProperty->AppendSetterText(text);
155 else if (mSecondaryState == eXBL_InBody) {
156 // Get the text and add it to the method
157 if (mMethod)
158 mMethod->AppendBodyText(text);
160 else if (mSecondaryState == eXBL_InField) {
161 // Get the text and add it to the method
162 if (mField)
163 mField->AppendFieldText(text);
165 mTextLength = 0;
166 return NS_OK;
169 nsIContent* content = GetCurrentContent();
170 if (content &&
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;
180 while (cp < end) {
181 PRUnichar ch = *cp++;
182 if (!XP_IS_SPACE(ch)) {
183 isWS = PR_FALSE;
184 break;
189 if (isWS && mTextLength > 0) {
190 mTextLength = 0;
191 // Make sure to drop the textnode, if any
192 return nsXMLContentSink::FlushText(aReleaseTextNode);
197 return nsXMLContentSink::FlushText(aReleaseTextNode);
200 NS_IMETHODIMP
201 nsXBLContentSink::ReportError(const PRUnichar* aErrorText,
202 const PRUnichar* aSourceText,
203 nsIScriptError *aError,
204 PRBool *_retval)
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
214 // binding.
216 #ifdef DEBUG
217 // Report the error to stderr.
218 fprintf(stderr,
219 "\n%s\n%s\n\n",
220 NS_LossyConvertUTF16toASCII(aErrorText).get(),
221 NS_LossyConvertUTF16toASCII(aSourceText).get());
222 #endif
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,
227 aSourceText,
228 aError,
229 _retval);
232 nsresult
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
238 // we do...
239 mState = eXBL_Error;
240 nsAutoString elementName;
241 aElementName->ToString(elementName);
243 const PRUnichar* params[] = { elementName.get() };
245 return nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES,
246 "UnexpectedElement",
247 params, NS_ARRAY_LENGTH(params),
248 mDocumentURI,
249 EmptyString() /* source line */,
250 aLineNumber, 0 /* column number */,
251 nsIScriptError::errorFlag,
252 "XBL Content Sink");
255 void
256 nsXBLContentSink::AddMember(nsXBLProtoImplMember* aMember)
258 // Add this member to our chain.
259 if (mImplMember)
260 mImplMember->SetNext(aMember); // Already have a chain. Just append to the end.
261 else
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.
267 void
268 nsXBLContentSink::AddField(nsXBLProtoImplField* aField)
270 // Add this field to our chain.
271 if (mImplField)
272 mImplField->SetNext(aField); // Already have a chain. Just append to the end.
273 else
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.
279 NS_IMETHODIMP
280 nsXBLContentSink::HandleStartElement(const PRUnichar *aName,
281 const PRUnichar **aAtts,
282 PRUint32 aAttsCount,
283 PRInt32 aIndex,
284 PRUint32 aLineNumber)
286 nsresult rv = nsXMLContentSink::HandleStartElement(aName,aAtts,aAttsCount,aIndex,aLineNumber);
287 if (NS_FAILED(rv))
288 return rv;
290 if (mState == eXBL_InBinding && !mBinding) {
291 rv = ConstructBinding();
292 if (NS_FAILED(rv))
293 return rv;
295 // mBinding may still be null, if the binding had no id. If so,
296 // we'll deal with that later in the sink.
299 return rv;
302 NS_IMETHODIMP
303 nsXBLContentSink::HandleEndElement(const PRUnichar *aName)
305 FlushText();
307 if (mState != eXBL_InDocument) {
308 PRInt32 nameSpaceID;
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,
318 nameSpaceID)) {
319 // OK, this tag was never opened as far as the XML sink is
320 // concerned. Just drop the HandleEndElement
321 return NS_OK;
324 else if (mState == eXBL_InHandlers) {
325 if (localName == nsGkAtoms::handlers) {
326 mState = eXBL_InBinding;
327 mHandler = nsnull;
329 else if (localName == nsGkAtoms::handler)
330 mSecondaryState = eXBL_None;
331 return NS_OK;
333 else if (mState == eXBL_InResources) {
334 if (localName == nsGkAtoms::resources)
335 mState = eXBL_InBinding;
336 return NS_OK;
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;
343 mProperty = nsnull;
345 else if (localName == nsGkAtoms::method) {
346 mSecondaryState = eXBL_None;
347 mMethod = nsnull;
349 else if (localName == nsGkAtoms::field) {
350 mSecondaryState = eXBL_None;
351 mField = nsnull;
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;
362 return NS_OK;
364 else if (mState == eXBL_InBindings &&
365 localName == nsGkAtoms::bindings) {
366 mState = eXBL_InDocument;
369 nsresult rv = nsXMLContentSink::HandleEndElement(aName);
370 if (NS_FAILED(rv))
371 return rv;
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.
381 return NS_OK;
385 return nsXMLContentSink::HandleEndElement(aName);
388 NS_IMETHODIMP
389 nsXBLContentSink::HandleCDataSection(const PRUnichar *aData,
390 PRUint32 aLength)
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) \
398 PR_BEGIN_MACRO \
399 if (!(_cond)) { ReportUnexpectedElement(aTagName, aLineNumber); return PR_TRUE; } \
400 PR_END_MACRO
402 PRBool
403 nsXBLContentSink::OnOpenContainer(const PRUnichar **aAtts,
404 PRUint32 aAttsCount,
405 PRInt32 aNameSpaceID,
406 nsIAtom* aTagName,
407 PRUint32 aLineNumber)
409 if (mState == eXBL_Error) {
410 return PR_TRUE;
413 if (aNameSpaceID != kNameSpaceID_XBL) {
414 // Construct non-XBL nodes
415 return PR_TRUE;
418 PRBool ret = PR_TRUE;
419 if (aTagName == nsGkAtoms::bindings) {
420 ENSURE_XBL_STATE(mState == eXBL_InDocument);
422 NS_NewXBLDocumentInfo(mDocument, &mDocInfo);
423 if (!mDocInfo) {
424 mState = eXBL_Error;
425 return PR_TRUE;
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;
450 ret = PR_FALSE;
452 else if (aTagName == nsGkAtoms::handler) {
453 ENSURE_XBL_STATE(mState == eXBL_InHandlers);
454 mSecondaryState = eXBL_InHandler;
455 ConstructHandler(aAtts, aLineNumber);
456 ret = PR_FALSE;
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();
484 if (newMethod) {
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();
497 if (newMethod) {
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
554 nsresult
555 nsXBLContentSink::ConstructBinding()
557 nsCOMPtr<nsIContent> binding = GetCurrentContent();
558 nsAutoString id;
559 binding->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
560 NS_ConvertUTF16toUTF8 cid(id);
562 nsresult rv = NS_OK;
564 if (!cid.IsEmpty()) {
565 mBinding = new nsXBLPrototypeBinding();
566 if (!mBinding)
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);
577 } else {
578 delete mBinding;
579 mBinding = nsnull;
583 return rv;
586 static PRBool
587 FindValue(const PRUnichar **aAtts, nsIAtom *aAtom, const PRUnichar **aResult)
589 nsCOMPtr<nsIAtom> prefix, localName;
590 for (; *aAtts; aAtts += 2) {
591 PRInt32 nameSpaceID;
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) {
597 *aResult = aAtts[1];
599 return PR_TRUE;
603 return PR_FALSE;
606 void
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) {
624 PRInt32 nameSpaceID;
625 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
626 getter_AddRefs(localName), &nameSpaceID);
628 if (nameSpaceID != kNameSpaceID_None) {
629 continue;
632 // Is this attribute one of the ones we care about?
633 if (localName == nsGkAtoms::event)
634 event = aAtts[1];
635 else if (localName == nsGkAtoms::modifiers)
636 modifiers = aAtts[1];
637 else if (localName == nsGkAtoms::button)
638 button = aAtts[1];
639 else if (localName == nsGkAtoms::clickcount)
640 clickcount = aAtts[1];
641 else if (localName == nsGkAtoms::keycode)
642 keycode = aAtts[1];
643 else if (localName == nsGkAtoms::key || localName == nsGkAtoms::charcode)
644 charcode = aAtts[1];
645 else if (localName == nsGkAtoms::phase)
646 phase = aAtts[1];
647 else if (localName == nsGkAtoms::command)
648 command = aAtts[1];
649 else if (localName == nsGkAtoms::action)
650 action = aAtts[1];
651 else if (localName == nsGkAtoms::group)
652 group = aAtts[1];
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
661 // shorthand syntax.
662 mState = eXBL_Error;
663 nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES,
664 "CommandNotInChrome", nsnull, 0,
665 mDocumentURI,
666 EmptyString() /* source line */,
667 aLineNumber, 0 /* column number */,
668 nsIScriptError::errorFlag,
669 "XBL Content Sink");
670 return; // Don't even make this handler.
673 // All of our pointers are now filled in. Construct our handler with all of
674 // these parameters.
675 nsXBLPrototypeHandler* newHandler;
676 newHandler = new nsXBLPrototypeHandler(event, phase, action, command,
677 keycode, charcode, modifiers, button,
678 clickcount, group, preventdefault,
679 allowuntrusted, mBinding, aLineNumber);
681 if (newHandler) {
682 // Add this handler to our chain of handlers.
683 if (mHandler) {
684 // Already have a chain. Just append to the end.
685 mHandler->SetNextHandler(newHandler);
687 else {
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
692 // chain.
693 mHandler = newHandler;
694 } else {
695 mState = eXBL_Error;
699 void
700 nsXBLContentSink::ConstructResource(const PRUnichar **aAtts,
701 nsIAtom* aResourceType)
703 if (!mBinding)
704 return;
706 const PRUnichar* src = nsnull;
707 if (FindValue(aAtts, nsGkAtoms::src, &src)) {
708 mBinding->AddResource(aResourceType, nsDependentString(src));
712 void
713 nsXBLContentSink::ConstructImplementation(const PRUnichar **aAtts)
715 mImplementation = nsnull;
716 mImplMember = nsnull;
717 mImplField = nsnull;
719 if (!mBinding)
720 return;
722 const PRUnichar* name = nsnull;
724 nsCOMPtr<nsIAtom> prefix, localName;
725 for (; *aAtts; aAtts += 2) {
726 PRInt32 nameSpaceID;
727 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
728 getter_AddRefs(localName), &nameSpaceID);
730 if (nameSpaceID != kNameSpaceID_None) {
731 continue;
734 // Is this attribute one of the ones we care about?
735 if (localName == nsGkAtoms::name) {
736 name = aAtts[1];
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
741 // means no privs!
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);
761 void
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) {
769 PRInt32 nameSpaceID;
770 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
771 getter_AddRefs(localName), &nameSpaceID);
773 if (nameSpaceID != kNameSpaceID_None) {
774 continue;
777 // Is this attribute one of the ones we care about?
778 if (localName == nsGkAtoms::name) {
779 name = aAtts[1];
781 else if (localName == nsGkAtoms::readonly) {
782 readonly = aAtts[1];
786 if (name) {
787 // All of our pointers are now filled in. Construct our field with all of
788 // these parameters.
789 mField = new nsXBLProtoImplField(name, readonly);
790 if (mField) {
791 mField->SetLineNumber(aLineNumber);
792 AddField(mField);
797 void
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) {
807 PRInt32 nameSpaceID;
808 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
809 getter_AddRefs(localName), &nameSpaceID);
811 if (nameSpaceID != kNameSpaceID_None) {
812 continue;
815 // Is this attribute one of the ones we care about?
816 if (localName == nsGkAtoms::name) {
817 name = aAtts[1];
819 else if (localName == nsGkAtoms::readonly) {
820 readonly = aAtts[1];
822 else if (localName == nsGkAtoms::onget) {
823 onget = aAtts[1];
825 else if (localName == nsGkAtoms::onset) {
826 onset = aAtts[1];
830 if (name) {
831 // All of our pointers are now filled in. Construct our property with all of
832 // these parameters.
833 mProperty = new nsXBLProtoImplProperty(name, onget, onset, readonly);
834 if (mProperty) {
835 AddMember(mProperty);
840 void
841 nsXBLContentSink::ConstructMethod(const PRUnichar **aAtts)
843 mMethod = nsnull;
845 const PRUnichar* name = nsnull;
846 if (FindValue(aAtts, nsGkAtoms::name, &name)) {
847 mMethod = new nsXBLProtoImplMethod(name);
850 if (mMethod) {
851 AddMember(mMethod);
855 void
856 nsXBLContentSink::ConstructParameter(const PRUnichar **aAtts)
858 if (!mMethod)
859 return;
861 const PRUnichar* name = nsnull;
862 if (FindValue(aAtts, nsGkAtoms::name, &name)) {
863 mMethod->AddParameter(nsDependentString(name));
867 nsresult
868 nsXBLContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
869 nsINodeInfo* aNodeInfo, PRUint32 aLineNumber,
870 nsIContent** aResult, PRBool* aAppendContent,
871 PRBool aFromParser)
873 #ifdef MOZ_XUL
874 if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
875 #endif
876 return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo,
877 aLineNumber, aResult,
878 aAppendContent, aFromParser);
879 #ifdef MOZ_XUL
882 *aAppendContent = PR_TRUE;
883 nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
884 if (!prototype)
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);
895 #endif
898 nsresult
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);
908 #ifdef MOZ_XUL
909 nsresult
910 nsXBLContentSink::AddAttributesToXULPrototype(const PRUnichar **aAtts,
911 PRUint32 aAttsCount,
912 nsXULPrototypeElement* aElement)
914 // Add tag attributes to the element
915 nsresult rv;
917 // Create storage for the attributes
918 nsXULPrototypeAttribute* attrs = nsnull;
919 if (aAttsCount > 0) {
920 attrs = new nsXULPrototypeAttribute[aAttsCount];
921 if (!attrs)
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;
931 PRUint32 i;
932 for (i = 0; i < aAttsCount; ++i) {
933 PRInt32 nameSpaceID;
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);
940 else {
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]),
947 mDocumentURI);
948 NS_ENSURE_SUCCESS(rv, rv);
951 return NS_OK;
953 #endif