Bumping manifests a=b2g-bump
[gecko.git] / dom / xbl / nsXBLContentSink.cpp
blob03934610a6306fbec379f2a9a0aa32554d1fa6c0
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"
14 #include "nsIURI.h"
15 #include "nsTextFragment.h"
16 #ifdef MOZ_XUL
17 #include "nsXULElement.h"
18 #endif
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;
33 nsresult
34 NS_NewXBLContentSink(nsIXMLContentSink** aResult,
35 nsIDocument* aDoc,
36 nsIURI* aURI,
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),
54 mDocInfo(nullptr),
55 mIsChromeOrResource(false),
56 mFoundFirstBinding(false),
57 mBinding(nullptr),
58 mHandler(nullptr),
59 mImplementation(nullptr),
60 mImplMember(nullptr),
61 mImplField(nullptr),
62 mProperty(nullptr),
63 mMethod(nullptr),
64 mField(nullptr)
66 mPrettyPrintXML = false;
69 nsXBLContentSink::~nsXBLContentSink()
73 nsresult
74 nsXBLContentSink::Init(nsIDocument* aDoc,
75 nsIURI* aURI,
76 nsISupports* aContainer)
78 nsresult rv;
79 rv = nsXMLContentSink::Init(aDoc, aURI, aContainer, nullptr);
80 return rv;
83 void
84 nsXBLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
86 return;
89 nsresult
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);
99 mTextLength = 0;
100 return NS_OK;
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();
110 else
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);
121 else
122 mProperty->AppendSetterText(text);
124 else if (mSecondaryState == eXBL_InBody) {
125 // Get the text and add it to the method
126 if (mMethod)
127 mMethod->AppendBodyText(text);
129 else if (mSecondaryState == eXBL_InField) {
130 // Get the text and add it to the method
131 if (mField)
132 mField->AppendFieldText(text);
134 mTextLength = 0;
135 return NS_OK;
138 nsIContent* content = GetCurrentContent();
139 if (content &&
140 (content->NodeInfo()->NamespaceEquals(kNameSpaceID_XBL) ||
141 (content->NodeInfo()->NamespaceEquals(kNameSpaceID_XUL) &&
142 content->Tag() != nsGkAtoms::label &&
143 content->Tag() != nsGkAtoms::description))) {
145 bool isWS = true;
146 if (mTextLength > 0) {
147 const char16_t* cp = mText;
148 const char16_t* end = mText + mTextLength;
149 while (cp < end) {
150 char16_t ch = *cp++;
151 if (!dom::IsSpaceCharacter(ch)) {
152 isWS = false;
153 break;
158 if (isWS && mTextLength > 0) {
159 mTextLength = 0;
160 // Make sure to drop the textnode, if any
161 return nsXMLContentSink::FlushText(aReleaseTextNode);
166 return nsXMLContentSink::FlushText(aReleaseTextNode);
169 NS_IMETHODIMP
170 nsXBLContentSink::ReportError(const char16_t* aErrorText,
171 const char16_t* aSourceText,
172 nsIScriptError *aError,
173 bool *_retval)
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
183 // binding.
185 #ifdef DEBUG
186 // Report the error to stderr.
187 fprintf(stderr,
188 "\n%s\n%s\n\n",
189 NS_LossyConvertUTF16toASCII(aErrorText).get(),
190 NS_LossyConvertUTF16toASCII(aSourceText).get());
191 #endif
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,
196 aSourceText,
197 aError,
198 _retval);
201 nsresult
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
207 // we do...
208 mState = eXBL_Error;
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"),
216 mDocument,
217 nsContentUtils::eXBL_PROPERTIES,
218 "UnexpectedElement",
219 params, ArrayLength(params),
220 nullptr,
221 EmptyString() /* source line */,
222 aLineNumber);
225 void
226 nsXBLContentSink::AddMember(nsXBLProtoImplMember* aMember)
228 // Add this member to our chain.
229 if (mImplMember)
230 mImplMember->SetNext(aMember); // Already have a chain. Just append to the end.
231 else
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.
237 void
238 nsXBLContentSink::AddField(nsXBLProtoImplField* aField)
240 // Add this field to our chain.
241 if (mImplField)
242 mImplField->SetNext(aField); // Already have a chain. Just append to the end.
243 else
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.
249 NS_IMETHODIMP
250 nsXBLContentSink::HandleStartElement(const char16_t *aName,
251 const char16_t **aAtts,
252 uint32_t aAttsCount,
253 uint32_t aLineNumber)
255 nsresult rv = nsXMLContentSink::HandleStartElement(aName, aAtts, aAttsCount,
256 aLineNumber);
257 if (NS_FAILED(rv))
258 return rv;
260 if (mState == eXBL_InBinding && !mBinding) {
261 rv = ConstructBinding(aLineNumber);
262 if (NS_FAILED(rv))
263 return rv;
265 // mBinding may still be null, if the binding had no id. If so,
266 // we'll deal with that later in the sink.
269 return rv;
272 NS_IMETHODIMP
273 nsXBLContentSink::HandleEndElement(const char16_t *aName)
275 FlushText();
277 if (mState != eXBL_InDocument) {
278 int32_t nameSpaceID;
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,
288 nameSpaceID)) {
289 // OK, this tag was never opened as far as the XML sink is
290 // concerned. Just drop the HandleEndElement
291 return NS_OK;
294 else if (mState == eXBL_InHandlers) {
295 if (localName == nsGkAtoms::handlers) {
296 mState = eXBL_InBinding;
297 mHandler = nullptr;
299 else if (localName == nsGkAtoms::handler)
300 mSecondaryState = eXBL_None;
301 return NS_OK;
303 else if (mState == eXBL_InResources) {
304 if (localName == nsGkAtoms::resources)
305 mState = eXBL_InBinding;
306 return NS_OK;
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;
313 mProperty = nullptr;
315 else if (localName == nsGkAtoms::method) {
316 mSecondaryState = eXBL_None;
317 mMethod = nullptr;
319 else if (localName == nsGkAtoms::field) {
320 mSecondaryState = eXBL_None;
321 mField = nullptr;
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;
332 return NS_OK;
334 else if (mState == eXBL_InBindings &&
335 localName == nsGkAtoms::bindings) {
336 mState = eXBL_InDocument;
339 nsresult rv = nsXMLContentSink::HandleEndElement(aName);
340 if (NS_FAILED(rv))
341 return rv;
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.
351 return NS_OK;
355 return nsXMLContentSink::HandleEndElement(aName);
358 NS_IMETHODIMP
359 nsXBLContentSink::HandleCDataSection(const char16_t *aData,
360 uint32_t aLength)
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) \
368 PR_BEGIN_MACRO \
369 if (!(_cond)) { ReportUnexpectedElement(aTagName, aLineNumber); return true; } \
370 PR_END_MACRO
372 bool
373 nsXBLContentSink::OnOpenContainer(const char16_t **aAtts,
374 uint32_t aAttsCount,
375 int32_t aNameSpaceID,
376 nsIAtom* aTagName,
377 uint32_t aLineNumber)
379 if (mState == eXBL_Error) {
380 return true;
383 if (aNameSpaceID != kNameSpaceID_XBL) {
384 // Construct non-XBL nodes
385 return true;
388 bool ret = true;
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.
396 mDocInfo = info;
398 if (!mDocInfo) {
399 mState = eXBL_Error;
400 return true;
403 mDocument->BindingManager()->PutXBLDocumentInfo(mDocInfo);
405 nsIURI *uri = mDocument->GetDocumentURI();
407 bool isChrome = false;
408 bool isRes = 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;
423 ret = false;
425 else if (aTagName == nsGkAtoms::handler) {
426 ENSURE_XBL_STATE(mState == eXBL_InHandlers);
427 mSecondaryState = eXBL_InHandler;
428 ConstructHandler(aAtts, aLineNumber);
429 ret = false;
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;
455 nsAutoString name;
456 if (!mCurrentBindingID.IsEmpty()) {
457 name.Assign(mCurrentBindingID);
458 name.AppendLiteral("_XBL_Constructor");
459 } else {
460 name.AppendLiteral("XBL_Constructor");
462 nsXBLProtoImplAnonymousMethod* newMethod =
463 new nsXBLProtoImplAnonymousMethod(name.get());
464 if (newMethod) {
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;
475 nsAutoString name;
476 if (!mCurrentBindingID.IsEmpty()) {
477 name.Assign(mCurrentBindingID);
478 name.AppendLiteral("_XBL_Destructor");
479 } else {
480 name.AppendLiteral("XBL_Destructor");
482 nsXBLProtoImplAnonymousMethod* newMethod =
483 new nsXBLProtoImplAnonymousMethod(name.get());
484 if (newMethod) {
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
541 nsresult
542 nsXBLContentSink::ConstructBinding(uint32_t aLineNumber)
544 nsCOMPtr<nsIContent> binding = GetCurrentContent();
545 binding->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mCurrentBindingID);
546 NS_ConvertUTF16toUTF8 cid(mCurrentBindingID);
548 nsresult rv = NS_OK;
550 // Don't create a binding with no id. nsXBLPrototypeBinding::Read also
551 // performs this check.
552 if (!cid.IsEmpty()) {
553 mBinding = new nsXBLPrototypeBinding();
554 if (!mBinding)
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);
565 } else {
566 delete mBinding;
567 mBinding = nullptr;
569 } else {
570 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
571 NS_LITERAL_CSTRING("XBL Content Sink"), nullptr,
572 nsContentUtils::eXBL_PROPERTIES,
573 "MissingIdAttr", nullptr, 0,
574 mDocumentURI,
575 EmptyString(),
576 aLineNumber);
579 return rv;
582 static bool
583 FindValue(const char16_t **aAtts, nsIAtom *aAtom, const char16_t **aResult)
585 nsCOMPtr<nsIAtom> prefix, localName;
586 for (; *aAtts; aAtts += 2) {
587 int32_t nameSpaceID;
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) {
593 *aResult = aAtts[1];
595 return true;
599 return false;
602 void
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) {
620 int32_t nameSpaceID;
621 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
622 getter_AddRefs(localName), &nameSpaceID);
624 if (nameSpaceID != kNameSpaceID_None) {
625 continue;
628 // Is this attribute one of the ones we care about?
629 if (localName == nsGkAtoms::event)
630 event = aAtts[1];
631 else if (localName == nsGkAtoms::modifiers)
632 modifiers = aAtts[1];
633 else if (localName == nsGkAtoms::button)
634 button = aAtts[1];
635 else if (localName == nsGkAtoms::clickcount)
636 clickcount = aAtts[1];
637 else if (localName == nsGkAtoms::keycode)
638 keycode = aAtts[1];
639 else if (localName == nsGkAtoms::key || localName == nsGkAtoms::charcode)
640 charcode = aAtts[1];
641 else if (localName == nsGkAtoms::phase)
642 phase = aAtts[1];
643 else if (localName == nsGkAtoms::command)
644 command = aAtts[1];
645 else if (localName == nsGkAtoms::action)
646 action = aAtts[1];
647 else if (localName == nsGkAtoms::group)
648 group = aAtts[1];
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
657 // shorthand syntax.
658 mState = eXBL_Error;
659 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
660 NS_LITERAL_CSTRING("XBL Content Sink"),
661 mDocument,
662 nsContentUtils::eXBL_PROPERTIES,
663 "CommandNotInChrome", nullptr, 0,
664 nullptr,
665 EmptyString() /* source line */,
666 aLineNumber);
667 return; // Don't even make this handler.
670 // All of our pointers are now filled in. Construct our handler with all of
671 // these parameters.
672 nsXBLPrototypeHandler* newHandler;
673 newHandler = new nsXBLPrototypeHandler(event, phase, action, command,
674 keycode, charcode, modifiers, button,
675 clickcount, group, preventdefault,
676 allowuntrusted, mBinding, aLineNumber);
678 if (newHandler) {
679 // Add this handler to our chain of handlers.
680 if (mHandler) {
681 // Already have a chain. Just append to the end.
682 mHandler->SetNextHandler(newHandler);
684 else {
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
689 // chain.
690 mHandler = newHandler;
691 } else {
692 mState = eXBL_Error;
696 void
697 nsXBLContentSink::ConstructResource(const char16_t **aAtts,
698 nsIAtom* aResourceType)
700 if (!mBinding)
701 return;
703 const char16_t* src = nullptr;
704 if (FindValue(aAtts, nsGkAtoms::src, &src)) {
705 mBinding->AddResource(aResourceType, nsDependentString(src));
709 void
710 nsXBLContentSink::ConstructImplementation(const char16_t **aAtts)
712 mImplementation = nullptr;
713 mImplMember = nullptr;
714 mImplField = nullptr;
716 if (!mBinding)
717 return;
719 const char16_t* name = nullptr;
721 nsCOMPtr<nsIAtom> prefix, localName;
722 for (; *aAtts; aAtts += 2) {
723 int32_t nameSpaceID;
724 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
725 getter_AddRefs(localName), &nameSpaceID);
727 if (nameSpaceID != kNameSpaceID_None) {
728 continue;
731 // Is this attribute one of the ones we care about?
732 if (localName == nsGkAtoms::name) {
733 name = aAtts[1];
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);
747 void
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) {
755 int32_t nameSpaceID;
756 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
757 getter_AddRefs(localName), &nameSpaceID);
759 if (nameSpaceID != kNameSpaceID_None) {
760 continue;
763 // Is this attribute one of the ones we care about?
764 if (localName == nsGkAtoms::name) {
765 name = aAtts[1];
767 else if (localName == nsGkAtoms::readonly) {
768 readonly = aAtts[1];
772 if (name) {
773 // All of our pointers are now filled in. Construct our field with all of
774 // these parameters.
775 mField = new nsXBLProtoImplField(name, readonly);
776 if (mField) {
777 mField->SetLineNumber(aLineNumber);
778 AddField(mField);
783 void
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) {
794 int32_t nameSpaceID;
795 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
796 getter_AddRefs(localName), &nameSpaceID);
798 if (nameSpaceID != kNameSpaceID_None) {
799 continue;
802 // Is this attribute one of the ones we care about?
803 if (localName == nsGkAtoms::name) {
804 name = aAtts[1];
806 else if (localName == nsGkAtoms::readonly) {
807 readonly = aAtts[1];
809 else if (localName == nsGkAtoms::onget) {
810 onget = aAtts[1];
812 else if (localName == nsGkAtoms::onset) {
813 onset = aAtts[1];
815 else if (localName == nsGkAtoms::exposeToUntrustedContent &&
816 nsDependentString(aAtts[1]).EqualsLiteral("true"))
818 exposeToUntrustedContent = true;
822 if (name) {
823 // All of our pointers are now filled in. Construct our property with all of
824 // these parameters.
825 mProperty = new nsXBLProtoImplProperty(name, onget, onset, readonly, aLineNumber);
826 if (exposeToUntrustedContent) {
827 mProperty->SetExposeToUntrustedContent(true);
829 AddMember(mProperty);
833 void
834 nsXBLContentSink::ConstructMethod(const char16_t **aAtts)
836 mMethod = nullptr;
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);
849 if (mMethod) {
850 AddMember(mMethod);
854 void
855 nsXBLContentSink::ConstructParameter(const char16_t **aAtts)
857 if (!mMethod)
858 return;
860 const char16_t* name = nullptr;
861 if (FindValue(aAtts, nsGkAtoms::name, &name)) {
862 mMethod->AddParameter(nsDependentString(name));
866 nsresult
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)
872 #ifdef MOZ_XUL
873 if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
874 #endif
875 return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo,
876 aLineNumber, aResult,
877 aAppendContent, aFromParser);
878 #ifdef MOZ_XUL
881 // Note that this needs to match the code in nsXBLPrototypeBinding::ReadContentNode.
883 *aAppendContent = true;
884 nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
885 if (!prototype)
886 return NS_ERROR_OUT_OF_MEMORY;
888 prototype->mNodeInfo = aNodeInfo;
890 AddAttributesToXULPrototype(aAtts, aAttsCount, prototype);
892 Element* result;
893 nsresult rv = nsXULElement::Create(prototype, mDocument, false, false, &result);
894 *aResult = result;
895 return rv;
896 #endif
899 nsresult
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);
909 #ifdef MOZ_XUL
910 nsresult
911 nsXBLContentSink::AddAttributesToXULPrototype(const char16_t **aAtts,
912 uint32_t aAttsCount,
913 nsXULPrototypeElement* aElement)
915 // Add tag attributes to the element
916 nsresult rv;
918 // Create storage for the attributes
919 nsXULPrototypeAttribute* attrs = nullptr;
920 if (aAttsCount > 0) {
921 attrs = new nsXULPrototypeAttribute[aAttsCount];
922 if (!attrs)
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;
932 uint32_t i;
933 for (i = 0; i < aAttsCount; ++i) {
934 int32_t nameSpaceID;
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);
941 else {
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]),
949 mDocumentURI);
950 NS_ENSURE_SUCCESS(rv, rv);
953 return NS_OK;
955 #endif