dom/xbl/nsXBLContentSink.cpp

changeset 0
6474c204b198
     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

mercurial