1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/xbl/nsXBLContentSink.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,956 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/ArrayUtils.h" 1.10 + 1.11 +#include "nsXBLContentSink.h" 1.12 +#include "nsIDocument.h" 1.13 +#include "nsBindingManager.h" 1.14 +#include "nsIDOMNode.h" 1.15 +#include "nsGkAtoms.h" 1.16 +#include "nsNameSpaceManager.h" 1.17 +#include "nsIURI.h" 1.18 +#include "nsTextFragment.h" 1.19 +#ifdef MOZ_XUL 1.20 +#include "nsXULElement.h" 1.21 +#endif 1.22 +#include "nsXBLProtoImplProperty.h" 1.23 +#include "nsXBLProtoImplMethod.h" 1.24 +#include "nsXBLProtoImplField.h" 1.25 +#include "nsXBLPrototypeBinding.h" 1.26 +#include "nsContentUtils.h" 1.27 +#include "nsIConsoleService.h" 1.28 +#include "nsIScriptError.h" 1.29 +#include "nsNodeInfoManager.h" 1.30 +#include "nsINodeInfo.h" 1.31 +#include "nsIPrincipal.h" 1.32 +#include "mozilla/dom/Element.h" 1.33 + 1.34 +using namespace mozilla; 1.35 +using namespace mozilla::dom; 1.36 + 1.37 +nsresult 1.38 +NS_NewXBLContentSink(nsIXMLContentSink** aResult, 1.39 + nsIDocument* aDoc, 1.40 + nsIURI* aURI, 1.41 + nsISupports* aContainer) 1.42 +{ 1.43 + NS_ENSURE_ARG_POINTER(aResult); 1.44 + 1.45 + nsXBLContentSink* it = new nsXBLContentSink(); 1.46 + NS_ENSURE_TRUE(it, NS_ERROR_OUT_OF_MEMORY); 1.47 + 1.48 + nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it; 1.49 + nsresult rv = it->Init(aDoc, aURI, aContainer); 1.50 + NS_ENSURE_SUCCESS(rv, rv); 1.51 + 1.52 + return CallQueryInterface(it, aResult); 1.53 +} 1.54 + 1.55 +nsXBLContentSink::nsXBLContentSink() 1.56 + : mState(eXBL_InDocument), 1.57 + mSecondaryState(eXBL_None), 1.58 + mDocInfo(nullptr), 1.59 + mIsChromeOrResource(false), 1.60 + mFoundFirstBinding(false), 1.61 + mBinding(nullptr), 1.62 + mHandler(nullptr), 1.63 + mImplementation(nullptr), 1.64 + mImplMember(nullptr), 1.65 + mImplField(nullptr), 1.66 + mProperty(nullptr), 1.67 + mMethod(nullptr), 1.68 + mField(nullptr) 1.69 +{ 1.70 + mPrettyPrintXML = false; 1.71 +} 1.72 + 1.73 +nsXBLContentSink::~nsXBLContentSink() 1.74 +{ 1.75 +} 1.76 + 1.77 +nsresult 1.78 +nsXBLContentSink::Init(nsIDocument* aDoc, 1.79 + nsIURI* aURI, 1.80 + nsISupports* aContainer) 1.81 +{ 1.82 + nsresult rv; 1.83 + rv = nsXMLContentSink::Init(aDoc, aURI, aContainer, nullptr); 1.84 + return rv; 1.85 +} 1.86 + 1.87 +void 1.88 +nsXBLContentSink::MaybeStartLayout(bool aIgnorePendingSheets) 1.89 +{ 1.90 + return; 1.91 +} 1.92 + 1.93 +nsresult 1.94 +nsXBLContentSink::FlushText(bool aReleaseTextNode) 1.95 +{ 1.96 + if (mTextLength != 0) { 1.97 + const nsASingleFragmentString& text = Substring(mText, mText+mTextLength); 1.98 + if (mState == eXBL_InHandlers) { 1.99 + NS_ASSERTION(mBinding, "Must have binding here"); 1.100 + // Get the text and add it to the event handler. 1.101 + if (mSecondaryState == eXBL_InHandler) 1.102 + mHandler->AppendHandlerText(text); 1.103 + mTextLength = 0; 1.104 + return NS_OK; 1.105 + } 1.106 + else if (mState == eXBL_InImplementation) { 1.107 + NS_ASSERTION(mBinding, "Must have binding here"); 1.108 + if (mSecondaryState == eXBL_InConstructor || 1.109 + mSecondaryState == eXBL_InDestructor) { 1.110 + // Construct a method for the constructor/destructor. 1.111 + nsXBLProtoImplMethod* method; 1.112 + if (mSecondaryState == eXBL_InConstructor) 1.113 + method = mBinding->GetConstructor(); 1.114 + else 1.115 + method = mBinding->GetDestructor(); 1.116 + 1.117 + // Get the text and add it to the constructor/destructor. 1.118 + method->AppendBodyText(text); 1.119 + } 1.120 + else if (mSecondaryState == eXBL_InGetter || 1.121 + mSecondaryState == eXBL_InSetter) { 1.122 + // Get the text and add it to the getter/setter 1.123 + if (mSecondaryState == eXBL_InGetter) 1.124 + mProperty->AppendGetterText(text); 1.125 + else 1.126 + mProperty->AppendSetterText(text); 1.127 + } 1.128 + else if (mSecondaryState == eXBL_InBody) { 1.129 + // Get the text and add it to the method 1.130 + if (mMethod) 1.131 + mMethod->AppendBodyText(text); 1.132 + } 1.133 + else if (mSecondaryState == eXBL_InField) { 1.134 + // Get the text and add it to the method 1.135 + if (mField) 1.136 + mField->AppendFieldText(text); 1.137 + } 1.138 + mTextLength = 0; 1.139 + return NS_OK; 1.140 + } 1.141 + 1.142 + nsIContent* content = GetCurrentContent(); 1.143 + if (content && 1.144 + (content->NodeInfo()->NamespaceEquals(kNameSpaceID_XBL) || 1.145 + (content->NodeInfo()->NamespaceEquals(kNameSpaceID_XUL) && 1.146 + content->Tag() != nsGkAtoms::label && 1.147 + content->Tag() != nsGkAtoms::description))) { 1.148 + 1.149 + bool isWS = true; 1.150 + if (mTextLength > 0) { 1.151 + const char16_t* cp = mText; 1.152 + const char16_t* end = mText + mTextLength; 1.153 + while (cp < end) { 1.154 + char16_t ch = *cp++; 1.155 + if (!dom::IsSpaceCharacter(ch)) { 1.156 + isWS = false; 1.157 + break; 1.158 + } 1.159 + } 1.160 + } 1.161 + 1.162 + if (isWS && mTextLength > 0) { 1.163 + mTextLength = 0; 1.164 + // Make sure to drop the textnode, if any 1.165 + return nsXMLContentSink::FlushText(aReleaseTextNode); 1.166 + } 1.167 + } 1.168 + } 1.169 + 1.170 + return nsXMLContentSink::FlushText(aReleaseTextNode); 1.171 +} 1.172 + 1.173 +NS_IMETHODIMP 1.174 +nsXBLContentSink::ReportError(const char16_t* aErrorText, 1.175 + const char16_t* aSourceText, 1.176 + nsIScriptError *aError, 1.177 + bool *_retval) 1.178 +{ 1.179 + NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!"); 1.180 + 1.181 + // XXX FIXME This function overrides and calls on 1.182 + // nsXMLContentSink::ReportError, and probably should die. See bug 347826. 1.183 + 1.184 + // XXX We should make sure the binding has no effect, but that it also 1.185 + // gets destroyed properly without leaking. Perhaps we should even 1.186 + // ensure that the content that was bound is displayed with no 1.187 + // binding. 1.188 + 1.189 +#ifdef DEBUG 1.190 + // Report the error to stderr. 1.191 + fprintf(stderr, 1.192 + "\n%s\n%s\n\n", 1.193 + NS_LossyConvertUTF16toASCII(aErrorText).get(), 1.194 + NS_LossyConvertUTF16toASCII(aSourceText).get()); 1.195 +#endif 1.196 + 1.197 + // Most of what this does won't be too useful, but whatever... 1.198 + // nsXMLContentSink::ReportError will handle the console logging. 1.199 + return nsXMLContentSink::ReportError(aErrorText, 1.200 + aSourceText, 1.201 + aError, 1.202 + _retval); 1.203 +} 1.204 + 1.205 +nsresult 1.206 +nsXBLContentSink::ReportUnexpectedElement(nsIAtom* aElementName, 1.207 + uint32_t aLineNumber) 1.208 +{ 1.209 + // XXX we should really somehow stop the parse and drop the binding 1.210 + // instead of just letting the XML sink build the content model like 1.211 + // we do... 1.212 + mState = eXBL_Error; 1.213 + nsAutoString elementName; 1.214 + aElementName->ToString(elementName); 1.215 + 1.216 + const char16_t* params[] = { elementName.get() }; 1.217 + 1.218 + return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, 1.219 + NS_LITERAL_CSTRING("XBL Content Sink"), 1.220 + mDocument, 1.221 + nsContentUtils::eXBL_PROPERTIES, 1.222 + "UnexpectedElement", 1.223 + params, ArrayLength(params), 1.224 + nullptr, 1.225 + EmptyString() /* source line */, 1.226 + aLineNumber); 1.227 +} 1.228 + 1.229 +void 1.230 +nsXBLContentSink::AddMember(nsXBLProtoImplMember* aMember) 1.231 +{ 1.232 + // Add this member to our chain. 1.233 + if (mImplMember) 1.234 + mImplMember->SetNext(aMember); // Already have a chain. Just append to the end. 1.235 + else 1.236 + mImplementation->SetMemberList(aMember); // We're the first member in the chain. 1.237 + 1.238 + mImplMember = aMember; // Adjust our pointer to point to the new last member in the chain. 1.239 +} 1.240 + 1.241 +void 1.242 +nsXBLContentSink::AddField(nsXBLProtoImplField* aField) 1.243 +{ 1.244 + // Add this field to our chain. 1.245 + if (mImplField) 1.246 + mImplField->SetNext(aField); // Already have a chain. Just append to the end. 1.247 + else 1.248 + mImplementation->SetFieldList(aField); // We're the first member in the chain. 1.249 + 1.250 + mImplField = aField; // Adjust our pointer to point to the new last field in the chain. 1.251 +} 1.252 + 1.253 +NS_IMETHODIMP 1.254 +nsXBLContentSink::HandleStartElement(const char16_t *aName, 1.255 + const char16_t **aAtts, 1.256 + uint32_t aAttsCount, 1.257 + int32_t aIndex, 1.258 + uint32_t aLineNumber) 1.259 +{ 1.260 + nsresult rv = nsXMLContentSink::HandleStartElement(aName,aAtts,aAttsCount,aIndex,aLineNumber); 1.261 + if (NS_FAILED(rv)) 1.262 + return rv; 1.263 + 1.264 + if (mState == eXBL_InBinding && !mBinding) { 1.265 + rv = ConstructBinding(aLineNumber); 1.266 + if (NS_FAILED(rv)) 1.267 + return rv; 1.268 + 1.269 + // mBinding may still be null, if the binding had no id. If so, 1.270 + // we'll deal with that later in the sink. 1.271 + } 1.272 + 1.273 + return rv; 1.274 +} 1.275 + 1.276 +NS_IMETHODIMP 1.277 +nsXBLContentSink::HandleEndElement(const char16_t *aName) 1.278 +{ 1.279 + FlushText(); 1.280 + 1.281 + if (mState != eXBL_InDocument) { 1.282 + int32_t nameSpaceID; 1.283 + nsCOMPtr<nsIAtom> prefix, localName; 1.284 + nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix), 1.285 + getter_AddRefs(localName), &nameSpaceID); 1.286 + 1.287 + if (nameSpaceID == kNameSpaceID_XBL) { 1.288 + if (mState == eXBL_Error) { 1.289 + // Check whether we've opened this tag before; we may not have if 1.290 + // it was a real XBL tag before the error occurred. 1.291 + if (!GetCurrentContent()->NodeInfo()->Equals(localName, 1.292 + nameSpaceID)) { 1.293 + // OK, this tag was never opened as far as the XML sink is 1.294 + // concerned. Just drop the HandleEndElement 1.295 + return NS_OK; 1.296 + } 1.297 + } 1.298 + else if (mState == eXBL_InHandlers) { 1.299 + if (localName == nsGkAtoms::handlers) { 1.300 + mState = eXBL_InBinding; 1.301 + mHandler = nullptr; 1.302 + } 1.303 + else if (localName == nsGkAtoms::handler) 1.304 + mSecondaryState = eXBL_None; 1.305 + return NS_OK; 1.306 + } 1.307 + else if (mState == eXBL_InResources) { 1.308 + if (localName == nsGkAtoms::resources) 1.309 + mState = eXBL_InBinding; 1.310 + return NS_OK; 1.311 + } 1.312 + else if (mState == eXBL_InImplementation) { 1.313 + if (localName == nsGkAtoms::implementation) 1.314 + mState = eXBL_InBinding; 1.315 + else if (localName == nsGkAtoms::property) { 1.316 + mSecondaryState = eXBL_None; 1.317 + mProperty = nullptr; 1.318 + } 1.319 + else if (localName == nsGkAtoms::method) { 1.320 + mSecondaryState = eXBL_None; 1.321 + mMethod = nullptr; 1.322 + } 1.323 + else if (localName == nsGkAtoms::field) { 1.324 + mSecondaryState = eXBL_None; 1.325 + mField = nullptr; 1.326 + } 1.327 + else if (localName == nsGkAtoms::constructor || 1.328 + localName == nsGkAtoms::destructor) 1.329 + mSecondaryState = eXBL_None; 1.330 + else if (localName == nsGkAtoms::getter || 1.331 + localName == nsGkAtoms::setter) 1.332 + mSecondaryState = eXBL_InProperty; 1.333 + else if (localName == nsGkAtoms::parameter || 1.334 + localName == nsGkAtoms::body) 1.335 + mSecondaryState = eXBL_InMethod; 1.336 + return NS_OK; 1.337 + } 1.338 + else if (mState == eXBL_InBindings && 1.339 + localName == nsGkAtoms::bindings) { 1.340 + mState = eXBL_InDocument; 1.341 + } 1.342 + 1.343 + nsresult rv = nsXMLContentSink::HandleEndElement(aName); 1.344 + if (NS_FAILED(rv)) 1.345 + return rv; 1.346 + 1.347 + if (mState == eXBL_InBinding && localName == nsGkAtoms::binding) { 1.348 + mState = eXBL_InBindings; 1.349 + if (mBinding) { // See comment in HandleStartElement() 1.350 + mBinding->Initialize(); 1.351 + mBinding = nullptr; // Clear our current binding ref. 1.352 + } 1.353 + } 1.354 + 1.355 + return NS_OK; 1.356 + } 1.357 + } 1.358 + 1.359 + return nsXMLContentSink::HandleEndElement(aName); 1.360 +} 1.361 + 1.362 +NS_IMETHODIMP 1.363 +nsXBLContentSink::HandleCDataSection(const char16_t *aData, 1.364 + uint32_t aLength) 1.365 +{ 1.366 + if (mState == eXBL_InHandlers || mState == eXBL_InImplementation) 1.367 + return AddText(aData, aLength); 1.368 + return nsXMLContentSink::HandleCDataSection(aData, aLength); 1.369 +} 1.370 + 1.371 +#define ENSURE_XBL_STATE(_cond) \ 1.372 + PR_BEGIN_MACRO \ 1.373 + if (!(_cond)) { ReportUnexpectedElement(aTagName, aLineNumber); return true; } \ 1.374 + PR_END_MACRO 1.375 + 1.376 +bool 1.377 +nsXBLContentSink::OnOpenContainer(const char16_t **aAtts, 1.378 + uint32_t aAttsCount, 1.379 + int32_t aNameSpaceID, 1.380 + nsIAtom* aTagName, 1.381 + uint32_t aLineNumber) 1.382 +{ 1.383 + if (mState == eXBL_Error) { 1.384 + return true; 1.385 + } 1.386 + 1.387 + if (aNameSpaceID != kNameSpaceID_XBL) { 1.388 + // Construct non-XBL nodes 1.389 + return true; 1.390 + } 1.391 + 1.392 + bool ret = true; 1.393 + if (aTagName == nsGkAtoms::bindings) { 1.394 + ENSURE_XBL_STATE(mState == eXBL_InDocument); 1.395 + 1.396 + NS_ASSERTION(mDocument, "Must have a document!"); 1.397 + nsRefPtr<nsXBLDocumentInfo> info = new nsXBLDocumentInfo(mDocument); 1.398 + 1.399 + // We keep a weak ref. We're creating a cycle between doc/binding manager/doc info. 1.400 + mDocInfo = info; 1.401 + 1.402 + if (!mDocInfo) { 1.403 + mState = eXBL_Error; 1.404 + return true; 1.405 + } 1.406 + 1.407 + mDocument->BindingManager()->PutXBLDocumentInfo(mDocInfo); 1.408 + 1.409 + nsIURI *uri = mDocument->GetDocumentURI(); 1.410 + 1.411 + bool isChrome = false; 1.412 + bool isRes = false; 1.413 + 1.414 + uri->SchemeIs("chrome", &isChrome); 1.415 + uri->SchemeIs("resource", &isRes); 1.416 + mIsChromeOrResource = isChrome || isRes; 1.417 + 1.418 + mState = eXBL_InBindings; 1.419 + } 1.420 + else if (aTagName == nsGkAtoms::binding) { 1.421 + ENSURE_XBL_STATE(mState == eXBL_InBindings); 1.422 + mState = eXBL_InBinding; 1.423 + } 1.424 + else if (aTagName == nsGkAtoms::handlers) { 1.425 + ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding); 1.426 + mState = eXBL_InHandlers; 1.427 + ret = false; 1.428 + } 1.429 + else if (aTagName == nsGkAtoms::handler) { 1.430 + ENSURE_XBL_STATE(mState == eXBL_InHandlers); 1.431 + mSecondaryState = eXBL_InHandler; 1.432 + ConstructHandler(aAtts, aLineNumber); 1.433 + ret = false; 1.434 + } 1.435 + else if (aTagName == nsGkAtoms::resources) { 1.436 + ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding); 1.437 + mState = eXBL_InResources; 1.438 + // Note that this mState will cause us to return false, so no need 1.439 + // to set ret to false. 1.440 + } 1.441 + else if (aTagName == nsGkAtoms::stylesheet || aTagName == nsGkAtoms::image) { 1.442 + ENSURE_XBL_STATE(mState == eXBL_InResources); 1.443 + NS_ASSERTION(mBinding, "Must have binding here"); 1.444 + ConstructResource(aAtts, aTagName); 1.445 + } 1.446 + else if (aTagName == nsGkAtoms::implementation) { 1.447 + ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding); 1.448 + mState = eXBL_InImplementation; 1.449 + ConstructImplementation(aAtts); 1.450 + // Note that this mState will cause us to return false, so no need 1.451 + // to set ret to false. 1.452 + } 1.453 + else if (aTagName == nsGkAtoms::constructor) { 1.454 + ENSURE_XBL_STATE(mState == eXBL_InImplementation && 1.455 + mSecondaryState == eXBL_None); 1.456 + NS_ASSERTION(mBinding, "Must have binding here"); 1.457 + 1.458 + mSecondaryState = eXBL_InConstructor; 1.459 + nsAutoString name; 1.460 + if (!mCurrentBindingID.IsEmpty()) { 1.461 + name.Assign(mCurrentBindingID); 1.462 + name.AppendLiteral("_XBL_Constructor"); 1.463 + } else { 1.464 + name.AppendLiteral("XBL_Constructor"); 1.465 + } 1.466 + nsXBLProtoImplAnonymousMethod* newMethod = 1.467 + new nsXBLProtoImplAnonymousMethod(name.get()); 1.468 + if (newMethod) { 1.469 + newMethod->SetLineNumber(aLineNumber); 1.470 + mBinding->SetConstructor(newMethod); 1.471 + AddMember(newMethod); 1.472 + } 1.473 + } 1.474 + else if (aTagName == nsGkAtoms::destructor) { 1.475 + ENSURE_XBL_STATE(mState == eXBL_InImplementation && 1.476 + mSecondaryState == eXBL_None); 1.477 + NS_ASSERTION(mBinding, "Must have binding here"); 1.478 + mSecondaryState = eXBL_InDestructor; 1.479 + nsAutoString name; 1.480 + if (!mCurrentBindingID.IsEmpty()) { 1.481 + name.Assign(mCurrentBindingID); 1.482 + name.AppendLiteral("_XBL_Destructor"); 1.483 + } else { 1.484 + name.AppendLiteral("XBL_Destructor"); 1.485 + } 1.486 + nsXBLProtoImplAnonymousMethod* newMethod = 1.487 + new nsXBLProtoImplAnonymousMethod(name.get()); 1.488 + if (newMethod) { 1.489 + newMethod->SetLineNumber(aLineNumber); 1.490 + mBinding->SetDestructor(newMethod); 1.491 + AddMember(newMethod); 1.492 + } 1.493 + } 1.494 + else if (aTagName == nsGkAtoms::field) { 1.495 + ENSURE_XBL_STATE(mState == eXBL_InImplementation && 1.496 + mSecondaryState == eXBL_None); 1.497 + NS_ASSERTION(mBinding, "Must have binding here"); 1.498 + mSecondaryState = eXBL_InField; 1.499 + ConstructField(aAtts, aLineNumber); 1.500 + } 1.501 + else if (aTagName == nsGkAtoms::property) { 1.502 + ENSURE_XBL_STATE(mState == eXBL_InImplementation && 1.503 + mSecondaryState == eXBL_None); 1.504 + NS_ASSERTION(mBinding, "Must have binding here"); 1.505 + mSecondaryState = eXBL_InProperty; 1.506 + ConstructProperty(aAtts, aLineNumber); 1.507 + } 1.508 + else if (aTagName == nsGkAtoms::getter) { 1.509 + ENSURE_XBL_STATE(mSecondaryState == eXBL_InProperty && mProperty); 1.510 + NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state"); 1.511 + mProperty->SetGetterLineNumber(aLineNumber); 1.512 + mSecondaryState = eXBL_InGetter; 1.513 + } 1.514 + else if (aTagName == nsGkAtoms::setter) { 1.515 + ENSURE_XBL_STATE(mSecondaryState == eXBL_InProperty && mProperty); 1.516 + NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state"); 1.517 + mProperty->SetSetterLineNumber(aLineNumber); 1.518 + mSecondaryState = eXBL_InSetter; 1.519 + } 1.520 + else if (aTagName == nsGkAtoms::method) { 1.521 + ENSURE_XBL_STATE(mState == eXBL_InImplementation && 1.522 + mSecondaryState == eXBL_None); 1.523 + NS_ASSERTION(mBinding, "Must have binding here"); 1.524 + mSecondaryState = eXBL_InMethod; 1.525 + ConstructMethod(aAtts); 1.526 + } 1.527 + else if (aTagName == nsGkAtoms::parameter) { 1.528 + ENSURE_XBL_STATE(mSecondaryState == eXBL_InMethod && mMethod); 1.529 + NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state"); 1.530 + ConstructParameter(aAtts); 1.531 + } 1.532 + else if (aTagName == nsGkAtoms::body) { 1.533 + ENSURE_XBL_STATE(mSecondaryState == eXBL_InMethod && mMethod); 1.534 + NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state"); 1.535 + // stash away the line number 1.536 + mMethod->SetLineNumber(aLineNumber); 1.537 + mSecondaryState = eXBL_InBody; 1.538 + } 1.539 + 1.540 + return ret && mState != eXBL_InResources && mState != eXBL_InImplementation; 1.541 +} 1.542 + 1.543 +#undef ENSURE_XBL_STATE 1.544 + 1.545 +nsresult 1.546 +nsXBLContentSink::ConstructBinding(uint32_t aLineNumber) 1.547 +{ 1.548 + nsCOMPtr<nsIContent> binding = GetCurrentContent(); 1.549 + binding->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mCurrentBindingID); 1.550 + NS_ConvertUTF16toUTF8 cid(mCurrentBindingID); 1.551 + 1.552 + nsresult rv = NS_OK; 1.553 + 1.554 + // Don't create a binding with no id. nsXBLPrototypeBinding::Read also 1.555 + // performs this check. 1.556 + if (!cid.IsEmpty()) { 1.557 + mBinding = new nsXBLPrototypeBinding(); 1.558 + if (!mBinding) 1.559 + return NS_ERROR_OUT_OF_MEMORY; 1.560 + 1.561 + rv = mBinding->Init(cid, mDocInfo, binding, !mFoundFirstBinding); 1.562 + if (NS_SUCCEEDED(rv) && 1.563 + NS_SUCCEEDED(mDocInfo->SetPrototypeBinding(cid, mBinding))) { 1.564 + if (!mFoundFirstBinding) { 1.565 + mFoundFirstBinding = true; 1.566 + mDocInfo->SetFirstPrototypeBinding(mBinding); 1.567 + } 1.568 + binding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::id, false); 1.569 + } else { 1.570 + delete mBinding; 1.571 + mBinding = nullptr; 1.572 + } 1.573 + } else { 1.574 + nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, 1.575 + NS_LITERAL_CSTRING("XBL Content Sink"), nullptr, 1.576 + nsContentUtils::eXBL_PROPERTIES, 1.577 + "MissingIdAttr", nullptr, 0, 1.578 + mDocumentURI, 1.579 + EmptyString(), 1.580 + aLineNumber); 1.581 + } 1.582 + 1.583 + return rv; 1.584 +} 1.585 + 1.586 +static bool 1.587 +FindValue(const char16_t **aAtts, nsIAtom *aAtom, const char16_t **aResult) 1.588 +{ 1.589 + nsCOMPtr<nsIAtom> prefix, localName; 1.590 + for (; *aAtts; aAtts += 2) { 1.591 + int32_t nameSpaceID; 1.592 + nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), 1.593 + getter_AddRefs(localName), &nameSpaceID); 1.594 + 1.595 + // Is this attribute one of the ones we care about? 1.596 + if (nameSpaceID == kNameSpaceID_None && localName == aAtom) { 1.597 + *aResult = aAtts[1]; 1.598 + 1.599 + return true; 1.600 + } 1.601 + } 1.602 + 1.603 + return false; 1.604 +} 1.605 + 1.606 +void 1.607 +nsXBLContentSink::ConstructHandler(const char16_t **aAtts, uint32_t aLineNumber) 1.608 +{ 1.609 + const char16_t* event = nullptr; 1.610 + const char16_t* modifiers = nullptr; 1.611 + const char16_t* button = nullptr; 1.612 + const char16_t* clickcount = nullptr; 1.613 + const char16_t* keycode = nullptr; 1.614 + const char16_t* charcode = nullptr; 1.615 + const char16_t* phase = nullptr; 1.616 + const char16_t* command = nullptr; 1.617 + const char16_t* action = nullptr; 1.618 + const char16_t* group = nullptr; 1.619 + const char16_t* preventdefault = nullptr; 1.620 + const char16_t* allowuntrusted = nullptr; 1.621 + 1.622 + nsCOMPtr<nsIAtom> prefix, localName; 1.623 + for (; *aAtts; aAtts += 2) { 1.624 + int32_t nameSpaceID; 1.625 + nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), 1.626 + getter_AddRefs(localName), &nameSpaceID); 1.627 + 1.628 + if (nameSpaceID != kNameSpaceID_None) { 1.629 + continue; 1.630 + } 1.631 + 1.632 + // Is this attribute one of the ones we care about? 1.633 + if (localName == nsGkAtoms::event) 1.634 + event = aAtts[1]; 1.635 + else if (localName == nsGkAtoms::modifiers) 1.636 + modifiers = aAtts[1]; 1.637 + else if (localName == nsGkAtoms::button) 1.638 + button = aAtts[1]; 1.639 + else if (localName == nsGkAtoms::clickcount) 1.640 + clickcount = aAtts[1]; 1.641 + else if (localName == nsGkAtoms::keycode) 1.642 + keycode = aAtts[1]; 1.643 + else if (localName == nsGkAtoms::key || localName == nsGkAtoms::charcode) 1.644 + charcode = aAtts[1]; 1.645 + else if (localName == nsGkAtoms::phase) 1.646 + phase = aAtts[1]; 1.647 + else if (localName == nsGkAtoms::command) 1.648 + command = aAtts[1]; 1.649 + else if (localName == nsGkAtoms::action) 1.650 + action = aAtts[1]; 1.651 + else if (localName == nsGkAtoms::group) 1.652 + group = aAtts[1]; 1.653 + else if (localName == nsGkAtoms::preventdefault) 1.654 + preventdefault = aAtts[1]; 1.655 + else if (localName == nsGkAtoms::allowuntrusted) 1.656 + allowuntrusted = aAtts[1]; 1.657 + } 1.658 + 1.659 + if (command && !mIsChromeOrResource) { 1.660 + // Make sure the XBL doc is chrome or resource if we have a command 1.661 + // shorthand syntax. 1.662 + mState = eXBL_Error; 1.663 + nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, 1.664 + NS_LITERAL_CSTRING("XBL Content Sink"), 1.665 + mDocument, 1.666 + nsContentUtils::eXBL_PROPERTIES, 1.667 + "CommandNotInChrome", nullptr, 0, 1.668 + nullptr, 1.669 + EmptyString() /* source line */, 1.670 + aLineNumber); 1.671 + return; // Don't even make this handler. 1.672 + } 1.673 + 1.674 + // All of our pointers are now filled in. Construct our handler with all of 1.675 + // these parameters. 1.676 + nsXBLPrototypeHandler* newHandler; 1.677 + newHandler = new nsXBLPrototypeHandler(event, phase, action, command, 1.678 + keycode, charcode, modifiers, button, 1.679 + clickcount, group, preventdefault, 1.680 + allowuntrusted, mBinding, aLineNumber); 1.681 + 1.682 + if (newHandler) { 1.683 + // Add this handler to our chain of handlers. 1.684 + if (mHandler) { 1.685 + // Already have a chain. Just append to the end. 1.686 + mHandler->SetNextHandler(newHandler); 1.687 + } 1.688 + else { 1.689 + // We're the first handler in the chain. 1.690 + mBinding->SetPrototypeHandlers(newHandler); 1.691 + } 1.692 + // Adjust our mHandler pointer to point to the new last handler in the 1.693 + // chain. 1.694 + mHandler = newHandler; 1.695 + } else { 1.696 + mState = eXBL_Error; 1.697 + } 1.698 +} 1.699 + 1.700 +void 1.701 +nsXBLContentSink::ConstructResource(const char16_t **aAtts, 1.702 + nsIAtom* aResourceType) 1.703 +{ 1.704 + if (!mBinding) 1.705 + return; 1.706 + 1.707 + const char16_t* src = nullptr; 1.708 + if (FindValue(aAtts, nsGkAtoms::src, &src)) { 1.709 + mBinding->AddResource(aResourceType, nsDependentString(src)); 1.710 + } 1.711 +} 1.712 + 1.713 +void 1.714 +nsXBLContentSink::ConstructImplementation(const char16_t **aAtts) 1.715 +{ 1.716 + mImplementation = nullptr; 1.717 + mImplMember = nullptr; 1.718 + mImplField = nullptr; 1.719 + 1.720 + if (!mBinding) 1.721 + return; 1.722 + 1.723 + const char16_t* name = nullptr; 1.724 + 1.725 + nsCOMPtr<nsIAtom> prefix, localName; 1.726 + for (; *aAtts; aAtts += 2) { 1.727 + int32_t nameSpaceID; 1.728 + nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), 1.729 + getter_AddRefs(localName), &nameSpaceID); 1.730 + 1.731 + if (nameSpaceID != kNameSpaceID_None) { 1.732 + continue; 1.733 + } 1.734 + 1.735 + // Is this attribute one of the ones we care about? 1.736 + if (localName == nsGkAtoms::name) { 1.737 + name = aAtts[1]; 1.738 + } 1.739 + else if (localName == nsGkAtoms::implements) { 1.740 + // Only allow implementation of interfaces via XBL if the principal of 1.741 + // our XBL document is the system principal. 1.742 + if (nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal())) { 1.743 + mBinding->ConstructInterfaceTable(nsDependentString(aAtts[1])); 1.744 + } 1.745 + } 1.746 + } 1.747 + 1.748 + NS_NewXBLProtoImpl(mBinding, name, &mImplementation); 1.749 +} 1.750 + 1.751 +void 1.752 +nsXBLContentSink::ConstructField(const char16_t **aAtts, uint32_t aLineNumber) 1.753 +{ 1.754 + const char16_t* name = nullptr; 1.755 + const char16_t* readonly = nullptr; 1.756 + 1.757 + nsCOMPtr<nsIAtom> prefix, localName; 1.758 + for (; *aAtts; aAtts += 2) { 1.759 + int32_t nameSpaceID; 1.760 + nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), 1.761 + getter_AddRefs(localName), &nameSpaceID); 1.762 + 1.763 + if (nameSpaceID != kNameSpaceID_None) { 1.764 + continue; 1.765 + } 1.766 + 1.767 + // Is this attribute one of the ones we care about? 1.768 + if (localName == nsGkAtoms::name) { 1.769 + name = aAtts[1]; 1.770 + } 1.771 + else if (localName == nsGkAtoms::readonly) { 1.772 + readonly = aAtts[1]; 1.773 + } 1.774 + } 1.775 + 1.776 + if (name) { 1.777 + // All of our pointers are now filled in. Construct our field with all of 1.778 + // these parameters. 1.779 + mField = new nsXBLProtoImplField(name, readonly); 1.780 + if (mField) { 1.781 + mField->SetLineNumber(aLineNumber); 1.782 + AddField(mField); 1.783 + } 1.784 + } 1.785 +} 1.786 + 1.787 +void 1.788 +nsXBLContentSink::ConstructProperty(const char16_t **aAtts, uint32_t aLineNumber) 1.789 +{ 1.790 + const char16_t* name = nullptr; 1.791 + const char16_t* readonly = nullptr; 1.792 + const char16_t* onget = nullptr; 1.793 + const char16_t* onset = nullptr; 1.794 + bool exposeToUntrustedContent = false; 1.795 + 1.796 + nsCOMPtr<nsIAtom> prefix, localName; 1.797 + for (; *aAtts; aAtts += 2) { 1.798 + int32_t nameSpaceID; 1.799 + nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), 1.800 + getter_AddRefs(localName), &nameSpaceID); 1.801 + 1.802 + if (nameSpaceID != kNameSpaceID_None) { 1.803 + continue; 1.804 + } 1.805 + 1.806 + // Is this attribute one of the ones we care about? 1.807 + if (localName == nsGkAtoms::name) { 1.808 + name = aAtts[1]; 1.809 + } 1.810 + else if (localName == nsGkAtoms::readonly) { 1.811 + readonly = aAtts[1]; 1.812 + } 1.813 + else if (localName == nsGkAtoms::onget) { 1.814 + onget = aAtts[1]; 1.815 + } 1.816 + else if (localName == nsGkAtoms::onset) { 1.817 + onset = aAtts[1]; 1.818 + } 1.819 + else if (localName == nsGkAtoms::exposeToUntrustedContent && 1.820 + nsDependentString(aAtts[1]).EqualsLiteral("true")) 1.821 + { 1.822 + exposeToUntrustedContent = true; 1.823 + } 1.824 + } 1.825 + 1.826 + if (name) { 1.827 + // All of our pointers are now filled in. Construct our property with all of 1.828 + // these parameters. 1.829 + mProperty = new nsXBLProtoImplProperty(name, onget, onset, readonly, aLineNumber); 1.830 + if (exposeToUntrustedContent) { 1.831 + mProperty->SetExposeToUntrustedContent(true); 1.832 + } 1.833 + AddMember(mProperty); 1.834 + } 1.835 +} 1.836 + 1.837 +void 1.838 +nsXBLContentSink::ConstructMethod(const char16_t **aAtts) 1.839 +{ 1.840 + mMethod = nullptr; 1.841 + 1.842 + const char16_t* name = nullptr; 1.843 + const char16_t* expose = nullptr; 1.844 + if (FindValue(aAtts, nsGkAtoms::name, &name)) { 1.845 + mMethod = new nsXBLProtoImplMethod(name); 1.846 + if (FindValue(aAtts, nsGkAtoms::exposeToUntrustedContent, &expose) && 1.847 + nsDependentString(expose).EqualsLiteral("true")) 1.848 + { 1.849 + mMethod->SetExposeToUntrustedContent(true); 1.850 + } 1.851 + } 1.852 + 1.853 + if (mMethod) { 1.854 + AddMember(mMethod); 1.855 + } 1.856 +} 1.857 + 1.858 +void 1.859 +nsXBLContentSink::ConstructParameter(const char16_t **aAtts) 1.860 +{ 1.861 + if (!mMethod) 1.862 + return; 1.863 + 1.864 + const char16_t* name = nullptr; 1.865 + if (FindValue(aAtts, nsGkAtoms::name, &name)) { 1.866 + mMethod->AddParameter(nsDependentString(name)); 1.867 + } 1.868 +} 1.869 + 1.870 +nsresult 1.871 +nsXBLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount, 1.872 + nsINodeInfo* aNodeInfo, uint32_t aLineNumber, 1.873 + nsIContent** aResult, bool* aAppendContent, 1.874 + FromParser aFromParser) 1.875 +{ 1.876 +#ifdef MOZ_XUL 1.877 + if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) { 1.878 +#endif 1.879 + return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo, 1.880 + aLineNumber, aResult, 1.881 + aAppendContent, aFromParser); 1.882 +#ifdef MOZ_XUL 1.883 + } 1.884 + 1.885 + // Note that this needs to match the code in nsXBLPrototypeBinding::ReadContentNode. 1.886 + 1.887 + *aAppendContent = true; 1.888 + nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement(); 1.889 + if (!prototype) 1.890 + return NS_ERROR_OUT_OF_MEMORY; 1.891 + 1.892 + prototype->mNodeInfo = aNodeInfo; 1.893 + 1.894 + AddAttributesToXULPrototype(aAtts, aAttsCount, prototype); 1.895 + 1.896 + Element* result; 1.897 + nsresult rv = nsXULElement::Create(prototype, mDocument, false, false, &result); 1.898 + *aResult = result; 1.899 + return rv; 1.900 +#endif 1.901 +} 1.902 + 1.903 +nsresult 1.904 +nsXBLContentSink::AddAttributes(const char16_t** aAtts, 1.905 + nsIContent* aContent) 1.906 +{ 1.907 + if (aContent->IsXUL()) 1.908 + return NS_OK; // Nothing to do, since the proto already has the attrs. 1.909 + 1.910 + return nsXMLContentSink::AddAttributes(aAtts, aContent); 1.911 +} 1.912 + 1.913 +#ifdef MOZ_XUL 1.914 +nsresult 1.915 +nsXBLContentSink::AddAttributesToXULPrototype(const char16_t **aAtts, 1.916 + uint32_t aAttsCount, 1.917 + nsXULPrototypeElement* aElement) 1.918 +{ 1.919 + // Add tag attributes to the element 1.920 + nsresult rv; 1.921 + 1.922 + // Create storage for the attributes 1.923 + nsXULPrototypeAttribute* attrs = nullptr; 1.924 + if (aAttsCount > 0) { 1.925 + attrs = new nsXULPrototypeAttribute[aAttsCount]; 1.926 + if (!attrs) 1.927 + return NS_ERROR_OUT_OF_MEMORY; 1.928 + } 1.929 + 1.930 + aElement->mAttributes = attrs; 1.931 + aElement->mNumAttributes = aAttsCount; 1.932 + 1.933 + // Copy the attributes into the prototype 1.934 + nsCOMPtr<nsIAtom> prefix, localName; 1.935 + 1.936 + uint32_t i; 1.937 + for (i = 0; i < aAttsCount; ++i) { 1.938 + int32_t nameSpaceID; 1.939 + nsContentUtils::SplitExpatName(aAtts[i * 2], getter_AddRefs(prefix), 1.940 + getter_AddRefs(localName), &nameSpaceID); 1.941 + 1.942 + if (nameSpaceID == kNameSpaceID_None) { 1.943 + attrs[i].mName.SetTo(localName); 1.944 + } 1.945 + else { 1.946 + nsCOMPtr<nsINodeInfo> ni; 1.947 + ni = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID, 1.948 + nsIDOMNode::ATTRIBUTE_NODE); 1.949 + attrs[i].mName.SetTo(ni); 1.950 + } 1.951 + 1.952 + rv = aElement->SetAttrAt(i, nsDependentString(aAtts[i * 2 + 1]), 1.953 + mDocumentURI); 1.954 + NS_ENSURE_SUCCESS(rv, rv); 1.955 + } 1.956 + 1.957 + return NS_OK; 1.958 +} 1.959 +#endif