dom/xbl/nsXBLPrototypeBinding.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/xbl/nsXBLPrototypeBinding.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1700 @@
     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 "nsCOMPtr.h"
    1.12 +#include "nsIAtom.h"
    1.13 +#include "nsIInputStream.h"
    1.14 +#include "nsNameSpaceManager.h"
    1.15 +#include "nsIURI.h"
    1.16 +#include "nsIURL.h"
    1.17 +#include "nsIChannel.h"
    1.18 +#include "nsXPIDLString.h"
    1.19 +#include "nsReadableUtils.h"
    1.20 +#include "nsNetUtil.h"
    1.21 +#include "plstr.h"
    1.22 +#include "nsContentCreatorFunctions.h"
    1.23 +#include "nsIDocument.h"
    1.24 +#include "nsIXMLContentSink.h"
    1.25 +#include "nsContentCID.h"
    1.26 +#include "mozilla/dom/XMLDocument.h"
    1.27 +#include "nsXBLService.h"
    1.28 +#include "nsXBLBinding.h"
    1.29 +#include "nsXBLPrototypeBinding.h"
    1.30 +#include "nsXBLContentSink.h"
    1.31 +#include "xptinfo.h"
    1.32 +#include "nsIInterfaceInfoManager.h"
    1.33 +#include "nsIDocumentObserver.h"
    1.34 +#include "nsGkAtoms.h"
    1.35 +#include "nsXBLProtoImpl.h"
    1.36 +#include "nsCRT.h"
    1.37 +#include "nsContentUtils.h"
    1.38 +#include "nsTextFragment.h"
    1.39 +#include "nsTextNode.h"
    1.40 +#include "nsIInterfaceInfo.h"
    1.41 +#include "nsIScriptError.h"
    1.42 +
    1.43 +#include "nsIStyleRuleProcessor.h"
    1.44 +#include "nsXBLResourceLoader.h"
    1.45 +#include "mozilla/dom/CDATASection.h"
    1.46 +#include "mozilla/dom/Comment.h"
    1.47 +#include "mozilla/dom/Element.h"
    1.48 +
    1.49 +#ifdef MOZ_XUL
    1.50 +#include "nsXULElement.h"
    1.51 +#endif
    1.52 +
    1.53 +using namespace mozilla;
    1.54 +using namespace mozilla::dom;
    1.55 +
    1.56 +// Helper Classes =====================================================================
    1.57 +
    1.58 +// nsXBLAttributeEntry and helpers.  This class is used to efficiently handle
    1.59 +// attribute changes in anonymous content.
    1.60 +
    1.61 +class nsXBLAttributeEntry {
    1.62 +public:
    1.63 +  nsXBLAttributeEntry(nsIAtom* aSrcAtom, nsIAtom* aDstAtom,
    1.64 +                      int32_t aDstNameSpace, nsIContent* aContent)
    1.65 +    : mElement(aContent),
    1.66 +      mSrcAttribute(aSrcAtom),
    1.67 +      mDstAttribute(aDstAtom),
    1.68 +      mDstNameSpace(aDstNameSpace),
    1.69 +      mNext(nullptr) { }
    1.70 +
    1.71 +  ~nsXBLAttributeEntry() {
    1.72 +    NS_CONTENT_DELETE_LIST_MEMBER(nsXBLAttributeEntry, this, mNext);
    1.73 +  }
    1.74 +
    1.75 +  nsIAtom* GetSrcAttribute() { return mSrcAttribute; }
    1.76 +  nsIAtom* GetDstAttribute() { return mDstAttribute; }
    1.77 +  int32_t GetDstNameSpace() { return mDstNameSpace; }
    1.78 +
    1.79 +  nsIContent* GetElement() { return mElement; }
    1.80 +
    1.81 +  nsXBLAttributeEntry* GetNext() { return mNext; }
    1.82 +  void SetNext(nsXBLAttributeEntry* aEntry) { mNext = aEntry; }
    1.83 +
    1.84 +protected:
    1.85 +  nsIContent* mElement;
    1.86 +
    1.87 +  nsCOMPtr<nsIAtom> mSrcAttribute;
    1.88 +  nsCOMPtr<nsIAtom> mDstAttribute;
    1.89 +  int32_t mDstNameSpace;
    1.90 +  nsXBLAttributeEntry* mNext;
    1.91 +};
    1.92 +
    1.93 +// =============================================================================
    1.94 +
    1.95 +// Implementation /////////////////////////////////////////////////////////////////
    1.96 +
    1.97 +// Constructors/Destructors
    1.98 +nsXBLPrototypeBinding::nsXBLPrototypeBinding()
    1.99 +: mImplementation(nullptr),
   1.100 +  mBaseBinding(nullptr),
   1.101 +  mInheritStyle(true),
   1.102 +  mCheckedBaseProto(false),
   1.103 +  mKeyHandlersRegistered(false),
   1.104 +  mChromeOnlyContent(false),
   1.105 +  mResources(nullptr),
   1.106 +  mBaseNameSpaceID(kNameSpaceID_None)
   1.107 +{
   1.108 +  MOZ_COUNT_CTOR(nsXBLPrototypeBinding);
   1.109 +}
   1.110 +
   1.111 +nsresult
   1.112 +nsXBLPrototypeBinding::Init(const nsACString& aID,
   1.113 +                            nsXBLDocumentInfo* aInfo,
   1.114 +                            nsIContent* aElement,
   1.115 +                            bool aFirstBinding)
   1.116 +{
   1.117 +  nsresult rv = aInfo->DocumentURI()->Clone(getter_AddRefs(mBindingURI));
   1.118 +  NS_ENSURE_SUCCESS(rv, rv);
   1.119 +
   1.120 +  // The binding URI might be an immutable URI (e.g. for about: URIs). In that case,
   1.121 +  // we'll fail in SetRef below, but that doesn't matter much for now.
   1.122 +  if (aFirstBinding) {
   1.123 +    rv = mBindingURI->Clone(getter_AddRefs(mAlternateBindingURI));
   1.124 +    NS_ENSURE_SUCCESS(rv, rv);
   1.125 +  }
   1.126 +  mBindingURI->SetRef(aID);
   1.127 +
   1.128 +  mXBLDocInfoWeak = aInfo;
   1.129 +
   1.130 +  // aElement will be null when reading from the cache, but the element will
   1.131 +  // still be set later.
   1.132 +  if (aElement) {
   1.133 +    SetBindingElement(aElement);
   1.134 +  }
   1.135 +  return NS_OK;
   1.136 +}
   1.137 +
   1.138 +bool nsXBLPrototypeBinding::CompareBindingURI(nsIURI* aURI) const
   1.139 +{
   1.140 +  bool equal = false;
   1.141 +  mBindingURI->Equals(aURI, &equal);
   1.142 +  if (!equal && mAlternateBindingURI) {
   1.143 +    mAlternateBindingURI->Equals(aURI, &equal);
   1.144 +  }
   1.145 +  return equal;
   1.146 +}
   1.147 +
   1.148 +void
   1.149 +nsXBLPrototypeBinding::Traverse(nsCycleCollectionTraversalCallback &cb) const
   1.150 +{
   1.151 +  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "proto mBinding");
   1.152 +  cb.NoteXPCOMChild(mBinding);
   1.153 +  if (mResources) {
   1.154 +    mResources->Traverse(cb);
   1.155 +  }
   1.156 +  ImplCycleCollectionTraverse(cb, mInterfaceTable, "proto mInterfaceTable");
   1.157 +}
   1.158 +
   1.159 +void
   1.160 +nsXBLPrototypeBinding::UnlinkJSObjects()
   1.161 +{
   1.162 +  if (mImplementation)
   1.163 +    mImplementation->UnlinkJSObjects();
   1.164 +}
   1.165 +
   1.166 +void
   1.167 +nsXBLPrototypeBinding::Trace(const TraceCallbacks& aCallbacks, void *aClosure) const
   1.168 +{
   1.169 +  if (mImplementation)
   1.170 +    mImplementation->Trace(aCallbacks, aClosure);
   1.171 +}
   1.172 +
   1.173 +void
   1.174 +nsXBLPrototypeBinding::Initialize()
   1.175 +{
   1.176 +  nsIContent* content = GetImmediateChild(nsGkAtoms::content);
   1.177 +  if (content) {
   1.178 +    ConstructAttributeTable(content);
   1.179 +  }
   1.180 +}
   1.181 +
   1.182 +nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
   1.183 +{
   1.184 +  delete mImplementation;
   1.185 +  MOZ_COUNT_DTOR(nsXBLPrototypeBinding);
   1.186 +}
   1.187 +
   1.188 +void
   1.189 +nsXBLPrototypeBinding::SetBasePrototype(nsXBLPrototypeBinding* aBinding)
   1.190 +{
   1.191 +  if (mBaseBinding == aBinding)
   1.192 +    return;
   1.193 +
   1.194 +  if (mBaseBinding) {
   1.195 +    NS_ERROR("Base XBL prototype binding is already defined!");
   1.196 +    return;
   1.197 +  }
   1.198 +
   1.199 +  mBaseBinding = aBinding;
   1.200 +}
   1.201 +
   1.202 +void
   1.203 +nsXBLPrototypeBinding::SetBindingElement(nsIContent* aElement)
   1.204 +{
   1.205 +  mBinding = aElement;
   1.206 +  if (mBinding->AttrValueIs(kNameSpaceID_None, nsGkAtoms::inheritstyle,
   1.207 +                            nsGkAtoms::_false, eCaseMatters))
   1.208 +    mInheritStyle = false;
   1.209 +
   1.210 +  mChromeOnlyContent = mBinding->AttrValueIs(kNameSpaceID_None,
   1.211 +                                             nsGkAtoms::chromeOnlyContent,
   1.212 +                                             nsGkAtoms::_true, eCaseMatters);
   1.213 +}
   1.214 +
   1.215 +bool
   1.216 +nsXBLPrototypeBinding::GetAllowScripts() const
   1.217 +{
   1.218 +  return mXBLDocInfoWeak->GetScriptAccess();
   1.219 +}
   1.220 +
   1.221 +bool
   1.222 +nsXBLPrototypeBinding::LoadResources()
   1.223 +{
   1.224 +  if (mResources) {
   1.225 +    bool result;
   1.226 +    mResources->LoadResources(&result);
   1.227 +    return result;
   1.228 +  }
   1.229 +
   1.230 +  return true;
   1.231 +}
   1.232 +
   1.233 +nsresult
   1.234 +nsXBLPrototypeBinding::AddResource(nsIAtom* aResourceType, const nsAString& aSrc)
   1.235 +{
   1.236 +  if (!mResources) {
   1.237 +    mResources = new nsXBLPrototypeResources(this);
   1.238 +  }
   1.239 +
   1.240 +  mResources->AddResource(aResourceType, aSrc);
   1.241 +  return NS_OK;
   1.242 +}
   1.243 +
   1.244 +nsresult
   1.245 +nsXBLPrototypeBinding::FlushSkinSheets()
   1.246 +{
   1.247 +  if (mResources)
   1.248 +    return mResources->FlushSkinSheets();
   1.249 +  return NS_OK;
   1.250 +}
   1.251 +
   1.252 +nsresult
   1.253 +nsXBLPrototypeBinding::BindingAttached(nsIContent* aBoundElement)
   1.254 +{
   1.255 +  if (mImplementation && mImplementation->CompiledMembers() &&
   1.256 +      mImplementation->mConstructor)
   1.257 +    return mImplementation->mConstructor->Execute(aBoundElement);
   1.258 +  return NS_OK;
   1.259 +}
   1.260 +
   1.261 +nsresult
   1.262 +nsXBLPrototypeBinding::BindingDetached(nsIContent* aBoundElement)
   1.263 +{
   1.264 +  if (mImplementation && mImplementation->CompiledMembers() &&
   1.265 +      mImplementation->mDestructor)
   1.266 +    return mImplementation->mDestructor->Execute(aBoundElement);
   1.267 +  return NS_OK;
   1.268 +}
   1.269 +
   1.270 +nsXBLProtoImplAnonymousMethod*
   1.271 +nsXBLPrototypeBinding::GetConstructor()
   1.272 +{
   1.273 +  if (mImplementation)
   1.274 +    return mImplementation->mConstructor;
   1.275 +
   1.276 +  return nullptr;
   1.277 +}
   1.278 +
   1.279 +nsXBLProtoImplAnonymousMethod*
   1.280 +nsXBLPrototypeBinding::GetDestructor()
   1.281 +{
   1.282 +  if (mImplementation)
   1.283 +    return mImplementation->mDestructor;
   1.284 +
   1.285 +  return nullptr;
   1.286 +}
   1.287 +
   1.288 +nsresult
   1.289 +nsXBLPrototypeBinding::SetConstructor(nsXBLProtoImplAnonymousMethod* aMethod)
   1.290 +{
   1.291 +  if (!mImplementation)
   1.292 +    return NS_ERROR_FAILURE;
   1.293 +  mImplementation->mConstructor = aMethod;
   1.294 +  return NS_OK;
   1.295 +}
   1.296 +
   1.297 +nsresult
   1.298 +nsXBLPrototypeBinding::SetDestructor(nsXBLProtoImplAnonymousMethod* aMethod)
   1.299 +{
   1.300 +  if (!mImplementation)
   1.301 +    return NS_ERROR_FAILURE;
   1.302 +  mImplementation->mDestructor = aMethod;
   1.303 +  return NS_OK;
   1.304 +}
   1.305 +
   1.306 +nsresult
   1.307 +nsXBLPrototypeBinding::InstallImplementation(nsXBLBinding* aBinding)
   1.308 +{
   1.309 +  if (mImplementation)
   1.310 +    return mImplementation->InstallImplementation(this, aBinding);
   1.311 +  return NS_OK;
   1.312 +}
   1.313 +
   1.314 +// XXXbz this duplicates lots of SetAttrs
   1.315 +void
   1.316 +nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute,
   1.317 +                                        int32_t aNameSpaceID,
   1.318 +                                        bool aRemoveFlag, 
   1.319 +                                        nsIContent* aChangedElement,
   1.320 +                                        nsIContent* aAnonymousContent,
   1.321 +                                        bool aNotify)
   1.322 +{
   1.323 +  if (!mAttributeTable)
   1.324 +    return;
   1.325 +
   1.326 +  InnerAttributeTable *attributesNS = mAttributeTable->Get(aNameSpaceID);
   1.327 +  if (!attributesNS)
   1.328 +    return;
   1.329 +
   1.330 +  nsXBLAttributeEntry* xblAttr = attributesNS->Get(aAttribute);
   1.331 +  if (!xblAttr)
   1.332 +    return;
   1.333 +
   1.334 +  // Iterate over the elements in the array.
   1.335 +  nsCOMPtr<nsIContent> content = GetImmediateChild(nsGkAtoms::content);
   1.336 +  while (xblAttr) {
   1.337 +    nsIContent* element = xblAttr->GetElement();
   1.338 +
   1.339 +    nsCOMPtr<nsIContent> realElement = LocateInstance(aChangedElement, content,
   1.340 +                                                      aAnonymousContent,
   1.341 +                                                      element);
   1.342 +
   1.343 +    if (realElement) {
   1.344 +      // Hold a strong reference here so that the atom doesn't go away during
   1.345 +      // UnsetAttr.
   1.346 +      nsCOMPtr<nsIAtom> dstAttr = xblAttr->GetDstAttribute();
   1.347 +      int32_t dstNs = xblAttr->GetDstNameSpace();
   1.348 +
   1.349 +      if (aRemoveFlag)
   1.350 +        realElement->UnsetAttr(dstNs, dstAttr, aNotify);
   1.351 +      else {
   1.352 +        bool attrPresent = true;
   1.353 +        nsAutoString value;
   1.354 +        // Check to see if the src attribute is xbl:text.  If so, then we need to obtain the
   1.355 +        // children of the real element and get the text nodes' values.
   1.356 +        if (aAttribute == nsGkAtoms::text && aNameSpaceID == kNameSpaceID_XBL) {
   1.357 +          if (!nsContentUtils::GetNodeTextContent(aChangedElement, false, value)) {
   1.358 +            NS_RUNTIMEABORT("OOM");
   1.359 +          }
   1.360 +          value.StripChar(char16_t('\n'));
   1.361 +          value.StripChar(char16_t('\r'));
   1.362 +          nsAutoString stripVal(value);
   1.363 +          stripVal.StripWhitespace();
   1.364 +          if (stripVal.IsEmpty()) 
   1.365 +            attrPresent = false;
   1.366 +        }
   1.367 +        else {
   1.368 +          attrPresent = aChangedElement->GetAttr(aNameSpaceID, aAttribute, value);
   1.369 +        }
   1.370 +
   1.371 +        if (attrPresent)
   1.372 +          realElement->SetAttr(dstNs, dstAttr, value, aNotify);
   1.373 +      }
   1.374 +
   1.375 +      // See if we're the <html> tag in XUL, and see if value is being
   1.376 +      // set or unset on us.  We may also be a tag that is having
   1.377 +      // xbl:text set on us.
   1.378 +
   1.379 +      if ((dstAttr == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
   1.380 +          (realElement->NodeInfo()->Equals(nsGkAtoms::html,
   1.381 +                                           kNameSpaceID_XUL) &&
   1.382 +           dstAttr == nsGkAtoms::value)) {
   1.383 +        // Flush out all our kids.
   1.384 +        uint32_t childCount = realElement->GetChildCount();
   1.385 +        for (uint32_t i = 0; i < childCount; i++)
   1.386 +          realElement->RemoveChildAt(0, aNotify);
   1.387 +
   1.388 +        if (!aRemoveFlag) {
   1.389 +          // Construct a new text node and insert it.
   1.390 +          nsAutoString value;
   1.391 +          aChangedElement->GetAttr(aNameSpaceID, aAttribute, value);
   1.392 +          if (!value.IsEmpty()) {
   1.393 +            nsRefPtr<nsTextNode> textContent =
   1.394 +              new nsTextNode(realElement->NodeInfo()->NodeInfoManager());
   1.395 +
   1.396 +            textContent->SetText(value, true);
   1.397 +            realElement->AppendChildTo(textContent, true);
   1.398 +          }
   1.399 +        }
   1.400 +      }
   1.401 +    }
   1.402 +
   1.403 +    xblAttr = xblAttr->GetNext();
   1.404 +  }
   1.405 +}
   1.406 +
   1.407 +void
   1.408 +nsXBLPrototypeBinding::SetBaseTag(int32_t aNamespaceID, nsIAtom* aTag)
   1.409 +{
   1.410 +  mBaseNameSpaceID = aNamespaceID;
   1.411 +  mBaseTag = aTag;
   1.412 +}
   1.413 +
   1.414 +nsIAtom*
   1.415 +nsXBLPrototypeBinding::GetBaseTag(int32_t* aNamespaceID)
   1.416 +{
   1.417 +  if (mBaseTag) {
   1.418 +    *aNamespaceID = mBaseNameSpaceID;
   1.419 +    return mBaseTag;
   1.420 +  }
   1.421 +
   1.422 +  return nullptr;
   1.423 +}
   1.424 +
   1.425 +bool
   1.426 +nsXBLPrototypeBinding::ImplementsInterface(REFNSIID aIID) const
   1.427 +{
   1.428 +  // Check our IID table.
   1.429 +  return !!mInterfaceTable.GetWeak(aIID);
   1.430 +}
   1.431 +
   1.432 +// Internal helpers ///////////////////////////////////////////////////////////////////////
   1.433 +
   1.434 +nsIContent*
   1.435 +nsXBLPrototypeBinding::GetImmediateChild(nsIAtom* aTag)
   1.436 +{
   1.437 +  for (nsIContent* child = mBinding->GetFirstChild();
   1.438 +       child;
   1.439 +       child = child->GetNextSibling()) {
   1.440 +    if (child->NodeInfo()->Equals(aTag, kNameSpaceID_XBL)) {
   1.441 +      return child;
   1.442 +    }
   1.443 +  }
   1.444 +
   1.445 +  return nullptr;
   1.446 +}
   1.447 +
   1.448 +nsresult
   1.449 +nsXBLPrototypeBinding::InitClass(const nsCString& aClassName,
   1.450 +                                 JSContext * aContext,
   1.451 +                                 JS::Handle<JSObject*> aScriptObject,
   1.452 +                                 JS::MutableHandle<JSObject*> aClassObject,
   1.453 +                                 bool* aNew)
   1.454 +{
   1.455 +  return nsXBLBinding::DoInitJSClass(aContext, aScriptObject,
   1.456 +                                     aClassName, this, aClassObject, aNew);
   1.457 +}
   1.458 +
   1.459 +nsIContent*
   1.460 +nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
   1.461 +                                      nsIContent* aTemplRoot,
   1.462 +                                      nsIContent* aCopyRoot, 
   1.463 +                                      nsIContent* aTemplChild)
   1.464 +{
   1.465 +  // XXX We will get in trouble if the binding instantiation deviates from the template
   1.466 +  // in the prototype.
   1.467 +  if (aTemplChild == aTemplRoot || !aTemplChild)
   1.468 +    return nullptr;
   1.469 +
   1.470 +  nsIContent* templParent = aTemplChild->GetParent();
   1.471 +
   1.472 +  // We may be disconnected from our parent during cycle collection.
   1.473 +  if (!templParent)
   1.474 +    return nullptr;
   1.475 +
   1.476 +  nsIContent *copyParent =
   1.477 +    templParent == aTemplRoot ? aCopyRoot :
   1.478 +                   LocateInstance(aBoundElement, aTemplRoot, aCopyRoot, templParent);
   1.479 +
   1.480 +  if (!copyParent)
   1.481 +    return nullptr;
   1.482 +
   1.483 +  return copyParent->GetChildAt(templParent->IndexOf(aTemplChild));
   1.484 +}
   1.485 +
   1.486 +struct nsXBLAttrChangeData
   1.487 +{
   1.488 +  nsXBLPrototypeBinding* mProto;
   1.489 +  nsIContent* mBoundElement;
   1.490 +  nsIContent* mContent;
   1.491 +  int32_t mSrcNamespace;
   1.492 +
   1.493 +  nsXBLAttrChangeData(nsXBLPrototypeBinding* aProto,
   1.494 +                      nsIContent* aElt, nsIContent* aContent) 
   1.495 +  :mProto(aProto), mBoundElement(aElt), mContent(aContent) {}
   1.496 +};
   1.497 +
   1.498 +// XXXbz this duplicates lots of AttributeChanged
   1.499 +static PLDHashOperator
   1.500 +SetAttrs(nsISupports* aKey, nsXBLAttributeEntry* aEntry, void* aClosure)
   1.501 +{
   1.502 +  nsXBLAttrChangeData* changeData = static_cast<nsXBLAttrChangeData*>(aClosure);
   1.503 +
   1.504 +  nsIAtom* src = aEntry->GetSrcAttribute();
   1.505 +  int32_t srcNs = changeData->mSrcNamespace;
   1.506 +  nsAutoString value;
   1.507 +  bool attrPresent = true;
   1.508 +
   1.509 +  if (src == nsGkAtoms::text && srcNs == kNameSpaceID_XBL) {
   1.510 +    if (!nsContentUtils::GetNodeTextContent(changeData->mBoundElement, false,
   1.511 +                                       value)) {
   1.512 +      NS_RUNTIMEABORT("OOM");
   1.513 +    }
   1.514 +    value.StripChar(char16_t('\n'));
   1.515 +    value.StripChar(char16_t('\r'));
   1.516 +    nsAutoString stripVal(value);
   1.517 +    stripVal.StripWhitespace();
   1.518 +
   1.519 +    if (stripVal.IsEmpty()) 
   1.520 +      attrPresent = false;
   1.521 +  }
   1.522 +  else {
   1.523 +    attrPresent = changeData->mBoundElement->GetAttr(srcNs, src, value);
   1.524 +  }
   1.525 +
   1.526 +  if (attrPresent) {
   1.527 +    nsIContent* content =
   1.528 +      changeData->mProto->GetImmediateChild(nsGkAtoms::content);
   1.529 +
   1.530 +    nsXBLAttributeEntry* curr = aEntry;
   1.531 +    while (curr) {
   1.532 +      nsIAtom* dst = curr->GetDstAttribute();
   1.533 +      int32_t dstNs = curr->GetDstNameSpace();
   1.534 +      nsIContent* element = curr->GetElement();
   1.535 +
   1.536 +      nsIContent *realElement =
   1.537 +        changeData->mProto->LocateInstance(changeData->mBoundElement, content,
   1.538 +                                           changeData->mContent, element);
   1.539 +
   1.540 +      if (realElement) {
   1.541 +        realElement->SetAttr(dstNs, dst, value, false);
   1.542 +
   1.543 +        // XXXndeakin shouldn't this be done in lieu of SetAttr?
   1.544 +        if ((dst == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
   1.545 +            (realElement->NodeInfo()->Equals(nsGkAtoms::html,
   1.546 +                                             kNameSpaceID_XUL) &&
   1.547 +             dst == nsGkAtoms::value && !value.IsEmpty())) {
   1.548 +
   1.549 +          nsRefPtr<nsTextNode> textContent =
   1.550 +            new nsTextNode(realElement->NodeInfo()->NodeInfoManager());
   1.551 +
   1.552 +          textContent->SetText(value, false);
   1.553 +          realElement->AppendChildTo(textContent, false);
   1.554 +        }
   1.555 +      }
   1.556 +
   1.557 +      curr = curr->GetNext();
   1.558 +    }
   1.559 +  }
   1.560 +
   1.561 +  return PL_DHASH_NEXT;
   1.562 +}
   1.563 +
   1.564 +static PLDHashOperator
   1.565 +SetAttrsNS(const uint32_t &aNamespace,
   1.566 +           nsXBLPrototypeBinding::InnerAttributeTable* aXBLAttributes,
   1.567 +           void* aClosure)
   1.568 +{
   1.569 +  if (aXBLAttributes && aClosure) {
   1.570 +    nsXBLAttrChangeData* changeData = static_cast<nsXBLAttrChangeData*>(aClosure);
   1.571 +    changeData->mSrcNamespace = aNamespace;
   1.572 +    aXBLAttributes->EnumerateRead(SetAttrs, aClosure);
   1.573 +  }
   1.574 +  return PL_DHASH_NEXT;
   1.575 +}
   1.576 +
   1.577 +void
   1.578 +nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)
   1.579 +{
   1.580 +  if (mAttributeTable) {
   1.581 +    nsXBLAttrChangeData data(this, aBoundElement, aAnonymousContent);
   1.582 +    mAttributeTable->EnumerateRead(SetAttrsNS, &data);
   1.583 +  }
   1.584 +}
   1.585 +
   1.586 +nsIStyleRuleProcessor*
   1.587 +nsXBLPrototypeBinding::GetRuleProcessor()
   1.588 +{
   1.589 +  if (mResources) {
   1.590 +    return mResources->mRuleProcessor;
   1.591 +  }
   1.592 +
   1.593 +  return nullptr;
   1.594 +}
   1.595 +
   1.596 +nsXBLPrototypeResources::sheet_array_type*
   1.597 +nsXBLPrototypeBinding::GetOrCreateStyleSheets()
   1.598 +{
   1.599 +  if (!mResources) {
   1.600 +    mResources = new nsXBLPrototypeResources(this);
   1.601 +  }
   1.602 +
   1.603 +  return &mResources->mStyleSheetList;
   1.604 +}
   1.605 +
   1.606 +nsXBLPrototypeResources::sheet_array_type*
   1.607 +nsXBLPrototypeBinding::GetStyleSheets()
   1.608 +{
   1.609 +  if (mResources) {
   1.610 +    return &mResources->mStyleSheetList;
   1.611 +  }
   1.612 +
   1.613 +  return nullptr;
   1.614 +}
   1.615 +
   1.616 +void
   1.617 +nsXBLPrototypeBinding::EnsureAttributeTable()
   1.618 +{
   1.619 +  if (!mAttributeTable) {
   1.620 +    mAttributeTable = new nsClassHashtable<nsUint32HashKey, InnerAttributeTable>(4);
   1.621 +  }
   1.622 +}
   1.623 +
   1.624 +void
   1.625 +nsXBLPrototypeBinding::AddToAttributeTable(int32_t aSourceNamespaceID, nsIAtom* aSourceTag,
   1.626 +                                           int32_t aDestNamespaceID, nsIAtom* aDestTag,
   1.627 +                                           nsIContent* aContent)
   1.628 +{
   1.629 +    InnerAttributeTable* attributesNS = mAttributeTable->Get(aSourceNamespaceID);
   1.630 +    if (!attributesNS) {
   1.631 +      attributesNS = new InnerAttributeTable(4);
   1.632 +      mAttributeTable->Put(aSourceNamespaceID, attributesNS);
   1.633 +    }
   1.634 +
   1.635 +    nsXBLAttributeEntry* xblAttr =
   1.636 +      new nsXBLAttributeEntry(aSourceTag, aDestTag, aDestNamespaceID, aContent);
   1.637 +
   1.638 +    nsXBLAttributeEntry* entry = attributesNS->Get(aSourceTag);
   1.639 +    if (!entry) {
   1.640 +      attributesNS->Put(aSourceTag, xblAttr);
   1.641 +    } else {
   1.642 +      while (entry->GetNext())
   1.643 +        entry = entry->GetNext();
   1.644 +      entry->SetNext(xblAttr);
   1.645 +    }
   1.646 +}
   1.647 +
   1.648 +void
   1.649 +nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
   1.650 +{
   1.651 +  // Don't add entries for <children> elements, since those will get
   1.652 +  // removed from the DOM when we construct the insertion point table.
   1.653 +  if (!aElement->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
   1.654 +    nsAutoString inherits;
   1.655 +    aElement->GetAttr(kNameSpaceID_XBL, nsGkAtoms::inherits, inherits);
   1.656 +
   1.657 +    if (!inherits.IsEmpty()) {
   1.658 +      EnsureAttributeTable();
   1.659 +
   1.660 +      // The user specified at least one attribute.
   1.661 +      char* str = ToNewCString(inherits);
   1.662 +      char* newStr;
   1.663 +      // XXX We should use a strtok function that tokenizes PRUnichars
   1.664 +      // so that we don't have to convert from Unicode to ASCII and then back
   1.665 +
   1.666 +      char* token = nsCRT::strtok( str, ", ", &newStr );
   1.667 +      while( token != nullptr ) {
   1.668 +        // Build an atom out of this attribute.
   1.669 +        nsCOMPtr<nsIAtom> atom;
   1.670 +        int32_t atomNsID = kNameSpaceID_None;
   1.671 +        nsCOMPtr<nsIAtom> attribute;
   1.672 +        int32_t attributeNsID = kNameSpaceID_None;
   1.673 +
   1.674 +        // Figure out if this token contains a :.
   1.675 +        nsAutoString attrTok; attrTok.AssignWithConversion(token);
   1.676 +        int32_t index = attrTok.Find("=", true);
   1.677 +        nsresult rv;
   1.678 +        if (index != -1) {
   1.679 +          // This attribute maps to something different.
   1.680 +          nsAutoString left, right;
   1.681 +          attrTok.Left(left, index);
   1.682 +          attrTok.Right(right, attrTok.Length()-index-1);
   1.683 +
   1.684 +          rv = nsContentUtils::SplitQName(aElement, left, &attributeNsID,
   1.685 +                                          getter_AddRefs(attribute));
   1.686 +          if (NS_FAILED(rv))
   1.687 +            return;
   1.688 +
   1.689 +          rv = nsContentUtils::SplitQName(aElement, right, &atomNsID,
   1.690 +                                          getter_AddRefs(atom));
   1.691 +          if (NS_FAILED(rv))
   1.692 +            return;
   1.693 +        }
   1.694 +        else {
   1.695 +          nsAutoString tok;
   1.696 +          tok.AssignWithConversion(token);
   1.697 +          rv = nsContentUtils::SplitQName(aElement, tok, &atomNsID, 
   1.698 +                                          getter_AddRefs(atom));
   1.699 +          if (NS_FAILED(rv))
   1.700 +            return;
   1.701 +          attribute = atom;
   1.702 +          attributeNsID = atomNsID;
   1.703 +        }
   1.704 +
   1.705 +        AddToAttributeTable(atomNsID, atom, attributeNsID, attribute, aElement);
   1.706 +
   1.707 +        // Now remove the inherits attribute from the element so that it doesn't
   1.708 +        // show up on clones of the element.  It is used
   1.709 +        // by the template only, and we don't need it anymore.
   1.710 +        // XXXdwh Don't do this for XUL elements, since it faults them into heavyweight
   1.711 +        // elements. Should nuke from the prototype instead.
   1.712 +        // aElement->UnsetAttr(kNameSpaceID_XBL, nsGkAtoms::inherits, false);
   1.713 +
   1.714 +        token = nsCRT::strtok( newStr, ", ", &newStr );
   1.715 +      }
   1.716 +
   1.717 +      nsMemory::Free(str);
   1.718 +    }
   1.719 +  }
   1.720 +
   1.721 +  // Recur into our children.
   1.722 +  for (nsIContent* child = aElement->GetFirstChild();
   1.723 +       child;
   1.724 +       child = child->GetNextSibling()) {
   1.725 +    ConstructAttributeTable(child);
   1.726 +  }
   1.727 +}
   1.728 +
   1.729 +nsresult
   1.730 +nsXBLPrototypeBinding::ConstructInterfaceTable(const nsAString& aImpls)
   1.731 +{
   1.732 +  if (!aImpls.IsEmpty()) {
   1.733 +    // Obtain the interface info manager that can tell us the IID
   1.734 +    // for a given interface name.
   1.735 +    nsCOMPtr<nsIInterfaceInfoManager>
   1.736 +      infoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
   1.737 +    if (!infoManager)
   1.738 +      return NS_ERROR_FAILURE;
   1.739 +
   1.740 +    // The user specified at least one attribute.
   1.741 +    NS_ConvertUTF16toUTF8 utf8impl(aImpls);
   1.742 +    char* str = utf8impl.BeginWriting();
   1.743 +    char* newStr;
   1.744 +    // XXX We should use a strtok function that tokenizes PRUnichars
   1.745 +    // so that we don't have to convert from Unicode to ASCII and then back
   1.746 +
   1.747 +    char* token = nsCRT::strtok( str, ", ", &newStr );
   1.748 +    while( token != nullptr ) {
   1.749 +      // get the InterfaceInfo for the name
   1.750 +      nsCOMPtr<nsIInterfaceInfo> iinfo;
   1.751 +      infoManager->GetInfoForName(token, getter_AddRefs(iinfo));
   1.752 +
   1.753 +      if (iinfo) {
   1.754 +        // obtain an IID.
   1.755 +        const nsIID* iid = nullptr;
   1.756 +        iinfo->GetIIDShared(&iid);
   1.757 +
   1.758 +        if (iid) {
   1.759 +          // We found a valid iid.  Add it to our table.
   1.760 +          mInterfaceTable.Put(*iid, mBinding);
   1.761 +
   1.762 +          // this block adds the parent interfaces of each interface
   1.763 +          // defined in the xbl definition (implements="nsI...")
   1.764 +          nsCOMPtr<nsIInterfaceInfo> parentInfo;
   1.765 +          // if it has a parent, add it to the table
   1.766 +          while (NS_SUCCEEDED(iinfo->GetParent(getter_AddRefs(parentInfo))) && parentInfo) {
   1.767 +            // get the iid
   1.768 +            parentInfo->GetIIDShared(&iid);
   1.769 +
   1.770 +            // don't add nsISupports to the table
   1.771 +            if (!iid || iid->Equals(NS_GET_IID(nsISupports)))
   1.772 +              break;
   1.773 +
   1.774 +            // add the iid to the table
   1.775 +            mInterfaceTable.Put(*iid, mBinding);
   1.776 +
   1.777 +            // look for the next parent
   1.778 +            iinfo = parentInfo;
   1.779 +          }
   1.780 +        }
   1.781 +      }
   1.782 +
   1.783 +      token = nsCRT::strtok( newStr, ", ", &newStr );
   1.784 +    }
   1.785 +  }
   1.786 +
   1.787 +  return NS_OK;
   1.788 +}
   1.789 +
   1.790 +nsresult
   1.791 +nsXBLPrototypeBinding::AddResourceListener(nsIContent* aBoundElement)
   1.792 +{
   1.793 +  if (!mResources)
   1.794 +    return NS_ERROR_FAILURE; // Makes no sense to add a listener when the binding
   1.795 +                             // has no resources.
   1.796 +
   1.797 +  mResources->AddResourceListener(aBoundElement);
   1.798 +  return NS_OK;
   1.799 +}
   1.800 +
   1.801 +void
   1.802 +nsXBLPrototypeBinding::CreateKeyHandlers()
   1.803 +{
   1.804 +  nsXBLPrototypeHandler* curr = mPrototypeHandler;
   1.805 +  while (curr) {
   1.806 +    nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
   1.807 +    if (eventAtom == nsGkAtoms::keyup ||
   1.808 +        eventAtom == nsGkAtoms::keydown ||
   1.809 +        eventAtom == nsGkAtoms::keypress) {
   1.810 +      uint8_t phase = curr->GetPhase();
   1.811 +      uint8_t type = curr->GetType();
   1.812 +
   1.813 +      int32_t count = mKeyHandlers.Count();
   1.814 +      int32_t i;
   1.815 +      nsXBLKeyEventHandler* handler = nullptr;
   1.816 +      for (i = 0; i < count; ++i) {
   1.817 +        handler = mKeyHandlers[i];
   1.818 +        if (handler->Matches(eventAtom, phase, type))
   1.819 +          break;
   1.820 +      }
   1.821 +
   1.822 +      if (i == count) {
   1.823 +        nsRefPtr<nsXBLKeyEventHandler> newHandler;
   1.824 +        NS_NewXBLKeyEventHandler(eventAtom, phase, type,
   1.825 +                                 getter_AddRefs(newHandler));
   1.826 +        if (newHandler)
   1.827 +          mKeyHandlers.AppendObject(newHandler);
   1.828 +        handler = newHandler;
   1.829 +      }
   1.830 +
   1.831 +      if (handler)
   1.832 +        handler->AddProtoHandler(curr);
   1.833 +    }
   1.834 +
   1.835 +    curr = curr->GetNextHandler();
   1.836 +  }
   1.837 +}
   1.838 +
   1.839 +class XBLPrototypeSetupCleanup
   1.840 +{
   1.841 +public:
   1.842 +  XBLPrototypeSetupCleanup(nsXBLDocumentInfo* aDocInfo, const nsACString& aID)
   1.843 +  : mDocInfo(aDocInfo), mID(aID) {}
   1.844 +
   1.845 +  ~XBLPrototypeSetupCleanup()
   1.846 +  {
   1.847 +    if (mDocInfo) {
   1.848 +      mDocInfo->RemovePrototypeBinding(mID);
   1.849 +    }
   1.850 +  }
   1.851 +
   1.852 +  void Disconnect()
   1.853 +  {
   1.854 +    mDocInfo = nullptr;
   1.855 +  }
   1.856 +
   1.857 +  nsXBLDocumentInfo* mDocInfo;
   1.858 +  nsAutoCString mID;
   1.859 +};
   1.860 +
   1.861 +nsresult
   1.862 +nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream,
   1.863 +                            nsXBLDocumentInfo* aDocInfo,
   1.864 +                            nsIDocument* aDocument,
   1.865 +                            uint8_t aFlags)
   1.866 +{
   1.867 +  mInheritStyle = (aFlags & XBLBinding_Serialize_InheritStyle) ? true : false;
   1.868 +  mChromeOnlyContent =
   1.869 +    (aFlags & XBLBinding_Serialize_ChromeOnlyContent) ? true : false;
   1.870 +
   1.871 +  // nsXBLContentSink::ConstructBinding doesn't create a binding with an empty
   1.872 +  // id, so we don't here either.
   1.873 +  nsAutoCString id;
   1.874 +  nsresult rv = aStream->ReadCString(id);
   1.875 +
   1.876 +  NS_ENSURE_SUCCESS(rv, rv);
   1.877 +  NS_ENSURE_TRUE(!id.IsEmpty(), NS_ERROR_FAILURE);
   1.878 +
   1.879 +  nsAutoCString baseBindingURI;
   1.880 +  rv = aStream->ReadCString(baseBindingURI);
   1.881 +  NS_ENSURE_SUCCESS(rv, rv);
   1.882 +  mCheckedBaseProto = true;
   1.883 +
   1.884 +  if (!baseBindingURI.IsEmpty()) {
   1.885 +    rv = NS_NewURI(getter_AddRefs(mBaseBindingURI), baseBindingURI);
   1.886 +    NS_ENSURE_SUCCESS(rv, rv);
   1.887 +  }
   1.888 +
   1.889 +  rv = ReadNamespace(aStream, mBaseNameSpaceID);
   1.890 +  NS_ENSURE_SUCCESS(rv, rv);
   1.891 +
   1.892 +  nsAutoString baseTag;
   1.893 +  rv = aStream->ReadString(baseTag);
   1.894 +  NS_ENSURE_SUCCESS(rv, rv);
   1.895 +  if (!baseTag.IsEmpty()) {
   1.896 +    mBaseTag = do_GetAtom(baseTag);
   1.897 +  }
   1.898 +
   1.899 +  aDocument->CreateElem(NS_LITERAL_STRING("binding"), nullptr, kNameSpaceID_XBL,
   1.900 +                        getter_AddRefs(mBinding));
   1.901 +
   1.902 +  nsCOMPtr<nsIContent> child;
   1.903 +  rv = ReadContentNode(aStream, aDocument, aDocument->NodeInfoManager(), getter_AddRefs(child));
   1.904 +  NS_ENSURE_SUCCESS(rv, rv);
   1.905 +
   1.906 +  Element* rootElement = aDocument->GetRootElement();
   1.907 +  if (rootElement)
   1.908 +    rootElement->AppendChildTo(mBinding, false);
   1.909 +
   1.910 +  if (child) {
   1.911 +    mBinding->AppendChildTo(child, false);
   1.912 +  }
   1.913 +
   1.914 +  uint32_t interfaceCount;
   1.915 +  rv = aStream->Read32(&interfaceCount);
   1.916 +  NS_ENSURE_SUCCESS(rv, rv);
   1.917 +
   1.918 +  for (; interfaceCount > 0; interfaceCount--) {
   1.919 +    nsIID iid;
   1.920 +    aStream->ReadID(&iid);
   1.921 +    mInterfaceTable.Put(iid, mBinding);
   1.922 +  }
   1.923 +
   1.924 +  AutoSafeJSContext cx;
   1.925 +  JS::Rooted<JSObject*> compilationGlobal(cx, xpc::GetCompilationScope());
   1.926 +  NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED);
   1.927 +  JSAutoCompartment ac(cx, compilationGlobal);
   1.928 +
   1.929 +  bool isFirstBinding = aFlags & XBLBinding_Serialize_IsFirstBinding;
   1.930 +  rv = Init(id, aDocInfo, nullptr, isFirstBinding);
   1.931 +  NS_ENSURE_SUCCESS(rv, rv);
   1.932 +
   1.933 +  // We need to set the prototype binding before reading the nsXBLProtoImpl,
   1.934 +  // as it may be retrieved within.
   1.935 +  rv = aDocInfo->SetPrototypeBinding(id, this);
   1.936 +  NS_ENSURE_SUCCESS(rv, rv);
   1.937 +
   1.938 +  XBLPrototypeSetupCleanup cleanup(aDocInfo, id);  
   1.939 +
   1.940 +  nsAutoCString className;
   1.941 +  rv = aStream->ReadCString(className);
   1.942 +  NS_ENSURE_SUCCESS(rv, rv);
   1.943 +
   1.944 +  if (!className.IsEmpty()) {
   1.945 +    nsXBLProtoImpl* impl; // NS_NewXBLProtoImpl will set mImplementation for us
   1.946 +    NS_NewXBLProtoImpl(this, NS_ConvertUTF8toUTF16(className).get(), &impl);
   1.947 +
   1.948 +    // This needs to happen after SetPrototypeBinding as calls are made to
   1.949 +    // retrieve the mapped bindings from within here. However, if an error
   1.950 +    // occurs, the mapping should be removed again so that we don't keep an
   1.951 +    // invalid binding around.
   1.952 +    rv = mImplementation->Read(aStream, this);
   1.953 +    NS_ENSURE_SUCCESS(rv, rv);
   1.954 +  }
   1.955 +
   1.956 +  // Next read in the handlers.
   1.957 +  nsXBLPrototypeHandler* previousHandler = nullptr;
   1.958 +
   1.959 +  do {
   1.960 +    XBLBindingSerializeDetails type;
   1.961 +    rv = aStream->Read8(&type);
   1.962 +    NS_ENSURE_SUCCESS(rv, rv);
   1.963 +
   1.964 +    if (type == XBLBinding_Serialize_NoMoreItems)
   1.965 +      break;
   1.966 +
   1.967 +    NS_ASSERTION((type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Handler,
   1.968 +                 "invalid handler type");
   1.969 +
   1.970 +    nsXBLPrototypeHandler* handler = new nsXBLPrototypeHandler(this);
   1.971 +    rv = handler->Read(aStream);
   1.972 +    if (NS_FAILED(rv)) {
   1.973 +      delete handler;
   1.974 +      return rv;
   1.975 +    }
   1.976 +
   1.977 +    if (previousHandler) {
   1.978 +      previousHandler->SetNextHandler(handler);
   1.979 +    }
   1.980 +    else {
   1.981 +      SetPrototypeHandlers(handler);
   1.982 +    }
   1.983 +    previousHandler = handler;
   1.984 +  } while (1);
   1.985 +
   1.986 +  if (mBinding) {
   1.987 +    while (true) {
   1.988 +      XBLBindingSerializeDetails type;
   1.989 +      rv = aStream->Read8(&type);
   1.990 +      NS_ENSURE_SUCCESS(rv, rv);
   1.991 +
   1.992 +      if (type != XBLBinding_Serialize_Attribute) {
   1.993 +        break;
   1.994 +      }
   1.995 +
   1.996 +      int32_t attrNamespace;
   1.997 +      rv = ReadNamespace(aStream, attrNamespace);
   1.998 +      NS_ENSURE_SUCCESS(rv, rv);
   1.999 +
  1.1000 +      nsAutoString attrPrefix, attrName, attrValue;
  1.1001 +      rv = aStream->ReadString(attrPrefix);
  1.1002 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1003 +
  1.1004 +      rv = aStream->ReadString(attrName);
  1.1005 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1006 +
  1.1007 +      rv = aStream->ReadString(attrValue);
  1.1008 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1009 +
  1.1010 +      nsCOMPtr<nsIAtom> atomPrefix = do_GetAtom(attrPrefix);
  1.1011 +      nsCOMPtr<nsIAtom> atomName = do_GetAtom(attrName);
  1.1012 +      mBinding->SetAttr(attrNamespace, atomName, atomPrefix, attrValue, false);
  1.1013 +    }
  1.1014 +  }
  1.1015 +
  1.1016 +  // Finally, read in the resources.
  1.1017 +  while (true) {
  1.1018 +    XBLBindingSerializeDetails type;
  1.1019 +    rv = aStream->Read8(&type);
  1.1020 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1021 +
  1.1022 +    if (type == XBLBinding_Serialize_NoMoreItems)
  1.1023 +      break;
  1.1024 +
  1.1025 +    NS_ASSERTION((type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Stylesheet ||
  1.1026 +                 (type & XBLBinding_Serialize_Mask) == XBLBinding_Serialize_Image, "invalid resource type");
  1.1027 +
  1.1028 +    nsAutoString src;
  1.1029 +    rv = aStream->ReadString(src);
  1.1030 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1031 +
  1.1032 +    AddResource(type == XBLBinding_Serialize_Stylesheet ? nsGkAtoms::stylesheet :
  1.1033 +                                                          nsGkAtoms::image, src);
  1.1034 +  }
  1.1035 +
  1.1036 +  if (isFirstBinding) {
  1.1037 +    aDocInfo->SetFirstPrototypeBinding(this);
  1.1038 +  }
  1.1039 +
  1.1040 +  cleanup.Disconnect();
  1.1041 +  return NS_OK;
  1.1042 +}
  1.1043 +
  1.1044 +// static
  1.1045 +nsresult
  1.1046 +nsXBLPrototypeBinding::ReadNewBinding(nsIObjectInputStream* aStream,
  1.1047 +                                      nsXBLDocumentInfo* aDocInfo,
  1.1048 +                                      nsIDocument* aDocument,
  1.1049 +                                      uint8_t aFlags)
  1.1050 +{
  1.1051 +  // If the Read() succeeds, |binding| will end up being owned by aDocInfo's
  1.1052 +  // binding table. Otherwise, we must manually delete it.
  1.1053 +  nsXBLPrototypeBinding* binding = new nsXBLPrototypeBinding();
  1.1054 +  nsresult rv = binding->Read(aStream, aDocInfo, aDocument, aFlags);
  1.1055 +  if (NS_FAILED(rv)) {
  1.1056 +    delete binding;
  1.1057 +  }
  1.1058 +  return rv;
  1.1059 +}
  1.1060 +
  1.1061 +static PLDHashOperator
  1.1062 +WriteInterfaceID(const nsIID& aKey, nsIContent* aData, void* aClosure)
  1.1063 +{
  1.1064 +  // We can just write out the ids. The cache will be invalidated when a
  1.1065 +  // different build is used, so we don't need to worry about ids changing.
  1.1066 +  static_cast<nsIObjectOutputStream *>(aClosure)->WriteID(aKey);
  1.1067 +  return PL_DHASH_NEXT;
  1.1068 +}
  1.1069 +
  1.1070 +nsresult
  1.1071 +nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
  1.1072 +{
  1.1073 +  // This writes out the binding. Note that mCheckedBaseProto,
  1.1074 +  // mKeyHandlersRegistered and mKeyHandlers are not serialized as they are
  1.1075 +  // computed on demand.
  1.1076 +
  1.1077 +  AutoSafeJSContext cx;
  1.1078 +  JS::Rooted<JSObject*> compilationGlobal(cx, xpc::GetCompilationScope());
  1.1079 +  NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED);
  1.1080 +  JSAutoCompartment ac(cx, compilationGlobal);
  1.1081 +
  1.1082 +  uint8_t flags = mInheritStyle ? XBLBinding_Serialize_InheritStyle : 0;
  1.1083 +
  1.1084 +  // mAlternateBindingURI is only set on the first binding.
  1.1085 +  if (mAlternateBindingURI) {
  1.1086 +    flags |= XBLBinding_Serialize_IsFirstBinding;
  1.1087 +  }
  1.1088 +
  1.1089 +  if (mChromeOnlyContent) {
  1.1090 +    flags |= XBLBinding_Serialize_ChromeOnlyContent;
  1.1091 +  }
  1.1092 +
  1.1093 +  nsresult rv = aStream->Write8(flags);
  1.1094 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1095 +
  1.1096 +  nsAutoCString id;
  1.1097 +  mBindingURI->GetRef(id);
  1.1098 +  rv = aStream->WriteStringZ(id.get());
  1.1099 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1100 +
  1.1101 +  // write out the extends and display attribute values
  1.1102 +  nsAutoCString extends;
  1.1103 +  ResolveBaseBinding();
  1.1104 +  if (mBaseBindingURI)
  1.1105 +    mBaseBindingURI->GetSpec(extends);
  1.1106 +
  1.1107 +  rv = aStream->WriteStringZ(extends.get());
  1.1108 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1109 +
  1.1110 +  rv = WriteNamespace(aStream, mBaseNameSpaceID);
  1.1111 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1112 +
  1.1113 +  nsAutoString baseTag;
  1.1114 +  if (mBaseTag) {
  1.1115 +    mBaseTag->ToString(baseTag);
  1.1116 +  }
  1.1117 +  rv = aStream->WriteWStringZ(baseTag.get());
  1.1118 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1119 +
  1.1120 +  nsIContent* content = GetImmediateChild(nsGkAtoms::content);
  1.1121 +  if (content) {
  1.1122 +    rv = WriteContentNode(aStream, content);
  1.1123 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1124 +  }
  1.1125 +  else {
  1.1126 +    // Write a marker to indicate that there is no content.
  1.1127 +    rv = aStream->Write8(XBLBinding_Serialize_NoContent);
  1.1128 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1129 +  }
  1.1130 +
  1.1131 +  // Enumerate and write out the implemented interfaces.
  1.1132 +  rv = aStream->Write32(mInterfaceTable.Count());
  1.1133 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1134 +
  1.1135 +  mInterfaceTable.EnumerateRead(WriteInterfaceID, aStream);
  1.1136 +
  1.1137 +  // Write out the implementation details.
  1.1138 +  if (mImplementation) {
  1.1139 +    rv = mImplementation->Write(aStream, this);
  1.1140 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1141 +  }
  1.1142 +  else {
  1.1143 +    // Write out an empty classname. This indicates that the binding does not
  1.1144 +    // define an implementation.
  1.1145 +    rv = aStream->WriteWStringZ(EmptyString().get());
  1.1146 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1147 +  }
  1.1148 +
  1.1149 +  // Write out the handlers.
  1.1150 +  nsXBLPrototypeHandler* handler = mPrototypeHandler;
  1.1151 +  while (handler) {
  1.1152 +    rv = handler->Write(aStream);
  1.1153 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1154 +
  1.1155 +    handler = handler->GetNextHandler();
  1.1156 +  }
  1.1157 +
  1.1158 +  aStream->Write8(XBLBinding_Serialize_NoMoreItems);
  1.1159 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1160 +
  1.1161 +  if (mBinding) {
  1.1162 +    uint32_t attributes = mBinding->GetAttrCount();
  1.1163 +    nsAutoString attrValue;
  1.1164 +    for (uint32_t i = 0; i < attributes; ++i) {
  1.1165 +      const nsAttrName* attr = mBinding->GetAttrNameAt(i);
  1.1166 +      nsDependentAtomString attrName = attr->LocalName();
  1.1167 +      mBinding->GetAttr(attr->NamespaceID(), attr->LocalName(), attrValue);
  1.1168 +      rv = aStream->Write8(XBLBinding_Serialize_Attribute);
  1.1169 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1170 +
  1.1171 +      rv = WriteNamespace(aStream, attr->NamespaceID());
  1.1172 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1173 +
  1.1174 +      nsIAtom* prefix = attr->GetPrefix();
  1.1175 +      nsAutoString prefixString;
  1.1176 +      if (prefix) {
  1.1177 +        prefix->ToString(prefixString);
  1.1178 +      }
  1.1179 +
  1.1180 +      rv = aStream->WriteWStringZ(prefixString.get());
  1.1181 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1182 +
  1.1183 +      rv = aStream->WriteWStringZ(attrName.get());
  1.1184 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1185 +
  1.1186 +      rv = aStream->WriteWStringZ(attrValue.get());
  1.1187 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1188 +    }
  1.1189 +  }
  1.1190 +
  1.1191 +  aStream->Write8(XBLBinding_Serialize_NoMoreItems);
  1.1192 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1193 +
  1.1194 +  // Write out the resources
  1.1195 +  if (mResources) {
  1.1196 +    rv = mResources->Write(aStream);
  1.1197 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1198 +  }
  1.1199 +
  1.1200 +  // Write out an end mark at the end.
  1.1201 +  return aStream->Write8(XBLBinding_Serialize_NoMoreItems);
  1.1202 +}
  1.1203 +
  1.1204 +nsresult
  1.1205 +nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
  1.1206 +                                       nsIDocument* aDocument,
  1.1207 +                                       nsNodeInfoManager* aNim,
  1.1208 +                                       nsIContent** aContent)
  1.1209 +{
  1.1210 +  *aContent = nullptr;
  1.1211 +
  1.1212 +  int32_t namespaceID;
  1.1213 +  nsresult rv = ReadNamespace(aStream, namespaceID);
  1.1214 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1215 +
  1.1216 +  // There is no content to read so just return.
  1.1217 +  if (namespaceID == XBLBinding_Serialize_NoContent)
  1.1218 +    return NS_OK;
  1.1219 +
  1.1220 +  nsCOMPtr<nsIContent> content;
  1.1221 +
  1.1222 +  // If this is a text type, just read the string and return.
  1.1223 +  if (namespaceID == XBLBinding_Serialize_TextNode ||
  1.1224 +      namespaceID == XBLBinding_Serialize_CDATANode ||
  1.1225 +      namespaceID == XBLBinding_Serialize_CommentNode) {
  1.1226 +    switch (namespaceID) {
  1.1227 +      case XBLBinding_Serialize_TextNode:
  1.1228 +        content = new nsTextNode(aNim);
  1.1229 +        break;
  1.1230 +      case XBLBinding_Serialize_CDATANode:
  1.1231 +        content = new CDATASection(aNim);
  1.1232 +        break;
  1.1233 +      case XBLBinding_Serialize_CommentNode:
  1.1234 +        content = new Comment(aNim);
  1.1235 +        break;
  1.1236 +      default:
  1.1237 +        break;
  1.1238 +    }
  1.1239 +
  1.1240 +    nsAutoString text;
  1.1241 +    rv = aStream->ReadString(text);
  1.1242 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1243 +
  1.1244 +    content->SetText(text, false);
  1.1245 +    content.swap(*aContent);
  1.1246 +    return NS_OK;
  1.1247 +  }
  1.1248 +
  1.1249 +  // Otherwise, it's an element, so read its tag, attributes and children.
  1.1250 +  nsAutoString prefix, tag;
  1.1251 +  rv = aStream->ReadString(prefix);
  1.1252 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1253 +
  1.1254 +  nsCOMPtr<nsIAtom> prefixAtom;
  1.1255 +  if (!prefix.IsEmpty())
  1.1256 +    prefixAtom = do_GetAtom(prefix);
  1.1257 +
  1.1258 +  rv = aStream->ReadString(tag);
  1.1259 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1260 +
  1.1261 +  nsCOMPtr<nsIAtom> tagAtom = do_GetAtom(tag);
  1.1262 +  nsCOMPtr<nsINodeInfo> nodeInfo =
  1.1263 +    aNim->GetNodeInfo(tagAtom, prefixAtom, namespaceID, nsIDOMNode::ELEMENT_NODE);
  1.1264 +
  1.1265 +  uint32_t attrCount;
  1.1266 +  rv = aStream->Read32(&attrCount);
  1.1267 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1268 +
  1.1269 +  // Create XUL prototype elements, or regular elements for other namespaces.
  1.1270 +  // This needs to match the code in nsXBLContentSink::CreateElement.
  1.1271 +#ifdef MOZ_XUL
  1.1272 +  if (namespaceID == kNameSpaceID_XUL) {
  1.1273 +    nsIURI* documentURI = aDocument->GetDocumentURI();
  1.1274 +
  1.1275 +    nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
  1.1276 +    NS_ENSURE_TRUE(prototype, NS_ERROR_OUT_OF_MEMORY);
  1.1277 +
  1.1278 +    prototype->mNodeInfo = nodeInfo;
  1.1279 +
  1.1280 +    nsXULPrototypeAttribute* attrs = nullptr;
  1.1281 +    if (attrCount > 0) {
  1.1282 +      attrs = new nsXULPrototypeAttribute[attrCount];
  1.1283 +    }
  1.1284 +
  1.1285 +    prototype->mAttributes = attrs;
  1.1286 +    prototype->mNumAttributes = attrCount;
  1.1287 +
  1.1288 +    for (uint32_t i = 0; i < attrCount; i++) {
  1.1289 +      rv = ReadNamespace(aStream, namespaceID);
  1.1290 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1291 +
  1.1292 +      nsAutoString prefix, name, val;
  1.1293 +      rv = aStream->ReadString(prefix);
  1.1294 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1295 +      rv = aStream->ReadString(name);
  1.1296 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1297 +      rv = aStream->ReadString(val);
  1.1298 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1299 +
  1.1300 +      nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(name);
  1.1301 +      if (namespaceID == kNameSpaceID_None) {
  1.1302 +        attrs[i].mName.SetTo(nameAtom);
  1.1303 +      }
  1.1304 +      else {
  1.1305 +        nsCOMPtr<nsIAtom> prefixAtom;
  1.1306 +        if (!prefix.IsEmpty())
  1.1307 +          prefixAtom = do_GetAtom(prefix);
  1.1308 +
  1.1309 +        nsCOMPtr<nsINodeInfo> ni =
  1.1310 +          aNim->GetNodeInfo(nameAtom, prefixAtom,
  1.1311 +                            namespaceID, nsIDOMNode::ATTRIBUTE_NODE);
  1.1312 +        attrs[i].mName.SetTo(ni);
  1.1313 +      }
  1.1314 +
  1.1315 +      rv = prototype->SetAttrAt(i, val, documentURI);
  1.1316 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1317 +    }
  1.1318 +
  1.1319 +    nsCOMPtr<Element> result;
  1.1320 +    nsresult rv =
  1.1321 +      nsXULElement::Create(prototype, aDocument, false, false, getter_AddRefs(result));
  1.1322 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1323 +    content = result;
  1.1324 +  }
  1.1325 +  else {
  1.1326 +#endif
  1.1327 +    nsCOMPtr<Element> element;
  1.1328 +    NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), NOT_FROM_PARSER);
  1.1329 +    content = element;
  1.1330 +
  1.1331 +    for (uint32_t i = 0; i < attrCount; i++) {
  1.1332 +      rv = ReadNamespace(aStream, namespaceID);
  1.1333 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1334 +
  1.1335 +      nsAutoString prefix, name, val;
  1.1336 +      rv = aStream->ReadString(prefix);
  1.1337 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1338 +      rv = aStream->ReadString(name);
  1.1339 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1340 +      rv = aStream->ReadString(val);
  1.1341 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1342 +
  1.1343 +      nsCOMPtr<nsIAtom> prefixAtom;
  1.1344 +      if (!prefix.IsEmpty())
  1.1345 +        prefixAtom = do_GetAtom(prefix);
  1.1346 +
  1.1347 +      nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(name);
  1.1348 +      content->SetAttr(namespaceID, nameAtom, prefixAtom, val, false);
  1.1349 +    }
  1.1350 +
  1.1351 +#ifdef MOZ_XUL
  1.1352 +  }
  1.1353 +#endif
  1.1354 +
  1.1355 +  // Now read the attribute forwarding entries (xbl:inherits)
  1.1356 +
  1.1357 +  int32_t srcNamespaceID, destNamespaceID;
  1.1358 +  rv = ReadNamespace(aStream, srcNamespaceID);
  1.1359 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1360 +
  1.1361 +  while (srcNamespaceID != XBLBinding_Serialize_NoMoreAttributes) {
  1.1362 +    nsAutoString srcAttribute, destAttribute;
  1.1363 +    rv = aStream->ReadString(srcAttribute);
  1.1364 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1365 +    rv = ReadNamespace(aStream, destNamespaceID);
  1.1366 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1367 +    rv = aStream->ReadString(destAttribute);
  1.1368 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1369 +
  1.1370 +    nsCOMPtr<nsIAtom> srcAtom = do_GetAtom(srcAttribute);
  1.1371 +    nsCOMPtr<nsIAtom> destAtom = do_GetAtom(destAttribute);
  1.1372 +
  1.1373 +    EnsureAttributeTable();
  1.1374 +    AddToAttributeTable(srcNamespaceID, srcAtom, destNamespaceID, destAtom, content);
  1.1375 +
  1.1376 +    rv = ReadNamespace(aStream, srcNamespaceID);
  1.1377 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1378 +  }
  1.1379 +
  1.1380 +  // Finally, read in the child nodes.
  1.1381 +  uint32_t childCount;
  1.1382 +  rv = aStream->Read32(&childCount);
  1.1383 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1384 +
  1.1385 +  for (uint32_t i = 0; i < childCount; i++) {
  1.1386 +    nsCOMPtr<nsIContent> child;
  1.1387 +    ReadContentNode(aStream, aDocument, aNim, getter_AddRefs(child));
  1.1388 +
  1.1389 +    // Child may be null if this was a comment for example and can just be ignored.
  1.1390 +    if (child) {
  1.1391 +      content->AppendChildTo(child, false);
  1.1392 +    }
  1.1393 +  }
  1.1394 +
  1.1395 +  content.swap(*aContent);
  1.1396 +  return NS_OK;
  1.1397 +}
  1.1398 +
  1.1399 +// This structure holds information about a forwarded attribute that needs to be
  1.1400 +// written out. This is used because we need several fields passed within the
  1.1401 +// enumeration closure.
  1.1402 +struct WriteAttributeData
  1.1403 +{
  1.1404 +  nsXBLPrototypeBinding* binding;
  1.1405 +  nsIObjectOutputStream* stream;
  1.1406 +  nsIContent* content;
  1.1407 +  int32_t srcNamespace;
  1.1408 +
  1.1409 +  WriteAttributeData(nsXBLPrototypeBinding* aBinding,
  1.1410 +                     nsIObjectOutputStream* aStream,
  1.1411 +                     nsIContent* aContent)
  1.1412 +    : binding(aBinding), stream(aStream), content(aContent)
  1.1413 +  { }
  1.1414 +};
  1.1415 +
  1.1416 +static PLDHashOperator
  1.1417 +WriteAttribute(nsISupports* aKey, nsXBLAttributeEntry* aEntry, void* aClosure)
  1.1418 +{
  1.1419 +  WriteAttributeData* data = static_cast<WriteAttributeData *>(aClosure);
  1.1420 +  nsIObjectOutputStream* stream = data->stream;
  1.1421 +  const int32_t srcNamespace = data->srcNamespace;
  1.1422 +
  1.1423 +  do {
  1.1424 +    if (aEntry->GetElement() == data->content) {
  1.1425 +      data->binding->WriteNamespace(stream, srcNamespace);
  1.1426 +      stream->WriteWStringZ(nsDependentAtomString(aEntry->GetSrcAttribute()).get());
  1.1427 +      data->binding->WriteNamespace(stream, aEntry->GetDstNameSpace());
  1.1428 +      stream->WriteWStringZ(nsDependentAtomString(aEntry->GetDstAttribute()).get());
  1.1429 +    }
  1.1430 +
  1.1431 +    aEntry = aEntry->GetNext();
  1.1432 +  } while (aEntry);
  1.1433 +
  1.1434 +  return PL_DHASH_NEXT;
  1.1435 +}
  1.1436 +
  1.1437 +// WriteAttributeNS is the callback to enumerate over the attribute
  1.1438 +// forwarding entries. Since these are stored in a hash of hashes,
  1.1439 +// we need to iterate over the inner hashes, calling WriteAttribute
  1.1440 +// to do the actual work.
  1.1441 +static PLDHashOperator
  1.1442 +WriteAttributeNS(const uint32_t &aNamespace,
  1.1443 +                 nsXBLPrototypeBinding::InnerAttributeTable* aXBLAttributes,
  1.1444 +                 void* aClosure)
  1.1445 +{
  1.1446 +  WriteAttributeData* data = static_cast<WriteAttributeData *>(aClosure);
  1.1447 +  data->srcNamespace = aNamespace;
  1.1448 +  aXBLAttributes->EnumerateRead(WriteAttribute, data);
  1.1449 +
  1.1450 +  return PL_DHASH_NEXT;
  1.1451 +}
  1.1452 +
  1.1453 +nsresult
  1.1454 +nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
  1.1455 +                                        nsIContent* aNode)
  1.1456 +{
  1.1457 +  nsresult rv;
  1.1458 +
  1.1459 +  if (!aNode->IsElement()) {
  1.1460 +    // Text is writen out as a single byte for the type, followed by the text.
  1.1461 +    uint8_t type = XBLBinding_Serialize_NoContent;
  1.1462 +    switch (aNode->NodeType()) {
  1.1463 +      case nsIDOMNode::TEXT_NODE:
  1.1464 +        type = XBLBinding_Serialize_TextNode;
  1.1465 +        break;
  1.1466 +      case nsIDOMNode::CDATA_SECTION_NODE:
  1.1467 +        type = XBLBinding_Serialize_CDATANode;
  1.1468 +        break;
  1.1469 +      case nsIDOMNode::COMMENT_NODE:
  1.1470 +        type = XBLBinding_Serialize_CommentNode;
  1.1471 +        break;
  1.1472 +      default:
  1.1473 +        break;
  1.1474 +    }
  1.1475 +
  1.1476 +    rv = aStream->Write8(type);
  1.1477 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1478 +
  1.1479 +    nsAutoString content;
  1.1480 +    aNode->GetText()->AppendTo(content);
  1.1481 +    return aStream->WriteWStringZ(content.get());
  1.1482 +  }
  1.1483 +
  1.1484 +  // Otherwise, this is an element.
  1.1485 +
  1.1486 +  // Write the namespace id followed by the tag name
  1.1487 +  rv = WriteNamespace(aStream, aNode->GetNameSpaceID());
  1.1488 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1489 +
  1.1490 +  nsAutoString prefixStr;
  1.1491 +  aNode->NodeInfo()->GetPrefix(prefixStr);
  1.1492 +  rv = aStream->WriteWStringZ(prefixStr.get());
  1.1493 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1494 +
  1.1495 +  rv = aStream->WriteWStringZ(nsDependentAtomString(aNode->Tag()).get());
  1.1496 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1497 +
  1.1498 +  // Write attributes
  1.1499 +  uint32_t count = aNode->GetAttrCount();
  1.1500 +  rv = aStream->Write32(count);
  1.1501 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1502 +
  1.1503 +  uint32_t i;
  1.1504 +  for (i = 0; i < count; i++) {
  1.1505 +    // Write out the namespace id, the namespace prefix, the local tag name,
  1.1506 +    // and the value, in that order.
  1.1507 +
  1.1508 +    const nsAttrName* attr = aNode->GetAttrNameAt(i);
  1.1509 +
  1.1510 +    // XXXndeakin don't write out xbl:inherits?
  1.1511 +    int32_t namespaceID = attr->NamespaceID();
  1.1512 +    rv = WriteNamespace(aStream, namespaceID);
  1.1513 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1514 +
  1.1515 +    nsAutoString prefixStr;
  1.1516 +    nsIAtom* prefix = attr->GetPrefix();
  1.1517 +    if (prefix)
  1.1518 +      prefix->ToString(prefixStr);
  1.1519 +    rv = aStream->WriteWStringZ(prefixStr.get());
  1.1520 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1521 +
  1.1522 +    rv = aStream->WriteWStringZ(nsDependentAtomString(attr->LocalName()).get());
  1.1523 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1524 +
  1.1525 +    nsAutoString val;
  1.1526 +    aNode->GetAttr(attr->NamespaceID(), attr->LocalName(), val);
  1.1527 +    rv = aStream->WriteWStringZ(val.get());
  1.1528 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1529 +  }
  1.1530 +
  1.1531 +  // Write out the attribute fowarding information
  1.1532 +  if (mAttributeTable) {
  1.1533 +    WriteAttributeData data(this, aStream, aNode);
  1.1534 +    mAttributeTable->EnumerateRead(WriteAttributeNS, &data);
  1.1535 +  }
  1.1536 +  rv = aStream->Write8(XBLBinding_Serialize_NoMoreAttributes);
  1.1537 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1538 +
  1.1539 +  // Finally, write out the child nodes.
  1.1540 +  count = aNode->GetChildCount();
  1.1541 +  rv = aStream->Write32(count);
  1.1542 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1543 +
  1.1544 +  for (i = 0; i < count; i++) {
  1.1545 +    rv = WriteContentNode(aStream, aNode->GetChildAt(i));
  1.1546 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1547 +  }
  1.1548 +
  1.1549 +  return NS_OK;
  1.1550 +}
  1.1551 +
  1.1552 +nsresult
  1.1553 +nsXBLPrototypeBinding::ReadNamespace(nsIObjectInputStream* aStream,
  1.1554 +                                     int32_t& aNameSpaceID)
  1.1555 +{
  1.1556 +  uint8_t namespaceID;
  1.1557 +  nsresult rv = aStream->Read8(&namespaceID);
  1.1558 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1559 +
  1.1560 +  if (namespaceID == XBLBinding_Serialize_CustomNamespace) {
  1.1561 +    nsAutoString namesp;
  1.1562 +    rv = aStream->ReadString(namesp);
  1.1563 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1564 +
  1.1565 +    nsContentUtils::NameSpaceManager()->RegisterNameSpace(namesp, aNameSpaceID);
  1.1566 +  }
  1.1567 +  else {
  1.1568 +    aNameSpaceID = namespaceID;
  1.1569 +  }
  1.1570 +
  1.1571 +  return NS_OK;
  1.1572 +}
  1.1573 +
  1.1574 +nsresult
  1.1575 +nsXBLPrototypeBinding::WriteNamespace(nsIObjectOutputStream* aStream,
  1.1576 +                                      int32_t aNameSpaceID)
  1.1577 +{
  1.1578 +  // Namespaces are stored as a single byte id for well-known namespaces.
  1.1579 +  // This saves time and space as other namespaces aren't very common in
  1.1580 +  // XBL. If another namespace is used however, the namespace id will be
  1.1581 +  // XBLBinding_Serialize_CustomNamespace and the string namespace written
  1.1582 +  // out directly afterwards.
  1.1583 +  nsresult rv;
  1.1584 +
  1.1585 +  if (aNameSpaceID <= kNameSpaceID_LastBuiltin) {
  1.1586 +    rv = aStream->Write8((int8_t)aNameSpaceID);
  1.1587 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1588 +  }
  1.1589 +  else {
  1.1590 +    rv = aStream->Write8(XBLBinding_Serialize_CustomNamespace);
  1.1591 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1592 +
  1.1593 +    nsAutoString namesp;
  1.1594 +    nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, namesp);
  1.1595 +    aStream->WriteWStringZ(namesp.get());
  1.1596 +  }
  1.1597 +
  1.1598 +  return NS_OK;
  1.1599 +}
  1.1600 +
  1.1601 +
  1.1602 +bool CheckTagNameWhiteList(int32_t aNameSpaceID, nsIAtom *aTagName)
  1.1603 +{
  1.1604 +  static nsIContent::AttrValuesArray kValidXULTagNames[] =  {
  1.1605 +    &nsGkAtoms::autorepeatbutton, &nsGkAtoms::box, &nsGkAtoms::browser,
  1.1606 +    &nsGkAtoms::button, &nsGkAtoms::hbox, &nsGkAtoms::image, &nsGkAtoms::menu,
  1.1607 +    &nsGkAtoms::menubar, &nsGkAtoms::menuitem, &nsGkAtoms::menupopup,
  1.1608 +    &nsGkAtoms::row, &nsGkAtoms::slider, &nsGkAtoms::spacer,
  1.1609 +    &nsGkAtoms::splitter, &nsGkAtoms::text, &nsGkAtoms::tree, nullptr};
  1.1610 +
  1.1611 +  uint32_t i;
  1.1612 +  if (aNameSpaceID == kNameSpaceID_XUL) {
  1.1613 +    for (i = 0; kValidXULTagNames[i]; ++i) {
  1.1614 +      if (aTagName == *(kValidXULTagNames[i])) {
  1.1615 +        return true;
  1.1616 +      }
  1.1617 +    }
  1.1618 +  }
  1.1619 +  else if (aNameSpaceID == kNameSpaceID_SVG &&
  1.1620 +           aTagName == nsGkAtoms::generic_) {
  1.1621 +    return true;
  1.1622 +  }
  1.1623 +
  1.1624 +  return false;
  1.1625 +}
  1.1626 +
  1.1627 +nsresult
  1.1628 +nsXBLPrototypeBinding::ResolveBaseBinding()
  1.1629 +{
  1.1630 +  if (mCheckedBaseProto)
  1.1631 +    return NS_OK;
  1.1632 +  mCheckedBaseProto = true;
  1.1633 +
  1.1634 +  nsCOMPtr<nsIDocument> doc = mXBLDocInfoWeak->GetDocument();
  1.1635 +
  1.1636 +  // Check for the presence of 'extends' and 'display' attributes
  1.1637 +  nsAutoString display, extends;
  1.1638 +  mBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::extends, extends);
  1.1639 +  if (extends.IsEmpty())
  1.1640 +    return NS_OK;
  1.1641 +
  1.1642 +  mBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::display, display);
  1.1643 +  bool hasDisplay = !display.IsEmpty();
  1.1644 +
  1.1645 +  nsAutoString value(extends);
  1.1646 +
  1.1647 +  // Now slice 'em up to see what we've got.
  1.1648 +  nsAutoString prefix;
  1.1649 +  int32_t offset;
  1.1650 +  if (hasDisplay) {
  1.1651 +    offset = display.FindChar(':');
  1.1652 +    if (-1 != offset) {
  1.1653 +      display.Left(prefix, offset);
  1.1654 +      display.Cut(0, offset+1);
  1.1655 +    }
  1.1656 +  }
  1.1657 +  else {
  1.1658 +    offset = extends.FindChar(':');
  1.1659 +    if (-1 != offset) {
  1.1660 +      extends.Left(prefix, offset);
  1.1661 +      extends.Cut(0, offset+1);
  1.1662 +      display = extends;
  1.1663 +    }
  1.1664 +  }
  1.1665 +
  1.1666 +  nsAutoString nameSpace;
  1.1667 +
  1.1668 +  if (!prefix.IsEmpty()) {
  1.1669 +    mBinding->LookupNamespaceURI(prefix, nameSpace);
  1.1670 +    if (!nameSpace.IsEmpty()) {
  1.1671 +      int32_t nameSpaceID =
  1.1672 +        nsContentUtils::NameSpaceManager()->GetNameSpaceID(nameSpace);
  1.1673 +
  1.1674 +      nsCOMPtr<nsIAtom> tagName = do_GetAtom(display);
  1.1675 +      // Check the white list
  1.1676 +      if (!CheckTagNameWhiteList(nameSpaceID, tagName)) {
  1.1677 +        const char16_t* params[] = { display.get() };
  1.1678 +        nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
  1.1679 +                                        NS_LITERAL_CSTRING("XBL"), nullptr,
  1.1680 +                                        nsContentUtils::eXBL_PROPERTIES,
  1.1681 +                                       "InvalidExtendsBinding",
  1.1682 +                                        params, ArrayLength(params),
  1.1683 +                                        doc->GetDocumentURI());
  1.1684 +        NS_ASSERTION(!nsXBLService::IsChromeOrResourceURI(doc->GetDocumentURI()),
  1.1685 +                     "Invalid extends value");
  1.1686 +        return NS_ERROR_ILLEGAL_VALUE;
  1.1687 +      }
  1.1688 +
  1.1689 +      SetBaseTag(nameSpaceID, tagName);
  1.1690 +    }
  1.1691 +  }
  1.1692 +
  1.1693 +  if (hasDisplay || nameSpace.IsEmpty()) {
  1.1694 +    mBinding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::extends, false);
  1.1695 +    mBinding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::display, false);
  1.1696 +
  1.1697 +    return NS_NewURI(getter_AddRefs(mBaseBindingURI), value,
  1.1698 +                     doc->GetDocumentCharacterSet().get(),
  1.1699 +                     doc->GetDocBaseURI());
  1.1700 +  }
  1.1701 +
  1.1702 +  return NS_OK;
  1.1703 +}

mercurial