summaryrefslogtreecommitdiffstats
path: root/dom/xbl/nsXBLContentSink.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /dom/xbl/nsXBLContentSink.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/xbl/nsXBLContentSink.cpp')
-rw-r--r--dom/xbl/nsXBLContentSink.cpp937
1 files changed, 937 insertions, 0 deletions
diff --git a/dom/xbl/nsXBLContentSink.cpp b/dom/xbl/nsXBLContentSink.cpp
new file mode 100644
index 000000000..4d5c9fb74
--- /dev/null
+++ b/dom/xbl/nsXBLContentSink.cpp
@@ -0,0 +1,937 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ArrayUtils.h"
+
+#include "nsXBLContentSink.h"
+#include "nsIDocument.h"
+#include "nsBindingManager.h"
+#include "nsIDOMNode.h"
+#include "nsGkAtoms.h"
+#include "nsNameSpaceManager.h"
+#include "nsIURI.h"
+#include "nsTextFragment.h"
+#ifdef MOZ_XUL
+#include "nsXULElement.h"
+#endif
+#include "nsXBLProtoImplProperty.h"
+#include "nsXBLProtoImplMethod.h"
+#include "nsXBLProtoImplField.h"
+#include "nsXBLPrototypeBinding.h"
+#include "nsContentUtils.h"
+#include "nsIConsoleService.h"
+#include "nsIScriptError.h"
+#include "nsNodeInfoManager.h"
+#include "nsIPrincipal.h"
+#include "mozilla/dom/Element.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+nsresult
+NS_NewXBLContentSink(nsIXMLContentSink** aResult,
+ nsIDocument* aDoc,
+ nsIURI* aURI,
+ nsISupports* aContainer)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ RefPtr<nsXBLContentSink> it = new nsXBLContentSink();
+ nsresult rv = it->Init(aDoc, aURI, aContainer);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ it.forget(aResult);
+ return NS_OK;
+}
+
+nsXBLContentSink::nsXBLContentSink()
+ : mState(eXBL_InDocument),
+ mSecondaryState(eXBL_None),
+ mDocInfo(nullptr),
+ mIsChromeOrResource(false),
+ mFoundFirstBinding(false),
+ mBinding(nullptr),
+ mHandler(nullptr),
+ mImplementation(nullptr),
+ mImplMember(nullptr),
+ mImplField(nullptr),
+ mProperty(nullptr),
+ mMethod(nullptr),
+ mField(nullptr)
+{
+ mPrettyPrintXML = false;
+}
+
+nsXBLContentSink::~nsXBLContentSink()
+{
+}
+
+nsresult
+nsXBLContentSink::Init(nsIDocument* aDoc,
+ nsIURI* aURI,
+ nsISupports* aContainer)
+{
+ nsresult rv;
+ rv = nsXMLContentSink::Init(aDoc, aURI, aContainer, nullptr);
+ return rv;
+}
+
+void
+nsXBLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
+{
+ return;
+}
+
+nsresult
+nsXBLContentSink::FlushText(bool aReleaseTextNode)
+{
+ if (mTextLength != 0) {
+ const nsASingleFragmentString& text = Substring(mText, mText+mTextLength);
+ if (mState == eXBL_InHandlers) {
+ NS_ASSERTION(mBinding, "Must have binding here");
+ // Get the text and add it to the event handler.
+ if (mSecondaryState == eXBL_InHandler)
+ mHandler->AppendHandlerText(text);
+ mTextLength = 0;
+ return NS_OK;
+ }
+ else if (mState == eXBL_InImplementation) {
+ NS_ASSERTION(mBinding, "Must have binding here");
+ if (mSecondaryState == eXBL_InConstructor ||
+ mSecondaryState == eXBL_InDestructor) {
+ // Construct a method for the constructor/destructor.
+ nsXBLProtoImplMethod* method;
+ if (mSecondaryState == eXBL_InConstructor)
+ method = mBinding->GetConstructor();
+ else
+ method = mBinding->GetDestructor();
+
+ // Get the text and add it to the constructor/destructor.
+ method->AppendBodyText(text);
+ }
+ else if (mSecondaryState == eXBL_InGetter ||
+ mSecondaryState == eXBL_InSetter) {
+ // Get the text and add it to the getter/setter
+ if (mSecondaryState == eXBL_InGetter)
+ mProperty->AppendGetterText(text);
+ else
+ mProperty->AppendSetterText(text);
+ }
+ else if (mSecondaryState == eXBL_InBody) {
+ // Get the text and add it to the method
+ if (mMethod)
+ mMethod->AppendBodyText(text);
+ }
+ else if (mSecondaryState == eXBL_InField) {
+ // Get the text and add it to the method
+ if (mField)
+ mField->AppendFieldText(text);
+ }
+ mTextLength = 0;
+ return NS_OK;
+ }
+
+ nsIContent* content = GetCurrentContent();
+ if (content &&
+ (content->NodeInfo()->NamespaceEquals(kNameSpaceID_XBL) ||
+ (content->IsXULElement() &&
+ !content->IsAnyOfXULElements(nsGkAtoms::label,
+ nsGkAtoms::description)))) {
+
+ bool isWS = true;
+ if (mTextLength > 0) {
+ const char16_t* cp = mText;
+ const char16_t* end = mText + mTextLength;
+ while (cp < end) {
+ char16_t ch = *cp++;
+ if (!dom::IsSpaceCharacter(ch)) {
+ isWS = false;
+ break;
+ }
+ }
+ }
+
+ if (isWS && mTextLength > 0) {
+ mTextLength = 0;
+ // Make sure to drop the textnode, if any
+ return nsXMLContentSink::FlushText(aReleaseTextNode);
+ }
+ }
+ }
+
+ return nsXMLContentSink::FlushText(aReleaseTextNode);
+}
+
+NS_IMETHODIMP
+nsXBLContentSink::ReportError(const char16_t* aErrorText,
+ const char16_t* aSourceText,
+ nsIScriptError *aError,
+ bool *_retval)
+{
+ NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
+
+ // XXX FIXME This function overrides and calls on
+ // nsXMLContentSink::ReportError, and probably should die. See bug 347826.
+
+ // XXX We should make sure the binding has no effect, but that it also
+ // gets destroyed properly without leaking. Perhaps we should even
+ // ensure that the content that was bound is displayed with no
+ // binding.
+
+#ifdef DEBUG
+ // Report the error to stderr.
+ fprintf(stderr,
+ "\n%s\n%s\n\n",
+ NS_LossyConvertUTF16toASCII(aErrorText).get(),
+ NS_LossyConvertUTF16toASCII(aSourceText).get());
+#endif
+
+ // Most of what this does won't be too useful, but whatever...
+ // nsXMLContentSink::ReportError will handle the console logging.
+ return nsXMLContentSink::ReportError(aErrorText,
+ aSourceText,
+ aError,
+ _retval);
+}
+
+nsresult
+nsXBLContentSink::ReportUnexpectedElement(nsIAtom* aElementName,
+ uint32_t aLineNumber)
+{
+ // XXX we should really somehow stop the parse and drop the binding
+ // instead of just letting the XML sink build the content model like
+ // we do...
+ mState = eXBL_Error;
+ nsAutoString elementName;
+ aElementName->ToString(elementName);
+
+ const char16_t* params[] = { elementName.get() };
+
+ return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
+ NS_LITERAL_CSTRING("XBL Content Sink"),
+ mDocument,
+ nsContentUtils::eXBL_PROPERTIES,
+ "UnexpectedElement",
+ params, ArrayLength(params),
+ nullptr,
+ EmptyString() /* source line */,
+ aLineNumber);
+}
+
+void
+nsXBLContentSink::AddMember(nsXBLProtoImplMember* aMember)
+{
+ // Add this member to our chain.
+ if (mImplMember)
+ mImplMember->SetNext(aMember); // Already have a chain. Just append to the end.
+ else
+ mImplementation->SetMemberList(aMember); // We're the first member in the chain.
+
+ mImplMember = aMember; // Adjust our pointer to point to the new last member in the chain.
+}
+
+void
+nsXBLContentSink::AddField(nsXBLProtoImplField* aField)
+{
+ // Add this field to our chain.
+ if (mImplField)
+ mImplField->SetNext(aField); // Already have a chain. Just append to the end.
+ else
+ mImplementation->SetFieldList(aField); // We're the first member in the chain.
+
+ mImplField = aField; // Adjust our pointer to point to the new last field in the chain.
+}
+
+NS_IMETHODIMP
+nsXBLContentSink::HandleStartElement(const char16_t *aName,
+ const char16_t **aAtts,
+ uint32_t aAttsCount,
+ uint32_t aLineNumber)
+{
+ nsresult rv = nsXMLContentSink::HandleStartElement(aName, aAtts, aAttsCount,
+ aLineNumber);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (mState == eXBL_InBinding && !mBinding) {
+ rv = ConstructBinding(aLineNumber);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // mBinding may still be null, if the binding had no id. If so,
+ // we'll deal with that later in the sink.
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsXBLContentSink::HandleEndElement(const char16_t *aName)
+{
+ FlushText();
+
+ if (mState != eXBL_InDocument) {
+ int32_t nameSpaceID;
+ nsCOMPtr<nsIAtom> prefix, localName;
+ nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
+ getter_AddRefs(localName), &nameSpaceID);
+
+ if (nameSpaceID == kNameSpaceID_XBL) {
+ if (mState == eXBL_Error) {
+ // Check whether we've opened this tag before; we may not have if
+ // it was a real XBL tag before the error occurred.
+ if (!GetCurrentContent()->NodeInfo()->Equals(localName,
+ nameSpaceID)) {
+ // OK, this tag was never opened as far as the XML sink is
+ // concerned. Just drop the HandleEndElement
+ return NS_OK;
+ }
+ }
+ else if (mState == eXBL_InHandlers) {
+ if (localName == nsGkAtoms::handlers) {
+ mState = eXBL_InBinding;
+ mHandler = nullptr;
+ }
+ else if (localName == nsGkAtoms::handler)
+ mSecondaryState = eXBL_None;
+ return NS_OK;
+ }
+ else if (mState == eXBL_InResources) {
+ if (localName == nsGkAtoms::resources)
+ mState = eXBL_InBinding;
+ return NS_OK;
+ }
+ else if (mState == eXBL_InImplementation) {
+ if (localName == nsGkAtoms::implementation)
+ mState = eXBL_InBinding;
+ else if (localName == nsGkAtoms::property) {
+ mSecondaryState = eXBL_None;
+ mProperty = nullptr;
+ }
+ else if (localName == nsGkAtoms::method) {
+ mSecondaryState = eXBL_None;
+ mMethod = nullptr;
+ }
+ else if (localName == nsGkAtoms::field) {
+ mSecondaryState = eXBL_None;
+ mField = nullptr;
+ }
+ else if (localName == nsGkAtoms::constructor ||
+ localName == nsGkAtoms::destructor)
+ mSecondaryState = eXBL_None;
+ else if (localName == nsGkAtoms::getter ||
+ localName == nsGkAtoms::setter)
+ mSecondaryState = eXBL_InProperty;
+ else if (localName == nsGkAtoms::parameter ||
+ localName == nsGkAtoms::body)
+ mSecondaryState = eXBL_InMethod;
+ return NS_OK;
+ }
+ else if (mState == eXBL_InBindings &&
+ localName == nsGkAtoms::bindings) {
+ mState = eXBL_InDocument;
+ }
+
+ nsresult rv = nsXMLContentSink::HandleEndElement(aName);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (mState == eXBL_InBinding && localName == nsGkAtoms::binding) {
+ mState = eXBL_InBindings;
+ if (mBinding) { // See comment in HandleStartElement()
+ mBinding->Initialize();
+ mBinding = nullptr; // Clear our current binding ref.
+ }
+ }
+
+ return NS_OK;
+ }
+ }
+
+ return nsXMLContentSink::HandleEndElement(aName);
+}
+
+NS_IMETHODIMP
+nsXBLContentSink::HandleCDataSection(const char16_t *aData,
+ uint32_t aLength)
+{
+ if (mState == eXBL_InHandlers || mState == eXBL_InImplementation)
+ return AddText(aData, aLength);
+ return nsXMLContentSink::HandleCDataSection(aData, aLength);
+}
+
+#define ENSURE_XBL_STATE(_cond) \
+ PR_BEGIN_MACRO \
+ if (!(_cond)) { ReportUnexpectedElement(aTagName, aLineNumber); return true; } \
+ PR_END_MACRO
+
+bool
+nsXBLContentSink::OnOpenContainer(const char16_t **aAtts,
+ uint32_t aAttsCount,
+ int32_t aNameSpaceID,
+ nsIAtom* aTagName,
+ uint32_t aLineNumber)
+{
+ if (mState == eXBL_Error) {
+ return true;
+ }
+
+ if (aNameSpaceID != kNameSpaceID_XBL) {
+ // Construct non-XBL nodes
+ return true;
+ }
+
+ bool ret = true;
+ if (aTagName == nsGkAtoms::bindings) {
+ ENSURE_XBL_STATE(mState == eXBL_InDocument);
+
+ NS_ASSERTION(mDocument, "Must have a document!");
+ RefPtr<nsXBLDocumentInfo> info = new nsXBLDocumentInfo(mDocument);
+
+ // We keep a weak ref. We're creating a cycle between doc/binding manager/doc info.
+ mDocInfo = info;
+
+ if (!mDocInfo) {
+ mState = eXBL_Error;
+ return true;
+ }
+
+ mDocument->BindingManager()->PutXBLDocumentInfo(mDocInfo);
+
+ nsIURI *uri = mDocument->GetDocumentURI();
+
+ bool isChrome = false;
+ bool isRes = false;
+
+ uri->SchemeIs("chrome", &isChrome);
+ uri->SchemeIs("resource", &isRes);
+ mIsChromeOrResource = isChrome || isRes;
+
+ mState = eXBL_InBindings;
+ }
+ else if (aTagName == nsGkAtoms::binding) {
+ ENSURE_XBL_STATE(mState == eXBL_InBindings);
+ mState = eXBL_InBinding;
+ }
+ else if (aTagName == nsGkAtoms::handlers) {
+ ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding);
+ mState = eXBL_InHandlers;
+ ret = false;
+ }
+ else if (aTagName == nsGkAtoms::handler) {
+ ENSURE_XBL_STATE(mState == eXBL_InHandlers);
+ mSecondaryState = eXBL_InHandler;
+ ConstructHandler(aAtts, aLineNumber);
+ ret = false;
+ }
+ else if (aTagName == nsGkAtoms::resources) {
+ ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding);
+ mState = eXBL_InResources;
+ // Note that this mState will cause us to return false, so no need
+ // to set ret to false.
+ }
+ else if (aTagName == nsGkAtoms::stylesheet || aTagName == nsGkAtoms::image) {
+ ENSURE_XBL_STATE(mState == eXBL_InResources);
+ NS_ASSERTION(mBinding, "Must have binding here");
+ ConstructResource(aAtts, aTagName);
+ }
+ else if (aTagName == nsGkAtoms::implementation) {
+ ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding);
+ mState = eXBL_InImplementation;
+ ConstructImplementation(aAtts);
+ // Note that this mState will cause us to return false, so no need
+ // to set ret to false.
+ }
+ else if (aTagName == nsGkAtoms::constructor) {
+ ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
+ mSecondaryState == eXBL_None);
+ NS_ASSERTION(mBinding, "Must have binding here");
+
+ mSecondaryState = eXBL_InConstructor;
+ nsAutoString name;
+ if (!mCurrentBindingID.IsEmpty()) {
+ name.Assign(mCurrentBindingID);
+ name.AppendLiteral("_XBL_Constructor");
+ } else {
+ name.AppendLiteral("XBL_Constructor");
+ }
+ nsXBLProtoImplAnonymousMethod* newMethod =
+ new nsXBLProtoImplAnonymousMethod(name.get());
+ newMethod->SetLineNumber(aLineNumber);
+ mBinding->SetConstructor(newMethod);
+ AddMember(newMethod);
+ }
+ else if (aTagName == nsGkAtoms::destructor) {
+ ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
+ mSecondaryState == eXBL_None);
+ NS_ASSERTION(mBinding, "Must have binding here");
+ mSecondaryState = eXBL_InDestructor;
+ nsAutoString name;
+ if (!mCurrentBindingID.IsEmpty()) {
+ name.Assign(mCurrentBindingID);
+ name.AppendLiteral("_XBL_Destructor");
+ } else {
+ name.AppendLiteral("XBL_Destructor");
+ }
+ nsXBLProtoImplAnonymousMethod* newMethod =
+ new nsXBLProtoImplAnonymousMethod(name.get());
+ newMethod->SetLineNumber(aLineNumber);
+ mBinding->SetDestructor(newMethod);
+ AddMember(newMethod);
+ }
+ else if (aTagName == nsGkAtoms::field) {
+ ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
+ mSecondaryState == eXBL_None);
+ NS_ASSERTION(mBinding, "Must have binding here");
+ mSecondaryState = eXBL_InField;
+ ConstructField(aAtts, aLineNumber);
+ }
+ else if (aTagName == nsGkAtoms::property) {
+ ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
+ mSecondaryState == eXBL_None);
+ NS_ASSERTION(mBinding, "Must have binding here");
+ mSecondaryState = eXBL_InProperty;
+ ConstructProperty(aAtts, aLineNumber);
+ }
+ else if (aTagName == nsGkAtoms::getter) {
+ ENSURE_XBL_STATE(mSecondaryState == eXBL_InProperty && mProperty);
+ NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
+ mProperty->SetGetterLineNumber(aLineNumber);
+ mSecondaryState = eXBL_InGetter;
+ }
+ else if (aTagName == nsGkAtoms::setter) {
+ ENSURE_XBL_STATE(mSecondaryState == eXBL_InProperty && mProperty);
+ NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
+ mProperty->SetSetterLineNumber(aLineNumber);
+ mSecondaryState = eXBL_InSetter;
+ }
+ else if (aTagName == nsGkAtoms::method) {
+ ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
+ mSecondaryState == eXBL_None);
+ NS_ASSERTION(mBinding, "Must have binding here");
+ mSecondaryState = eXBL_InMethod;
+ ConstructMethod(aAtts);
+ }
+ else if (aTagName == nsGkAtoms::parameter) {
+ ENSURE_XBL_STATE(mSecondaryState == eXBL_InMethod && mMethod);
+ NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
+ ConstructParameter(aAtts);
+ }
+ else if (aTagName == nsGkAtoms::body) {
+ ENSURE_XBL_STATE(mSecondaryState == eXBL_InMethod && mMethod);
+ NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
+ // stash away the line number
+ mMethod->SetLineNumber(aLineNumber);
+ mSecondaryState = eXBL_InBody;
+ }
+
+ return ret && mState != eXBL_InResources && mState != eXBL_InImplementation;
+}
+
+#undef ENSURE_XBL_STATE
+
+nsresult
+nsXBLContentSink::ConstructBinding(uint32_t aLineNumber)
+{
+ nsCOMPtr<nsIContent> binding = GetCurrentContent();
+ binding->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mCurrentBindingID);
+ NS_ConvertUTF16toUTF8 cid(mCurrentBindingID);
+
+ nsresult rv = NS_OK;
+
+ // Don't create a binding with no id. nsXBLPrototypeBinding::Read also
+ // performs this check.
+ if (!cid.IsEmpty()) {
+ mBinding = new nsXBLPrototypeBinding();
+
+ rv = mBinding->Init(cid, mDocInfo, binding, !mFoundFirstBinding);
+ if (NS_SUCCEEDED(rv) &&
+ NS_SUCCEEDED(mDocInfo->SetPrototypeBinding(cid, mBinding))) {
+ if (!mFoundFirstBinding) {
+ mFoundFirstBinding = true;
+ mDocInfo->SetFirstPrototypeBinding(mBinding);
+ }
+ binding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::id, false);
+ } else {
+ delete mBinding;
+ mBinding = nullptr;
+ }
+ } else {
+ nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
+ NS_LITERAL_CSTRING("XBL Content Sink"), nullptr,
+ nsContentUtils::eXBL_PROPERTIES,
+ "MissingIdAttr", nullptr, 0,
+ mDocumentURI,
+ EmptyString(),
+ aLineNumber);
+ }
+
+ return rv;
+}
+
+static bool
+FindValue(const char16_t **aAtts, nsIAtom *aAtom, const char16_t **aResult)
+{
+ nsCOMPtr<nsIAtom> prefix, localName;
+ for (; *aAtts; aAtts += 2) {
+ int32_t nameSpaceID;
+ nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
+ getter_AddRefs(localName), &nameSpaceID);
+
+ // Is this attribute one of the ones we care about?
+ if (nameSpaceID == kNameSpaceID_None && localName == aAtom) {
+ *aResult = aAtts[1];
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+nsXBLContentSink::ConstructHandler(const char16_t **aAtts, uint32_t aLineNumber)
+{
+ const char16_t* event = nullptr;
+ const char16_t* modifiers = nullptr;
+ const char16_t* button = nullptr;
+ const char16_t* clickcount = nullptr;
+ const char16_t* keycode = nullptr;
+ const char16_t* charcode = nullptr;
+ const char16_t* phase = nullptr;
+ const char16_t* command = nullptr;
+ const char16_t* action = nullptr;
+ const char16_t* group = nullptr;
+ const char16_t* preventdefault = nullptr;
+ const char16_t* allowuntrusted = nullptr;
+
+ nsCOMPtr<nsIAtom> prefix, localName;
+ for (; *aAtts; aAtts += 2) {
+ int32_t nameSpaceID;
+ nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
+ getter_AddRefs(localName), &nameSpaceID);
+
+ if (nameSpaceID != kNameSpaceID_None) {
+ continue;
+ }
+
+ // Is this attribute one of the ones we care about?
+ if (localName == nsGkAtoms::event)
+ event = aAtts[1];
+ else if (localName == nsGkAtoms::modifiers)
+ modifiers = aAtts[1];
+ else if (localName == nsGkAtoms::button)
+ button = aAtts[1];
+ else if (localName == nsGkAtoms::clickcount)
+ clickcount = aAtts[1];
+ else if (localName == nsGkAtoms::keycode)
+ keycode = aAtts[1];
+ else if (localName == nsGkAtoms::key || localName == nsGkAtoms::charcode)
+ charcode = aAtts[1];
+ else if (localName == nsGkAtoms::phase)
+ phase = aAtts[1];
+ else if (localName == nsGkAtoms::command)
+ command = aAtts[1];
+ else if (localName == nsGkAtoms::action)
+ action = aAtts[1];
+ else if (localName == nsGkAtoms::group)
+ group = aAtts[1];
+ else if (localName == nsGkAtoms::preventdefault)
+ preventdefault = aAtts[1];
+ else if (localName == nsGkAtoms::allowuntrusted)
+ allowuntrusted = aAtts[1];
+ }
+
+ if (command && !mIsChromeOrResource) {
+ // Make sure the XBL doc is chrome or resource if we have a command
+ // shorthand syntax.
+ mState = eXBL_Error;
+ nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
+ NS_LITERAL_CSTRING("XBL Content Sink"),
+ mDocument,
+ nsContentUtils::eXBL_PROPERTIES,
+ "CommandNotInChrome", nullptr, 0,
+ nullptr,
+ EmptyString() /* source line */,
+ aLineNumber);
+ return; // Don't even make this handler.
+ }
+
+ // All of our pointers are now filled in. Construct our handler with all of
+ // these parameters.
+ nsXBLPrototypeHandler* newHandler;
+ newHandler = new nsXBLPrototypeHandler(event, phase, action, command,
+ keycode, charcode, modifiers, button,
+ clickcount, group, preventdefault,
+ allowuntrusted, mBinding, aLineNumber);
+
+ // Add this handler to our chain of handlers.
+ if (mHandler) {
+ // Already have a chain. Just append to the end.
+ mHandler->SetNextHandler(newHandler);
+ } else {
+ // We're the first handler in the chain.
+ mBinding->SetPrototypeHandlers(newHandler);
+ }
+ // Adjust our mHandler pointer to point to the new last handler in the
+ // chain.
+ mHandler = newHandler;
+}
+
+void
+nsXBLContentSink::ConstructResource(const char16_t **aAtts,
+ nsIAtom* aResourceType)
+{
+ if (!mBinding)
+ return;
+
+ const char16_t* src = nullptr;
+ if (FindValue(aAtts, nsGkAtoms::src, &src)) {
+ mBinding->AddResource(aResourceType, nsDependentString(src));
+ }
+}
+
+void
+nsXBLContentSink::ConstructImplementation(const char16_t **aAtts)
+{
+ mImplementation = nullptr;
+ mImplMember = nullptr;
+ mImplField = nullptr;
+
+ if (!mBinding)
+ return;
+
+ const char16_t* name = nullptr;
+
+ nsCOMPtr<nsIAtom> prefix, localName;
+ for (; *aAtts; aAtts += 2) {
+ int32_t nameSpaceID;
+ nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
+ getter_AddRefs(localName), &nameSpaceID);
+
+ if (nameSpaceID != kNameSpaceID_None) {
+ continue;
+ }
+
+ // Is this attribute one of the ones we care about?
+ if (localName == nsGkAtoms::name) {
+ name = aAtts[1];
+ }
+ else if (localName == nsGkAtoms::implements) {
+ // Only allow implementation of interfaces via XBL if the principal of
+ // our XBL document is the system principal.
+ if (nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal())) {
+ mBinding->ConstructInterfaceTable(nsDependentString(aAtts[1]));
+ }
+ }
+ }
+
+ NS_NewXBLProtoImpl(mBinding, name, &mImplementation);
+}
+
+void
+nsXBLContentSink::ConstructField(const char16_t **aAtts, uint32_t aLineNumber)
+{
+ const char16_t* name = nullptr;
+ const char16_t* readonly = nullptr;
+
+ nsCOMPtr<nsIAtom> prefix, localName;
+ for (; *aAtts; aAtts += 2) {
+ int32_t nameSpaceID;
+ nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
+ getter_AddRefs(localName), &nameSpaceID);
+
+ if (nameSpaceID != kNameSpaceID_None) {
+ continue;
+ }
+
+ // Is this attribute one of the ones we care about?
+ if (localName == nsGkAtoms::name) {
+ name = aAtts[1];
+ }
+ else if (localName == nsGkAtoms::readonly) {
+ readonly = aAtts[1];
+ }
+ }
+
+ if (name) {
+ // All of our pointers are now filled in. Construct our field with all of
+ // these parameters.
+ mField = new nsXBLProtoImplField(name, readonly);
+ mField->SetLineNumber(aLineNumber);
+ AddField(mField);
+ }
+}
+
+void
+nsXBLContentSink::ConstructProperty(const char16_t **aAtts, uint32_t aLineNumber)
+{
+ const char16_t* name = nullptr;
+ const char16_t* readonly = nullptr;
+ const char16_t* onget = nullptr;
+ const char16_t* onset = nullptr;
+ bool exposeToUntrustedContent = false;
+
+ nsCOMPtr<nsIAtom> prefix, localName;
+ for (; *aAtts; aAtts += 2) {
+ int32_t nameSpaceID;
+ nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
+ getter_AddRefs(localName), &nameSpaceID);
+
+ if (nameSpaceID != kNameSpaceID_None) {
+ continue;
+ }
+
+ // Is this attribute one of the ones we care about?
+ if (localName == nsGkAtoms::name) {
+ name = aAtts[1];
+ }
+ else if (localName == nsGkAtoms::readonly) {
+ readonly = aAtts[1];
+ }
+ else if (localName == nsGkAtoms::onget) {
+ onget = aAtts[1];
+ }
+ else if (localName == nsGkAtoms::onset) {
+ onset = aAtts[1];
+ }
+ else if (localName == nsGkAtoms::exposeToUntrustedContent &&
+ nsDependentString(aAtts[1]).EqualsLiteral("true"))
+ {
+ exposeToUntrustedContent = true;
+ }
+ }
+
+ if (name) {
+ // All of our pointers are now filled in. Construct our property with all of
+ // these parameters.
+ mProperty = new nsXBLProtoImplProperty(name, onget, onset, readonly, aLineNumber);
+ if (exposeToUntrustedContent) {
+ mProperty->SetExposeToUntrustedContent(true);
+ }
+ AddMember(mProperty);
+ }
+}
+
+void
+nsXBLContentSink::ConstructMethod(const char16_t **aAtts)
+{
+ mMethod = nullptr;
+
+ const char16_t* name = nullptr;
+ const char16_t* expose = nullptr;
+ if (FindValue(aAtts, nsGkAtoms::name, &name)) {
+ mMethod = new nsXBLProtoImplMethod(name);
+ if (FindValue(aAtts, nsGkAtoms::exposeToUntrustedContent, &expose) &&
+ nsDependentString(expose).EqualsLiteral("true"))
+ {
+ mMethod->SetExposeToUntrustedContent(true);
+ }
+ }
+
+ if (mMethod) {
+ AddMember(mMethod);
+ }
+}
+
+void
+nsXBLContentSink::ConstructParameter(const char16_t **aAtts)
+{
+ if (!mMethod)
+ return;
+
+ const char16_t* name = nullptr;
+ if (FindValue(aAtts, nsGkAtoms::name, &name)) {
+ mMethod->AddParameter(nsDependentString(name));
+ }
+}
+
+nsresult
+nsXBLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
+ mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
+ nsIContent** aResult, bool* aAppendContent,
+ FromParser aFromParser)
+{
+#ifdef MOZ_XUL
+ if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
+#endif
+ return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo,
+ aLineNumber, aResult,
+ aAppendContent, aFromParser);
+#ifdef MOZ_XUL
+ }
+
+ // Note that this needs to match the code in nsXBLPrototypeBinding::ReadContentNode.
+
+ *aAppendContent = true;
+ RefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
+
+ prototype->mNodeInfo = aNodeInfo;
+
+ AddAttributesToXULPrototype(aAtts, aAttsCount, prototype);
+
+ Element* result;
+ nsresult rv = nsXULElement::Create(prototype, mDocument, false, false, &result);
+ *aResult = result;
+ return rv;
+#endif
+}
+
+nsresult
+nsXBLContentSink::AddAttributes(const char16_t** aAtts,
+ nsIContent* aContent)
+{
+ if (aContent->IsXULElement())
+ return NS_OK; // Nothing to do, since the proto already has the attrs.
+
+ return nsXMLContentSink::AddAttributes(aAtts, aContent);
+}
+
+#ifdef MOZ_XUL
+nsresult
+nsXBLContentSink::AddAttributesToXULPrototype(const char16_t **aAtts,
+ uint32_t aAttsCount,
+ nsXULPrototypeElement* aElement)
+{
+ // Add tag attributes to the element
+ nsresult rv;
+
+ // Create storage for the attributes
+ nsXULPrototypeAttribute* attrs = nullptr;
+ if (aAttsCount > 0) {
+ attrs = new nsXULPrototypeAttribute[aAttsCount];
+ }
+
+ aElement->mAttributes = attrs;
+ aElement->mNumAttributes = aAttsCount;
+
+ // Copy the attributes into the prototype
+ nsCOMPtr<nsIAtom> prefix, localName;
+
+ uint32_t i;
+ for (i = 0; i < aAttsCount; ++i) {
+ int32_t nameSpaceID;
+ nsContentUtils::SplitExpatName(aAtts[i * 2], getter_AddRefs(prefix),
+ getter_AddRefs(localName), &nameSpaceID);
+
+ if (nameSpaceID == kNameSpaceID_None) {
+ attrs[i].mName.SetTo(localName);
+ }
+ else {
+ RefPtr<NodeInfo> ni;
+ ni = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
+ nsIDOMNode::ATTRIBUTE_NODE);
+ attrs[i].mName.SetTo(ni);
+ }
+
+ rv = aElement->SetAttrAt(i, nsDependentString(aAtts[i * 2 + 1]),
+ mDocumentURI);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+#endif