dom/xbl/nsXBLBinding.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=79: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsCOMPtr.h"
     8 #include "nsIAtom.h"
     9 #include "nsXBLDocumentInfo.h"
    10 #include "nsIInputStream.h"
    11 #include "nsNameSpaceManager.h"
    12 #include "nsIURI.h"
    13 #include "nsIURL.h"
    14 #include "nsIChannel.h"
    15 #include "nsXPIDLString.h"
    16 #include "nsReadableUtils.h"
    17 #include "nsNetUtil.h"
    18 #include "plstr.h"
    19 #include "nsIContent.h"
    20 #include "nsIDocument.h"
    21 #include "nsContentUtils.h"
    22 #include "ChildIterator.h"
    23 #include "nsCxPusher.h"
    24 #ifdef MOZ_XUL
    25 #include "nsIXULDocument.h"
    26 #endif
    27 #include "nsIXMLContentSink.h"
    28 #include "nsContentCID.h"
    29 #include "mozilla/dom/XMLDocument.h"
    30 #include "jsapi.h"
    31 #include "nsXBLService.h"
    32 #include "nsIXPConnect.h"
    33 #include "nsIScriptContext.h"
    34 #include "nsCRT.h"
    36 // Event listeners
    37 #include "mozilla/EventListenerManager.h"
    38 #include "nsIDOMEventListener.h"
    39 #include "nsAttrName.h"
    41 #include "nsGkAtoms.h"
    43 #include "nsXBLPrototypeHandler.h"
    45 #include "nsXBLPrototypeBinding.h"
    46 #include "nsXBLBinding.h"
    47 #include "nsIPrincipal.h"
    48 #include "nsIScriptSecurityManager.h"
    49 #include "mozilla/dom/XBLChildrenElement.h"
    51 #include "prprf.h"
    52 #include "nsNodeUtils.h"
    53 #include "nsJSUtils.h"
    55 // Nasty hack.  Maybe we could move some of the classinfo utility methods
    56 // (e.g. WrapNative) over to nsContentUtils?
    57 #include "nsDOMClassInfo.h"
    59 #include "mozilla/dom/Element.h"
    60 #include "mozilla/dom/ShadowRoot.h"
    62 using namespace mozilla;
    63 using namespace mozilla::dom;
    65 // Helper classes
    67 /***********************************************************************/
    68 //
    69 // The JS class for XBLBinding
    70 //
    71 static void
    72 XBLFinalize(JSFreeOp *fop, JSObject *obj)
    73 {
    74   nsXBLDocumentInfo* docInfo =
    75     static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(obj));
    76   nsContentUtils::DeferredFinalize(docInfo);
    77 }
    79 static bool
    80 XBLEnumerate(JSContext *cx, JS::Handle<JSObject*> obj)
    81 {
    82   nsXBLPrototypeBinding* protoBinding =
    83     static_cast<nsXBLPrototypeBinding*>(::JS_GetReservedSlot(obj, 0).toPrivate());
    84   MOZ_ASSERT(protoBinding);
    86   return protoBinding->ResolveAllFields(cx, obj);
    87 }
    89 static const JSClass gPrototypeJSClass = {
    90     "XBL prototype JSClass",
    91     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
    92     JSCLASS_NEW_RESOLVE |
    93     // Our one reserved slot holds the relevant nsXBLPrototypeBinding
    94     JSCLASS_HAS_RESERVED_SLOTS(1),
    95     JS_PropertyStub,  JS_DeletePropertyStub,
    96     JS_PropertyStub, JS_StrictPropertyStub,
    97     XBLEnumerate, JS_ResolveStub,
    98     JS_ConvertStub, XBLFinalize,
    99     nullptr, nullptr, nullptr, nullptr
   100 };
   102 // Implementation /////////////////////////////////////////////////////////////////
   104 // Constructors/Destructors
   105 nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding)
   106   : mMarkedForDeath(false)
   107   , mUsingXBLScope(false)
   108   , mPrototypeBinding(aBinding)
   109 {
   110   NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!");
   111   // Grab a ref to the document info so the prototype binding won't die
   112   NS_ADDREF(mPrototypeBinding->XBLDocumentInfo());
   113 }
   115 // Constructor used by web components.
   116 nsXBLBinding::nsXBLBinding(ShadowRoot* aShadowRoot, nsXBLPrototypeBinding* aBinding)
   117   : mMarkedForDeath(false),
   118     mUsingXBLScope(false),
   119     mPrototypeBinding(aBinding),
   120     mContent(aShadowRoot)
   121 {
   122   NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!");
   123   // Grab a ref to the document info so the prototype binding won't die
   124   NS_ADDREF(mPrototypeBinding->XBLDocumentInfo());
   125 }
   127 nsXBLBinding::~nsXBLBinding(void)
   128 {
   129   if (mContent) {
   130     nsXBLBinding::UninstallAnonymousContent(mContent->OwnerDoc(), mContent);
   131   }
   132   nsXBLDocumentInfo* info = mPrototypeBinding->XBLDocumentInfo();
   133   NS_RELEASE(info);
   134 }
   136 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLBinding)
   138 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLBinding)
   139   // XXX Probably can't unlink mPrototypeBinding->XBLDocumentInfo(), because
   140   //     mPrototypeBinding is weak.
   141   if (tmp->mContent) {
   142     nsXBLBinding::UninstallAnonymousContent(tmp->mContent->OwnerDoc(),
   143                                             tmp->mContent);
   144   }
   145   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent)
   146   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNextBinding)
   147   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDefaultInsertionPoint)
   148   NS_IMPL_CYCLE_COLLECTION_UNLINK(mInsertionPoints)
   149   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousContentList)
   150 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLBinding)
   152   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
   153                                      "mPrototypeBinding->XBLDocumentInfo()");
   154   cb.NoteXPCOMChild(tmp->mPrototypeBinding->XBLDocumentInfo());
   155   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
   156   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNextBinding)
   157   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDefaultInsertionPoint)
   158   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInsertionPoints)
   159   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContentList)
   160 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   161 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXBLBinding, AddRef)
   162 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXBLBinding, Release)
   164 void
   165 nsXBLBinding::SetBaseBinding(nsXBLBinding* aBinding)
   166 {
   167   if (mNextBinding) {
   168     NS_ERROR("Base XBL binding is already defined!");
   169     return;
   170   }
   172   mNextBinding = aBinding; // Comptr handles rel/add
   173 }
   175 nsXBLBinding*
   176 nsXBLBinding::GetBindingWithContent()
   177 {
   178   if (mContent) {
   179     return this;
   180   }
   182   return mNextBinding ? mNextBinding->GetBindingWithContent() : nullptr;
   183 }
   185 void
   186 nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElement,
   187                                       bool aChromeOnlyContent)
   188 {
   189   // We need to ensure two things.
   190   // (1) The anonymous content should be fooled into thinking it's in the bound
   191   // element's document, assuming that the bound element is in a document
   192   // Note that we don't change the current doc of aAnonParent here, since that
   193   // quite simply does not matter.  aAnonParent is just a way of keeping refs
   194   // to all its kids, which are anonymous content from the point of view of
   195   // aElement.
   196   // (2) The children's parent back pointer should not be to this synthetic root
   197   // but should instead point to the enclosing parent element.
   198   nsIDocument* doc = aElement->GetCurrentDoc();
   199   bool allowScripts = AllowScripts();
   201   nsAutoScriptBlocker scriptBlocker;
   202   for (nsIContent* child = aAnonParent->GetFirstChild();
   203        child;
   204        child = child->GetNextSibling()) {
   205     child->UnbindFromTree();
   206     if (aChromeOnlyContent) {
   207       child->SetFlags(NODE_CHROME_ONLY_ACCESS |
   208                       NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS);
   209     }
   210     nsresult rv =
   211       child->BindToTree(doc, aElement, mBoundElement, allowScripts);
   212     if (NS_FAILED(rv)) {
   213       // Oh, well... Just give up.
   214       // XXXbz This really shouldn't be a void method!
   215       child->UnbindFromTree();
   216       return;
   217     }
   219     child->SetFlags(NODE_IS_ANONYMOUS_ROOT);
   221 #ifdef MOZ_XUL
   222     // To make XUL templates work (and other goodies that happen when
   223     // an element is added to a XUL document), we need to notify the
   224     // XUL document using its special API.
   225     nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(doc));
   226     if (xuldoc)
   227       xuldoc->AddSubtreeToDocument(child);
   228 #endif
   229   }
   230 }
   232 void
   233 nsXBLBinding::UninstallAnonymousContent(nsIDocument* aDocument,
   234                                         nsIContent* aAnonParent)
   235 {
   236   if (aAnonParent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
   237     // It is unnecessary to uninstall anonymous content in a shadow tree
   238     // because the ShadowRoot itself is a DocumentFragment and does not
   239     // need any additional cleanup.
   240     return;
   241   }
   243   nsAutoScriptBlocker scriptBlocker;
   244   // Hold a strong ref while doing this, just in case.
   245   nsCOMPtr<nsIContent> anonParent = aAnonParent;
   246 #ifdef MOZ_XUL
   247   nsCOMPtr<nsIXULDocument> xuldoc =
   248     do_QueryInterface(aDocument);
   249 #endif
   250   for (nsIContent* child = aAnonParent->GetFirstChild();
   251        child;
   252        child = child->GetNextSibling()) {
   253     child->UnbindFromTree();
   254 #ifdef MOZ_XUL
   255     if (xuldoc) {
   256       xuldoc->RemoveSubtreeFromDocument(child);
   257     }
   258 #endif
   259   }
   260 }
   262 void
   263 nsXBLBinding::SetBoundElement(nsIContent* aElement)
   264 {
   265   mBoundElement = aElement;
   266   if (mNextBinding)
   267     mNextBinding->SetBoundElement(aElement);
   269   if (!mBoundElement) {
   270     return;
   271   }
   273   // Compute whether we're using an XBL scope.
   274   //
   275   // We disable XBL scopes for remote XUL, where we care about compat more
   276   // than security. So we need to know whether we're using an XBL scope so that
   277   // we can decide what to do about untrusted events when "allowuntrusted"
   278   // is not given in the handler declaration.
   279   nsCOMPtr<nsIGlobalObject> go = mBoundElement->OwnerDoc()->GetScopeObject();
   280   NS_ENSURE_TRUE_VOID(go && go->GetGlobalJSObject());
   281   mUsingXBLScope = xpc::UseXBLScope(js::GetObjectCompartment(go->GetGlobalJSObject()));
   282 }
   284 bool
   285 nsXBLBinding::HasStyleSheets() const
   286 {
   287   // Find out if we need to re-resolve style.  We'll need to do this
   288   // if we have additional stylesheets in our binding document.
   289   if (mPrototypeBinding->HasStyleSheets())
   290     return true;
   292   return mNextBinding ? mNextBinding->HasStyleSheets() : false;
   293 }
   295 void
   296 nsXBLBinding::GenerateAnonymousContent()
   297 {
   298   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
   299                "Someone forgot a script blocker");
   301   // Fetch the content element for this binding.
   302   nsIContent* content =
   303     mPrototypeBinding->GetImmediateChild(nsGkAtoms::content);
   305   if (!content) {
   306     // We have no anonymous content.
   307     if (mNextBinding)
   308       mNextBinding->GenerateAnonymousContent();
   310     return;
   311   }
   313   // Find out if we're really building kids or if we're just
   314   // using the attribute-setting shorthand hack.
   315   uint32_t contentCount = content->GetChildCount();
   317   // Plan to build the content by default.
   318   bool hasContent = (contentCount > 0);
   319   if (hasContent) {
   320     nsIDocument* doc = mBoundElement->OwnerDoc();
   322     nsCOMPtr<nsINode> clonedNode;
   323     nsCOMArray<nsINode> nodesWithProperties;
   324     nsNodeUtils::Clone(content, true, doc->NodeInfoManager(),
   325                        nodesWithProperties, getter_AddRefs(clonedNode));
   326     mContent = clonedNode->AsElement();
   328     // Search for <xbl:children> elements in the XBL content. In the presence
   329     // of multiple default insertion points, we use the last one in document
   330     // order.
   331     for (nsIContent* child = mContent; child; child = child->GetNextNode(mContent)) {
   332       if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
   333         XBLChildrenElement* point = static_cast<XBLChildrenElement*>(child);
   334         if (point->IsDefaultInsertion()) {
   335           mDefaultInsertionPoint = point;
   336         } else {
   337           mInsertionPoints.AppendElement(point);
   338         }
   339       }
   340     }
   342     // Do this after looking for <children> as this messes up the parent
   343     // pointer which would make the GetNextNode call above fail
   344     InstallAnonymousContent(mContent, mBoundElement,
   345                             mPrototypeBinding->ChromeOnlyContent());
   347     // Insert explicit children into insertion points
   348     if (mDefaultInsertionPoint && mInsertionPoints.IsEmpty()) {
   349       ExplicitChildIterator iter(mBoundElement);
   350       for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
   351         mDefaultInsertionPoint->AppendInsertedChild(child);
   352       }
   353     } else {
   354       // It is odd to come into this code if mInsertionPoints is not empty, but
   355       // we need to make sure to do the compatibility hack below if the bound
   356       // node has any non <xul:template> or <xul:observes> children.
   357       ExplicitChildIterator iter(mBoundElement);
   358       for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
   359         XBLChildrenElement* point = FindInsertionPointForInternal(child);
   360         if (point) {
   361           point->AppendInsertedChild(child);
   362         } else {
   363           nsINodeInfo *ni = child->NodeInfo();
   364           if (ni->NamespaceID() != kNameSpaceID_XUL ||
   365               (!ni->Equals(nsGkAtoms::_template) &&
   366                !ni->Equals(nsGkAtoms::observes))) {
   367             // Compatibility hack. For some reason the original XBL
   368             // implementation dropped the content of a binding if any child of
   369             // the bound element didn't match any of the <children> in the
   370             // binding. This became a pseudo-API that we have to maintain.
   372             // Undo InstallAnonymousContent
   373             UninstallAnonymousContent(doc, mContent);
   375             // Clear out our children elements to avoid dangling references.
   376             ClearInsertionPoints();
   378             // Pretend as though there was no content in the binding.
   379             mContent = nullptr;
   380             return;
   381           }
   382         }
   383       }
   384     }
   386     // Set binding parent on default content if need
   387     if (mDefaultInsertionPoint) {
   388       mDefaultInsertionPoint->MaybeSetupDefaultContent();
   389     }
   390     for (uint32_t i = 0; i < mInsertionPoints.Length(); ++i) {
   391       mInsertionPoints[i]->MaybeSetupDefaultContent();
   392     }
   394     mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
   395   }
   397   // Always check the content element for potential attributes.
   398   // This shorthand hack always happens, even when we didn't
   399   // build anonymous content.
   400   const nsAttrName* attrName;
   401   for (uint32_t i = 0; (attrName = content->GetAttrNameAt(i)); ++i) {
   402     int32_t namespaceID = attrName->NamespaceID();
   403     // Hold a strong reference here so that the atom doesn't go away during
   404     // UnsetAttr.
   405     nsCOMPtr<nsIAtom> name = attrName->LocalName();
   407     if (name != nsGkAtoms::includes) {
   408       if (!nsContentUtils::HasNonEmptyAttr(mBoundElement, namespaceID, name)) {
   409         nsAutoString value2;
   410         content->GetAttr(namespaceID, name, value2);
   411         mBoundElement->SetAttr(namespaceID, name, attrName->GetPrefix(),
   412                                value2, false);
   413       }
   414     }
   416     // Conserve space by wiping the attributes off the clone.
   417     if (mContent)
   418       mContent->UnsetAttr(namespaceID, name, false);
   419   }
   420 }
   422 XBLChildrenElement*
   423 nsXBLBinding::FindInsertionPointFor(nsIContent* aChild)
   424 {
   425   // XXX We should get rid of this function as it causes us to traverse the
   426   // binding chain multiple times
   427   if (mContent) {
   428     return FindInsertionPointForInternal(aChild);
   429   }
   431   return mNextBinding ? mNextBinding->FindInsertionPointFor(aChild)
   432                       : nullptr;
   433 }
   435 XBLChildrenElement*
   436 nsXBLBinding::FindInsertionPointForInternal(nsIContent* aChild)
   437 {
   438   for (uint32_t i = 0; i < mInsertionPoints.Length(); ++i) {
   439     XBLChildrenElement* point = mInsertionPoints[i];
   440     if (point->Includes(aChild)) {
   441       return point;
   442     }
   443   }
   445   return mDefaultInsertionPoint;
   446 }
   448 void
   449 nsXBLBinding::ClearInsertionPoints()
   450 {
   451   if (mDefaultInsertionPoint) {
   452     mDefaultInsertionPoint->ClearInsertedChildren();
   453   }
   455   for (uint32_t i = 0; i < mInsertionPoints.Length(); ++i) {
   456     mInsertionPoints[i]->ClearInsertedChildren();
   457   }
   458 }
   460 nsAnonymousContentList*
   461 nsXBLBinding::GetAnonymousNodeList()
   462 {
   463   if (!mContent) {
   464     return mNextBinding ? mNextBinding->GetAnonymousNodeList() : nullptr;
   465   }
   467   if (!mAnonymousContentList) {
   468     mAnonymousContentList = new nsAnonymousContentList(mContent);
   469   }
   471   return mAnonymousContentList;
   472 }
   474 void
   475 nsXBLBinding::InstallEventHandlers()
   476 {
   477   // Don't install handlers if scripts aren't allowed.
   478   if (AllowScripts()) {
   479     // Fetch the handlers prototypes for this binding.
   480     nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
   482     if (handlerChain) {
   483       EventListenerManager* manager = mBoundElement->GetOrCreateListenerManager();
   484       if (!manager)
   485         return;
   487       bool isChromeDoc =
   488         nsContentUtils::IsChromeDoc(mBoundElement->OwnerDoc());
   489       bool isChromeBinding = mPrototypeBinding->IsChrome();
   490       nsXBLPrototypeHandler* curr;
   491       for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
   492         // Fetch the event type.
   493         nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
   494         if (!eventAtom ||
   495             eventAtom == nsGkAtoms::keyup ||
   496             eventAtom == nsGkAtoms::keydown ||
   497             eventAtom == nsGkAtoms::keypress)
   498           continue;
   500         nsXBLEventHandler* handler = curr->GetEventHandler();
   501         if (handler) {
   502           // Figure out if we're using capturing or not.
   503           EventListenerFlags flags;
   504           flags.mCapture = (curr->GetPhase() == NS_PHASE_CAPTURING);
   506           // If this is a command, add it in the system event group
   507           if ((curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND |
   508                                   NS_HANDLER_TYPE_SYSTEM)) &&
   509               (isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) {
   510             flags.mInSystemGroup = true;
   511           }
   513           bool hasAllowUntrustedAttr = curr->HasAllowUntrustedAttr();
   514           if ((hasAllowUntrustedAttr && curr->AllowUntrustedEvents()) ||
   515               (!hasAllowUntrustedAttr && !isChromeDoc && !mUsingXBLScope)) {
   516             flags.mAllowUntrustedEvents = true;
   517           }
   519           manager->AddEventListenerByType(handler,
   520                                           nsDependentAtomString(eventAtom),
   521                                           flags);
   522         }
   523       }
   525       const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers =
   526         mPrototypeBinding->GetKeyEventHandlers();
   527       int32_t i;
   528       for (i = 0; i < keyHandlers->Count(); ++i) {
   529         nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i);
   530         handler->SetIsBoundToChrome(isChromeDoc);
   531         handler->SetUsingXBLScope(mUsingXBLScope);
   533         nsAutoString type;
   534         handler->GetEventName(type);
   536         // If this is a command, add it in the system event group, otherwise
   537         // add it to the standard event group.
   539         // Figure out if we're using capturing or not.
   540         EventListenerFlags flags;
   541         flags.mCapture = (handler->GetPhase() == NS_PHASE_CAPTURING);
   543         if ((handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND |
   544                                    NS_HANDLER_TYPE_SYSTEM)) &&
   545             (isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) {
   546           flags.mInSystemGroup = true;
   547         }
   549         // For key handlers we have to set mAllowUntrustedEvents flag.
   550         // Whether the handling of the event is allowed or not is handled in
   551         // nsXBLKeyEventHandler::HandleEvent
   552         flags.mAllowUntrustedEvents = true;
   554         manager->AddEventListenerByType(handler, type, flags);
   555       }
   556     }
   557   }
   559   if (mNextBinding)
   560     mNextBinding->InstallEventHandlers();
   561 }
   563 nsresult
   564 nsXBLBinding::InstallImplementation()
   565 {
   566   // Always install the base class properties first, so that
   567   // derived classes can reference the base class properties.
   569   if (mNextBinding) {
   570     nsresult rv = mNextBinding->InstallImplementation();
   571     NS_ENSURE_SUCCESS(rv, rv);
   572   }
   574   // iterate through each property in the prototype's list and install the property.
   575   if (AllowScripts())
   576     return mPrototypeBinding->InstallImplementation(this);
   578   return NS_OK;
   579 }
   581 nsIAtom*
   582 nsXBLBinding::GetBaseTag(int32_t* aNameSpaceID)
   583 {
   584   nsIAtom *tag = mPrototypeBinding->GetBaseTag(aNameSpaceID);
   585   if (!tag && mNextBinding)
   586     return mNextBinding->GetBaseTag(aNameSpaceID);
   588   return tag;
   589 }
   591 void
   592 nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, int32_t aNameSpaceID,
   593                                bool aRemoveFlag, bool aNotify)
   594 {
   595   // XXX Change if we ever allow multiple bindings in a chain to contribute anonymous content
   596   if (!mContent) {
   597     if (mNextBinding)
   598       mNextBinding->AttributeChanged(aAttribute, aNameSpaceID,
   599                                      aRemoveFlag, aNotify);
   600   } else {
   601     mPrototypeBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag,
   602                                         mBoundElement, mContent, aNotify);
   603   }
   604 }
   606 void
   607 nsXBLBinding::ExecuteAttachedHandler()
   608 {
   609   if (mNextBinding)
   610     mNextBinding->ExecuteAttachedHandler();
   612   if (AllowScripts())
   613     mPrototypeBinding->BindingAttached(mBoundElement);
   614 }
   616 void
   617 nsXBLBinding::ExecuteDetachedHandler()
   618 {
   619   if (AllowScripts())
   620     mPrototypeBinding->BindingDetached(mBoundElement);
   622   if (mNextBinding)
   623     mNextBinding->ExecuteDetachedHandler();
   624 }
   626 void
   627 nsXBLBinding::UnhookEventHandlers()
   628 {
   629   nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
   631   if (handlerChain) {
   632     EventListenerManager* manager = mBoundElement->GetExistingListenerManager();
   633     if (!manager) {
   634       return;
   635     }
   637     bool isChromeBinding = mPrototypeBinding->IsChrome();
   638     nsXBLPrototypeHandler* curr;
   639     for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
   640       nsXBLEventHandler* handler = curr->GetCachedEventHandler();
   641       if (!handler) {
   642         continue;
   643       }
   645       nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
   646       if (!eventAtom ||
   647           eventAtom == nsGkAtoms::keyup ||
   648           eventAtom == nsGkAtoms::keydown ||
   649           eventAtom == nsGkAtoms::keypress)
   650         continue;
   652       // Figure out if we're using capturing or not.
   653       EventListenerFlags flags;
   654       flags.mCapture = (curr->GetPhase() == NS_PHASE_CAPTURING);
   656       // If this is a command, remove it from the system event group,
   657       // otherwise remove it from the standard event group.
   659       if ((curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND |
   660                               NS_HANDLER_TYPE_SYSTEM)) &&
   661           (isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) {
   662         flags.mInSystemGroup = true;
   663       }
   665       manager->RemoveEventListenerByType(handler,
   666                                          nsDependentAtomString(eventAtom),
   667                                          flags);
   668     }
   670     const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers =
   671       mPrototypeBinding->GetKeyEventHandlers();
   672     int32_t i;
   673     for (i = 0; i < keyHandlers->Count(); ++i) {
   674       nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i);
   676       nsAutoString type;
   677       handler->GetEventName(type);
   679       // Figure out if we're using capturing or not.
   680       EventListenerFlags flags;
   681       flags.mCapture = (handler->GetPhase() == NS_PHASE_CAPTURING);
   683       // If this is a command, remove it from the system event group, otherwise
   684       // remove it from the standard event group.
   686       if ((handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) &&
   687           (isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) {
   688         flags.mInSystemGroup = true;
   689       }
   691       manager->RemoveEventListenerByType(handler, type, flags);
   692     }
   693   }
   694 }
   696 static void
   697 UpdateInsertionParent(XBLChildrenElement* aPoint,
   698                       nsIContent* aOldBoundElement)
   699 {
   700   if (aPoint->IsDefaultInsertion()) {
   701     return;
   702   }
   704   for (size_t i = 0; i < aPoint->InsertedChildrenLength(); ++i) {
   705     nsIContent* child = aPoint->mInsertedChildren[i];
   707     MOZ_ASSERT(child->GetParentNode());
   709     // Here, we're iterating children that we inserted. There are two cases:
   710     // either |child| is an explicit child of |aOldBoundElement| and is no
   711     // longer inserted anywhere or it's a child of a <children> element
   712     // parented to |aOldBoundElement|. In the former case, the child is no
   713     // longer inserted anywhere, so we set its insertion parent to null. In the
   714     // latter case, the child is now inserted into |aOldBoundElement| from some
   715     // binding above us, so we set its insertion parent to aOldBoundElement.
   716     if (child->GetParentNode() == aOldBoundElement) {
   717       child->SetXBLInsertionParent(nullptr);
   718     } else {
   719       child->SetXBLInsertionParent(aOldBoundElement);
   720     }
   721   }
   722 }
   724 void
   725 nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument)
   726 {
   727   if (aOldDocument == aNewDocument)
   728     return;
   730   // Now the binding dies.  Unhook our prototypes.
   731   if (mPrototypeBinding->HasImplementation()) {
   732     nsCOMPtr<nsIScriptGlobalObject> global =  do_QueryInterface(
   733                                                                 aOldDocument->GetScopeObject());
   734     if (global) {
   735       nsCOMPtr<nsIScriptContext> context = global->GetContext();
   736       if (context) {
   737         JSContext *cx = context->GetNativeContext();
   739         nsCxPusher pusher;
   740         pusher.Push(cx);
   742         // scope might be null if we've cycle-collected the global
   743         // object, since the Unlink phase of cycle collection happens
   744         // after JS GC finalization.  But in that case, we don't care
   745         // about fixing the prototype chain, since everything's going
   746         // away immediately.
   747         JS::Rooted<JSObject*> scope(cx, global->GetGlobalJSObject());
   748         JS::Rooted<JSObject*> scriptObject(cx, mBoundElement->GetWrapper());
   749         if (scope && scriptObject) {
   750           // XXX Stay in sync! What if a layered binding has an
   751           // <interface>?!
   752           // XXXbz what does that comment mean, really?  It seems to date
   753           // back to when there was such a thing as an <interface>, whever
   754           // that was...
   756           // Find the right prototype.
   757           JSAutoCompartment ac(cx, scriptObject);
   759           JS::Rooted<JSObject*> base(cx, scriptObject);
   760           JS::Rooted<JSObject*> proto(cx);
   761           for ( ; true; base = proto) { // Will break out on null proto
   762             if (!JS_GetPrototype(cx, base, &proto)) {
   763               return;
   764             }
   765             if (!proto) {
   766               break;
   767             }
   769             if (JS_GetClass(proto) != &gPrototypeJSClass) {
   770               // Clearly not the right class
   771               continue;
   772             }
   774             nsRefPtr<nsXBLDocumentInfo> docInfo =
   775               static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(proto));
   776             if (!docInfo) {
   777               // Not the proto we seek
   778               continue;
   779             }
   781             JS::Value protoBinding = ::JS_GetReservedSlot(proto, 0);
   783             if (JSVAL_TO_PRIVATE(protoBinding) != mPrototypeBinding) {
   784               // Not the right binding
   785               continue;
   786             }
   788             // Alright!  This is the right prototype.  Pull it out of the
   789             // proto chain.
   790             JS::Rooted<JSObject*> grandProto(cx);
   791             if (!JS_GetPrototype(cx, proto, &grandProto)) {
   792               return;
   793             }
   794             ::JS_SetPrototype(cx, base, grandProto);
   795             break;
   796           }
   798           mPrototypeBinding->UndefineFields(cx, scriptObject);
   800           // Don't remove the reference from the document to the
   801           // wrapper here since it'll be removed by the element
   802           // itself when that's taken out of the document.
   803         }
   804       }
   805     }
   806   }
   808   // Remove our event handlers
   809   UnhookEventHandlers();
   811   {
   812     nsAutoScriptBlocker scriptBlocker;
   814     // Then do our ancestors.  This reverses the construction order, so that at
   815     // all times things are consistent as far as everyone is concerned.
   816     if (mNextBinding) {
   817       mNextBinding->ChangeDocument(aOldDocument, aNewDocument);
   818     }
   820     // Update the anonymous content.
   821     // XXXbz why not only for style bindings?
   822     if (mContent) {
   823       nsXBLBinding::UninstallAnonymousContent(aOldDocument, mContent);
   824     }
   826     // Now that we've unbound our anonymous content from the tree and updated
   827     // its binding parent, update the insertion parent for content inserted
   828     // into our <children> elements.
   829     if (mDefaultInsertionPoint) {
   830       UpdateInsertionParent(mDefaultInsertionPoint, mBoundElement);
   831     }
   833     for (size_t i = 0; i < mInsertionPoints.Length(); ++i) {
   834       UpdateInsertionParent(mInsertionPoints[i], mBoundElement);
   835     }
   837     // Now that our inserted children no longer think they're inserted
   838     // anywhere, make sure our internal state reflects that as well.
   839     ClearInsertionPoints();
   840   }
   841 }
   843 bool
   844 nsXBLBinding::InheritsStyle() const
   845 {
   846   // XXX Will have to change if we ever allow multiple bindings to contribute anonymous content.
   847   // Most derived binding with anonymous content determines style inheritance for now.
   849   // XXX What about bindings with <content> but no kids, e.g., my treecell-text binding?
   850   if (mContent)
   851     return mPrototypeBinding->InheritsStyle();
   853   if (mNextBinding)
   854     return mNextBinding->InheritsStyle();
   856   return true;
   857 }
   859 void
   860 nsXBLBinding::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData)
   861 {
   862   if (mNextBinding)
   863     mNextBinding->WalkRules(aFunc, aData);
   865   nsIStyleRuleProcessor *rules = mPrototypeBinding->GetRuleProcessor();
   866   if (rules)
   867     (*aFunc)(rules, aData);
   868 }
   870 // Internal helper methods ////////////////////////////////////////////////////////////////
   872 // Get or create a WeakMap object on a given XBL-hosting global.
   873 //
   874 // The scheme is as follows. XBL-hosting globals (either privileged content
   875 // Windows or XBL scopes) get two lazily-defined WeakMap properties. Each
   876 // WeakMap is keyed by the grand-proto - i.e. the original prototype of the
   877 // content before it was bound, and the prototype of the class object that we
   878 // splice in. The values in the WeakMap are simple dictionary-style objects,
   879 // mapping from XBL class names to class objects.
   880 static JSObject*
   881 GetOrCreateClassObjectMap(JSContext *cx, JS::Handle<JSObject*> scope, const char *mapName)
   882 {
   883   AssertSameCompartment(cx, scope);
   884   MOZ_ASSERT(JS_IsGlobalObject(scope));
   885   MOZ_ASSERT(scope == xpc::GetXBLScopeOrGlobal(cx, scope));
   887   // First, see if the map is already defined.
   888   JS::Rooted<JSPropertyDescriptor> desc(cx);
   889   if (!JS_GetOwnPropertyDescriptor(cx, scope, mapName, &desc)) {
   890     return nullptr;
   891   }
   892   if (desc.object() && desc.value().isObject() &&
   893       JS::IsWeakMapObject(&desc.value().toObject())) {
   894     return &desc.value().toObject();
   895   }
   897   // It's not there. Create and define it.
   898   JS::Rooted<JSObject*> map(cx, JS::NewWeakMapObject(cx));
   899   if (!map || !JS_DefineProperty(cx, scope, mapName, map,
   900                                  JSPROP_PERMANENT | JSPROP_READONLY,
   901                                  JS_PropertyStub, JS_StrictPropertyStub))
   902   {
   903     return nullptr;
   904   }
   905   return map;
   906 }
   908 static JSObject*
   909 GetOrCreateMapEntryForPrototype(JSContext *cx, JS::Handle<JSObject*> proto)
   910 {
   911   AssertSameCompartment(cx, proto);
   912   // We want to hang our class objects off the XBL scope. But since we also
   913   // hoist anonymous content into the XBL scope, this creates the potential for
   914   // tricky collisions, since we can simultaneously  have a bound in-content
   915   // node with grand-proto HTMLDivElement and a bound anonymous node whose
   916   // grand-proto is the XBL scope's cross-compartment wrapper to HTMLDivElement.
   917   // Since we have to wrap the WeakMap keys into its scope, this distinction
   918   // would be lost if we don't do something about it.
   919   //
   920   // So we define two maps - one class objects that live in content (prototyped
   921   // to content prototypes), and the other for class objects that live in the
   922   // XBL scope (prototyped to cross-compartment-wrapped content prototypes).
   923   const char* name = xpc::IsInXBLScope(proto) ? "__ContentClassObjectMap__"
   924                                               : "__XBLClassObjectMap__";
   926   // Now, enter the XBL scope, since that's where we need to operate, and wrap
   927   // the proto accordingly.
   928   JS::Rooted<JSObject*> scope(cx, xpc::GetXBLScopeOrGlobal(cx, proto));
   929   NS_ENSURE_TRUE(scope, nullptr);
   930   JS::Rooted<JSObject*> wrappedProto(cx, proto);
   931   JSAutoCompartment ac(cx, scope);
   932   if (!JS_WrapObject(cx, &wrappedProto)) {
   933     return nullptr;
   934   }
   936   // Grab the appropriate WeakMap.
   937   JS::Rooted<JSObject*> map(cx, GetOrCreateClassObjectMap(cx, scope, name));
   938   if (!map) {
   939     return nullptr;
   940   }
   942   // See if we already have a map entry for that prototype.
   943   JS::Rooted<JS::Value> val(cx);
   944   if (!JS::GetWeakMapEntry(cx, map, wrappedProto, &val)) {
   945     return nullptr;
   946   }
   947   if (val.isObject()) {
   948     return &val.toObject();
   949   }
   951   // We don't have an entry. Create one and stick it in the map.
   952   JS::Rooted<JSObject*> entry(cx);
   953   entry = JS_NewObjectWithGivenProto(cx, nullptr, JS::NullPtr(), scope);
   954   if (!entry) {
   955     return nullptr;
   956   }
   957   JS::Rooted<JS::Value> entryVal(cx, JS::ObjectValue(*entry));
   958   if (!JS::SetWeakMapEntry(cx, map, wrappedProto, entryVal)) {
   959     NS_WARNING("SetWeakMapEntry failed, probably due to non-preservable WeakMap "
   960                "key. XBL binding will fail for this element.");
   961     return nullptr;
   962   }
   963   return entry;
   964 }
   966 // static
   967 nsresult
   968 nsXBLBinding::DoInitJSClass(JSContext *cx,
   969                             JS::Handle<JSObject*> obj,
   970                             const nsAFlatCString& aClassName,
   971                             nsXBLPrototypeBinding* aProtoBinding,
   972                             JS::MutableHandle<JSObject*> aClassObject,
   973                             bool* aNew)
   974 {
   975   MOZ_ASSERT(obj);
   977   // Note that, now that NAC reflectors are created in the XBL scope, the
   978   // reflector is not necessarily same-compartment with the document. So we'll
   979   // end up creating a separate instance of the oddly-named XBL class object
   980   // and defining it as a property on the XBL scope's global. This works fine,
   981   // but we need to make sure never to assume that the the reflector and
   982   // prototype are same-compartment with the bound document.
   983   JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
   984   JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScopeOrGlobal(cx, global));
   985   NS_ENSURE_TRUE(xblScope, NS_ERROR_UNEXPECTED);
   987   JS::Rooted<JSObject*> parent_proto(cx);
   988   if (!JS_GetPrototype(cx, obj, &parent_proto)) {
   989     return NS_ERROR_FAILURE;
   990   }
   992   // Get the map entry for the parent prototype. In the one-off case that the
   993   // parent prototype is null, we somewhat hackily just use the WeakMap itself
   994   // as a property holder.
   995   JS::Rooted<JSObject*> holder(cx);
   996   if (parent_proto) {
   997     holder = GetOrCreateMapEntryForPrototype(cx, parent_proto);
   998   } else {
   999     JSAutoCompartment innerAC(cx, xblScope);
  1000     holder = GetOrCreateClassObjectMap(cx, xblScope, "__ContentClassObjectMap__");
  1002   if (NS_WARN_IF(!holder)) {
  1003     return NS_ERROR_FAILURE;
  1005   js::AssertSameCompartment(holder, xblScope);
  1006   JSAutoCompartment ac(cx, holder);
  1008   // Look up the class on the property holder. The only properties on the
  1009   // holder should be class objects. If we don't find the class object, we need
  1010   // to create and define it.
  1011   JS::Rooted<JSObject*> proto(cx);
  1012   JS::Rooted<JSPropertyDescriptor> desc(cx);
  1013   if (!JS_GetOwnPropertyDescriptor(cx, holder, aClassName.get(), &desc)) {
  1014     return NS_ERROR_OUT_OF_MEMORY;
  1016   *aNew = !desc.object();
  1017   if (desc.object()) {
  1018     proto = &desc.value().toObject();
  1019     MOZ_ASSERT(JS_GetClass(js::UncheckedUnwrap(proto)) == &gPrototypeJSClass);
  1020   } else {
  1022     // We need to create the prototype. First, enter the compartment where it's
  1023     // going to live, and create it.
  1024     JSAutoCompartment ac2(cx, global);
  1025     proto = JS_NewObjectWithGivenProto(cx, &gPrototypeJSClass, parent_proto, global);
  1026     if (!proto) {
  1027       return NS_ERROR_OUT_OF_MEMORY;
  1030     // Keep this proto binding alive while we're alive.  Do this first so that
  1031     // we can guarantee that in XBLFinalize this will be non-null.
  1032     // Note that we can't just store aProtoBinding in the private and
  1033     // addref/release the nsXBLDocumentInfo through it, because cycle
  1034     // collection doesn't seem to work right if the private is not an
  1035     // nsISupports.
  1036     nsXBLDocumentInfo* docInfo = aProtoBinding->XBLDocumentInfo();
  1037     ::JS_SetPrivate(proto, docInfo);
  1038     NS_ADDREF(docInfo);
  1039     JS_SetReservedSlot(proto, 0, PRIVATE_TO_JSVAL(aProtoBinding));
  1041     // Next, enter the compartment of the property holder, wrap the proto, and
  1042     // stick it on.
  1043     JSAutoCompartment ac3(cx, holder);
  1044     if (!JS_WrapObject(cx, &proto) ||
  1045         !JS_DefineProperty(cx, holder, aClassName.get(), proto,
  1046                            JSPROP_READONLY | JSPROP_PERMANENT,
  1047                            JS_PropertyStub, JS_StrictPropertyStub))
  1049       return NS_ERROR_OUT_OF_MEMORY;
  1053   // Whew. We have the proto. Wrap it back into the compartment of |obj|,
  1054   // splice it in, and return it.
  1055   JSAutoCompartment ac4(cx, obj);
  1056   if (!JS_WrapObject(cx, &proto) || !JS_SetPrototype(cx, obj, proto)) {
  1057     return NS_ERROR_FAILURE;
  1059   aClassObject.set(proto);
  1060   return NS_OK;
  1063 bool
  1064 nsXBLBinding::AllowScripts()
  1066   return mBoundElement && mPrototypeBinding->GetAllowScripts();
  1069 nsXBLBinding*
  1070 nsXBLBinding::RootBinding()
  1072   if (mNextBinding)
  1073     return mNextBinding->RootBinding();
  1075   return this;
  1078 bool
  1079 nsXBLBinding::ResolveAllFields(JSContext *cx, JS::Handle<JSObject*> obj) const
  1081   if (!mPrototypeBinding->ResolveAllFields(cx, obj)) {
  1082     return false;
  1085   if (mNextBinding) {
  1086     return mNextBinding->ResolveAllFields(cx, obj);
  1089   return true;
  1092 bool
  1093 nsXBLBinding::LookupMember(JSContext* aCx, JS::Handle<jsid> aId,
  1094                            JS::MutableHandle<JSPropertyDescriptor> aDesc)
  1096   // We should never enter this function with a pre-filled property descriptor.
  1097   MOZ_ASSERT(!aDesc.object());
  1099   // Get the string as an nsString before doing anything, so we can make
  1100   // convenient comparisons during our search.
  1101   if (!JSID_IS_STRING(aId)) {
  1102     return true;
  1104   nsDependentJSString name(aId);
  1106   // We have a weak reference to our bound element, so make sure it's alive.
  1107   if (!mBoundElement || !mBoundElement->GetWrapper()) {
  1108     return false;
  1111   // Get the scope of mBoundElement and the associated XBL scope. We should only
  1112   // be calling into this machinery if we're running in a separate XBL scope.
  1113   //
  1114   // Note that we only end up in LookupMember for XrayWrappers from XBL scopes
  1115   // into content. So for NAC reflectors that live in the XBL scope, we should
  1116   // never get here. But on the off-chance that someone adds new callsites to
  1117   // LookupMember, we do a release-mode assertion as belt-and-braces.
  1118   // We do a release-mode assertion here to be extra safe.
  1119   JS::Rooted<JSObject*> boundScope(aCx,
  1120     js::GetGlobalForObjectCrossCompartment(mBoundElement->GetWrapper()));
  1121   MOZ_RELEASE_ASSERT(!xpc::IsInXBLScope(boundScope));
  1122   JS::Rooted<JSObject*> xblScope(aCx, xpc::GetXBLScope(aCx, boundScope));
  1123   NS_ENSURE_TRUE(xblScope, false);
  1124   MOZ_ASSERT(boundScope != xblScope);
  1126   // Enter the xbl scope and invoke the internal version.
  1128     JSAutoCompartment ac(aCx, xblScope);
  1129     JS::Rooted<jsid> id(aCx, aId);
  1130     if (!JS_WrapId(aCx, &id) ||
  1131         !LookupMemberInternal(aCx, name, id, aDesc, xblScope))
  1133       return false;
  1137   // Wrap into the caller's scope.
  1138   return JS_WrapPropertyDescriptor(aCx, aDesc);
  1141 bool
  1142 nsXBLBinding::LookupMemberInternal(JSContext* aCx, nsString& aName,
  1143                                    JS::Handle<jsid> aNameAsId,
  1144                                    JS::MutableHandle<JSPropertyDescriptor> aDesc,
  1145                                    JS::Handle<JSObject*> aXBLScope)
  1147   // First, see if we have an implementation. If we don't, it means that this
  1148   // binding doesn't have a class object, and thus doesn't have any members.
  1149   // Skip it.
  1150   if (!PrototypeBinding()->HasImplementation()) {
  1151     if (!mNextBinding) {
  1152       return true;
  1154     return mNextBinding->LookupMemberInternal(aCx, aName, aNameAsId,
  1155                                               aDesc, aXBLScope);
  1158   // Find our class object. It's in a protected scope and permanent just in case,
  1159   // so should be there no matter what.
  1160   JS::Rooted<JS::Value> classObject(aCx);
  1161   if (!JS_GetProperty(aCx, aXBLScope, PrototypeBinding()->ClassName().get(),
  1162                       &classObject)) {
  1163     return false;
  1166   // The bound element may have been adoped by a document and have a different
  1167   // wrapper (and different xbl scope) than when the binding was applied, in
  1168   // this case getting the class object will fail. Behave as if the class
  1169   // object did not exist.
  1170   if (classObject.isUndefined()) {
  1171     return true;
  1174   MOZ_ASSERT(classObject.isObject());
  1176   // Look for the property on this binding. If it's not there, try the next
  1177   // binding on the chain.
  1178   nsXBLProtoImpl* impl = mPrototypeBinding->GetImplementation();
  1179   JS::Rooted<JSObject*> object(aCx, &classObject.toObject());
  1180   if (impl && !impl->LookupMember(aCx, aName, aNameAsId, aDesc, object)) {
  1181     return false;
  1183   if (aDesc.object() || !mNextBinding) {
  1184     return true;
  1187   return mNextBinding->LookupMemberInternal(aCx, aName, aNameAsId, aDesc,
  1188                                             aXBLScope);
  1191 bool
  1192 nsXBLBinding::HasField(nsString& aName)
  1194   // See if this binding has such a field.
  1195   return mPrototypeBinding->FindField(aName) ||
  1196     (mNextBinding && mNextBinding->HasField(aName));
  1199 void
  1200 nsXBLBinding::MarkForDeath()
  1202   mMarkedForDeath = true;
  1203   ExecuteDetachedHandler();
  1206 bool
  1207 nsXBLBinding::ImplementsInterface(REFNSIID aIID) const
  1209   return mPrototypeBinding->ImplementsInterface(aIID) ||
  1210     (mNextBinding && mNextBinding->ImplementsInterface(aIID));

mercurial