diff options
Diffstat (limited to 'dom/xbl/nsXBLContentSink.cpp')
-rw-r--r-- | dom/xbl/nsXBLContentSink.cpp | 937 |
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 |