Bug 94199, part 1, move handling of base binding to nsXBLPrototypeBinding, r=bz
authorNeil Deakin <neil@mozilla.com>
Thu, 03 Nov 2011 16:39:07 -0400
changeset 79697 e0274a0c094e153c7e4a52c96d5ebd1d6dea8018
parent 79696 ca673b65d7eb5c90a2d51a6b59c6c7dcb8f7b708
child 79698 44d61a68eae09394a289358361d846420de823c8
push id3103
push userneil@mozilla.com
push dateThu, 03 Nov 2011 20:41:05 +0000
treeherdermozilla-inbound@797d8083efca [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs94199
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 94199, part 1, move handling of base binding to nsXBLPrototypeBinding, r=bz
content/xbl/src/nsXBLPrototypeBinding.cpp
content/xbl/src/nsXBLPrototypeBinding.h
content/xbl/src/nsXBLService.cpp
content/xbl/src/nsXBLService.h
--- a/content/xbl/src/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -66,16 +66,17 @@
 #include "nsIInterfaceInfoManager.h"
 #include "nsIDocumentObserver.h"
 #include "nsGkAtoms.h"
 #include "nsXBLProtoImpl.h"
 #include "nsCRT.h"
 #include "nsContentUtils.h"
 
 #include "nsIScriptContext.h"
+#include "nsIScriptError.h"
 
 #include "nsIStyleRuleProcessor.h"
 #include "nsXBLResourceLoader.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 
 // Helper Classes =====================================================================
@@ -271,17 +272,17 @@ static const PRInt32 kInsInitialSize = (
 
 // Implementation /////////////////////////////////////////////////////////////////
 
 // Constructors/Destructors
 nsXBLPrototypeBinding::nsXBLPrototypeBinding()
 : mImplementation(nsnull),
   mBaseBinding(nsnull),
   mInheritStyle(true), 
-  mHasBaseProto(true),
+  mCheckedBaseProto(false),
   mKeyHandlersRegistered(false),
   mResources(nsnull),
   mAttributeTable(nsnull),
   mInsertionPointTable(nsnull),
   mInterfaceTable(nsnull)
 {
   MOZ_COUNT_CTOR(nsXBLPrototypeBinding);
   gRefCnt++;
@@ -1421,8 +1422,112 @@ nsXBLPrototypeBinding::CreateKeyHandlers
 
       if (handler)
         handler->AddProtoHandler(curr);
     }
 
     curr = curr->GetNextHandler();
   }
 }
+
+bool CheckTagNameWhiteList(PRInt32 aNameSpaceID, nsIAtom *aTagName)
+{
+  static nsIContent::AttrValuesArray kValidXULTagNames[] =  {
+    &nsGkAtoms::autorepeatbutton, &nsGkAtoms::box, &nsGkAtoms::browser,
+    &nsGkAtoms::button, &nsGkAtoms::hbox, &nsGkAtoms::image, &nsGkAtoms::menu,
+    &nsGkAtoms::menubar, &nsGkAtoms::menuitem, &nsGkAtoms::menupopup,
+    &nsGkAtoms::row, &nsGkAtoms::slider, &nsGkAtoms::spacer,
+    &nsGkAtoms::splitter, &nsGkAtoms::text, &nsGkAtoms::tree, nsnull};
+
+  PRUint32 i;
+  if (aNameSpaceID == kNameSpaceID_XUL) {
+    for (i = 0; kValidXULTagNames[i]; ++i) {
+      if (aTagName == *(kValidXULTagNames[i])) {
+        return true;
+      }
+    }
+  }
+  else if (aNameSpaceID == kNameSpaceID_SVG &&
+           aTagName == nsGkAtoms::generic) {
+    return true;
+  }
+
+  return false;
+}
+
+nsresult
+nsXBLPrototypeBinding::ResolveBaseBinding()
+{
+  if (mCheckedBaseProto)
+    return NS_OK;
+  mCheckedBaseProto = true;
+
+  nsCOMPtr<nsIDocument> doc = mXBLDocInfoWeak->GetDocument();
+
+  // Check for the presence of 'extends' and 'display' attributes
+  nsAutoString display, extends;
+  mBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::extends, extends);
+  if (extends.IsEmpty())
+    return NS_OK;
+
+  mBinding->GetAttr(kNameSpaceID_None, nsGkAtoms::display, display);
+  bool hasDisplay = !display.IsEmpty();
+
+  nsAutoString value(extends);
+       
+  // Now slice 'em up to see what we've got.
+  nsAutoString prefix;
+  PRInt32 offset;
+  if (hasDisplay) {
+    offset = display.FindChar(':');
+    if (-1 != offset) {
+      display.Left(prefix, offset);
+      display.Cut(0, offset+1);
+    }
+  }
+  else {
+    offset = extends.FindChar(':');
+    if (-1 != offset) {
+      extends.Left(prefix, offset);
+      extends.Cut(0, offset+1);
+      display = extends;
+    }
+  }
+
+  nsAutoString nameSpace;
+
+  if (!prefix.IsEmpty()) {
+    mBinding->LookupNamespaceURI(prefix, nameSpace);
+    if (!nameSpace.IsEmpty()) {
+      PRInt32 nameSpaceID =
+        nsContentUtils::NameSpaceManager()->GetNameSpaceID(nameSpace);
+
+      nsCOMPtr<nsIAtom> tagName = do_GetAtom(display);
+      // Check the white list
+      if (!CheckTagNameWhiteList(nameSpaceID, tagName)) {
+        const PRUnichar* params[] = { display.get() };
+        nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES,
+                                       "InvalidExtendsBinding",
+                                        params, NS_ARRAY_LENGTH(params),
+                                        doc->GetDocumentURI(),
+                                        EmptyString(), 0, 0,
+                                        nsIScriptError::errorFlag,
+                                        "XBL");
+        NS_ASSERTION(!nsXBLService::IsChromeOrResourceURI(doc->GetDocumentURI()),
+                     "Invalid extends value");
+        return NS_ERROR_ILLEGAL_VALUE;
+      }
+
+      SetBaseTag(nameSpaceID, tagName);
+    }
+  }
+
+  if (hasDisplay || nameSpace.IsEmpty()) {
+    mBinding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::extends, false);
+    mBinding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::display, false);
+
+    return NS_NewURI(getter_AddRefs(mBaseBindingURI), value,
+                     doc->GetDocumentCharacterSet().get(),
+                     doc->GetDocBaseURI());
+  }
+
+  return NS_OK;
+}
--- a/content/xbl/src/nsXBLPrototypeBinding.h
+++ b/content/xbl/src/nsXBLPrototypeBinding.h
@@ -71,16 +71,17 @@ class nsXBLPrototypeBinding
 {
 public:
   already_AddRefed<nsIContent> GetBindingElement();
   void SetBindingElement(nsIContent* aElement);
 
   nsIURI* BindingURI() const { return mBindingURI; }
   nsIURI* AlternateBindingURI() const { return mAlternateBindingURI; }
   nsIURI* DocURI() const { return mXBLDocInfoWeak->DocumentURI(); }
+  nsIURI* GetBaseBindingURI() const { return mBaseBindingURI; }
 
   // Checks if aURI refers to this binding by comparing to both possible
   // binding URIs.
   bool CompareBindingURI(nsIURI* aURI) const;
 
   bool GetAllowScripts();
 
   nsresult BindingAttached(nsIContent* aBoundElement);
@@ -138,19 +139,16 @@ public:
                         nsIContent* aAnonymousContent, bool aNotify);
 
   void SetBasePrototype(nsXBLPrototypeBinding* aBinding);
   nsXBLPrototypeBinding* GetBasePrototype() { return mBaseBinding; }
 
   nsXBLDocumentInfo* XBLDocumentInfo() const { return mXBLDocInfoWeak; }
   bool IsChrome() { return mXBLDocInfoWeak->IsChrome(); }
   
-  bool HasBasePrototype() { return mHasBaseProto; }
-  void SetHasBasePrototype(bool aHasBase) { mHasBaseProto = aHasBase; }
-
   void SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent);
 
   nsIStyleRuleProcessor* GetRuleProcessor();
   nsXBLPrototypeResources::sheet_array_type* GetStyleSheets();
 
   bool HasInsertionPoints() { return mInsertionPointTable != nsnull; }
   
   bool HasStyleSheets() {
@@ -176,16 +174,18 @@ public:
   void SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag);
 
   bool ImplementsInterface(REFNSIID aIID) const;
 
   nsresult AddResourceListener(nsIContent* aBoundElement);
 
   void Initialize();
 
+  nsresult ResolveBaseBinding();
+
   const nsCOMArray<nsXBLKeyEventHandler>* GetKeyEventHandlers()
   {
     if (!mKeyHandlersRegistered) {
       CreateKeyHandlers();
       mKeyHandlersRegistered = true;
     }
 
     return &mKeyHandlers;
@@ -261,23 +261,26 @@ protected:
   };
 
 // MEMBER VARIABLES
 protected:
   nsCOMPtr<nsIURI> mBindingURI;
   nsCOMPtr<nsIURI> mAlternateBindingURI; // Alternate id-less URI that is only non-null on the first binding.
   nsCOMPtr<nsIContent> mBinding; // Strong. We own a ref to our content element in the binding doc.
   nsAutoPtr<nsXBLPrototypeHandler> mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers.
-  
+
+  // the url of the base binding
+  nsCOMPtr<nsIURI> mBaseBindingURI;
+
   nsXBLProtoImpl* mImplementation; // Our prototype implementation (includes methods, properties, fields,
                                    // the constructor, and the destructor).
 
   nsXBLPrototypeBinding* mBaseBinding; // Weak.  The docinfo will own our base binding.
   bool mInheritStyle;
-  bool mHasBaseProto;
+  bool mCheckedBaseProto;
   bool mKeyHandlersRegistered;
  
   nsXBLPrototypeResources* mResources; // If we have any resources, this will be non-null.
                                       
   nsXBLDocumentInfo* mXBLDocInfoWeak; // A pointer back to our doc info.  Weak, since it owns us.
 
   nsObjectHashtable* mAttributeTable; // A table for attribute containers. Namespace IDs are used as
                                       // keys in the table. Containers are nsObjectHashtables.
--- a/content/xbl/src/nsXBLService.cpp
+++ b/content/xbl/src/nsXBLService.cpp
@@ -92,26 +92,16 @@
 #include "nsIDOMEventListener.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 
 #define NS_MAX_XBL_BINDING_RECURSION 20
 
-static bool IsChromeOrResourceURI(nsIURI* aURI)
-{
-  bool isChrome = false;
-  bool isResource = false;
-  if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && 
-      NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)))
-      return (isChrome || isResource);
-  return false;
-}
-
 static bool
 IsAncestorBinding(nsIDocument* aDocument,
                   nsIURI* aChildBindingURI,
                   nsIContent* aChild)
 {
   NS_ASSERTION(aDocument, "expected a document");
   NS_ASSERTION(aChildBindingURI, "expected a binding URI");
   NS_ASSERTION(aChild, "expected a child content");
@@ -144,41 +134,16 @@ IsAncestorBinding(nsIDocument* aDocument
                                       "XBL", aDocument);
       return true;
     }
   }
 
   return false;
 }
 
-bool CheckTagNameWhiteList(PRInt32 aNameSpaceID, nsIAtom *aTagName)
-{
-  static nsIContent::AttrValuesArray kValidXULTagNames[] =  {
-    &nsGkAtoms::autorepeatbutton, &nsGkAtoms::box, &nsGkAtoms::browser,
-    &nsGkAtoms::button, &nsGkAtoms::hbox, &nsGkAtoms::image, &nsGkAtoms::menu,
-    &nsGkAtoms::menubar, &nsGkAtoms::menuitem, &nsGkAtoms::menupopup,
-    &nsGkAtoms::row, &nsGkAtoms::slider, &nsGkAtoms::spacer,
-    &nsGkAtoms::splitter, &nsGkAtoms::text, &nsGkAtoms::tree, nsnull};
-
-  PRUint32 i;
-  if (aNameSpaceID == kNameSpaceID_XUL) {
-    for (i = 0; kValidXULTagNames[i]; ++i) {
-      if (aTagName == *(kValidXULTagNames[i])) {
-        return true;
-      }
-    }
-  }
-  else if (aNameSpaceID == kNameSpaceID_SVG &&
-           aTagName == nsGkAtoms::generic) {
-    return true;
-  }
-
-  return false;
-}
-
 // Individual binding requests.
 class nsXBLBindingRequest
 {
 public:
   nsCOMPtr<nsIURI> mBindingURI;
   nsCOMPtr<nsIContent> mBoundElement;
 
   static nsXBLBindingRequest*
@@ -445,31 +410,31 @@ nsXBLStreamListener::HandleEvent(nsIDOME
     }
 
     // Put our doc info in the doc table.
     nsBindingManager *xblDocBindingManager = bindingDocument->BindingManager();
     nsRefPtr<nsXBLDocumentInfo> info =
       xblDocBindingManager->GetXBLDocumentInfo(documentURI);
     xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle.
     if (!info) {
-      if (IsChromeOrResourceURI(documentURI)) {
+      if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
         NS_WARNING("An XBL file is malformed. Did you forget the XBL namespace on the bindings tag?");
       }
       nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES,
                                       "MalformedXBL",
                                       nsnull, 0, documentURI,
                                       EmptyString(), 0, 0,
                                       nsIScriptError::warningFlag,
                                       "XBL");
       return NS_ERROR_FAILURE;
     }
 
     // If the doc is a chrome URI, then we put it into the XUL cache.
 #ifdef MOZ_XUL
-    if (IsChromeOrResourceURI(documentURI)) {
+    if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
       nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
       if (cache && cache->IsEnabled())
         cache->PutXBLDocumentInfo(info);
     }
 #endif
   
     bindingManager->PutXBLDocumentInfo(info);
 
@@ -528,16 +493,29 @@ nsXBLService::~nsXBLService(void)
 
     // At this point, the only hash table entries should be for referenced
     // XBL class structs held by unfinalized JS binding objects.
     delete gClassTable;
     gClassTable = nsnull;
   }
 }
 
+// static
+bool
+nsXBLService::IsChromeOrResourceURI(nsIURI* aURI)
+{
+  bool isChrome = false;
+  bool isResource = false;
+  if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && 
+      NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)))
+      return (isChrome || isResource);
+  return false;
+}
+
+
 // This function loads a particular XBL file and installs all of the bindings
 // onto the element.
 NS_IMETHODIMP
 nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL,
                            nsIPrincipal* aOriginPrincipal, bool aAugmentFlag,
                            nsXBLBinding** aBinding, bool* aResolveStyle) 
 {
   NS_PRECONDITION(aOriginPrincipal, "Must have an origin principal");
@@ -874,164 +852,84 @@ nsXBLService::GetBinding(nsIContent* aBo
   NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(protoBinding->BindingURI()),
                  NS_ERROR_OUT_OF_MEMORY);
   nsCOMPtr<nsIURI> altBindingURI = protoBinding->AlternateBindingURI();
   if (altBindingURI) {
     NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(altBindingURI),
                    NS_ERROR_OUT_OF_MEMORY);
   }
 
-  nsCOMPtr<nsIContent> child = protoBinding->GetBindingElement();
-
   // Our prototype binding must have all its resources loaded.
   bool ready = protoBinding->LoadResources();
   if (!ready) {
     // Add our bound element to the protos list of elts that should
     // be notified when the stylesheets and scripts finish loading.
     protoBinding->AddResourceListener(aBoundElement);
     return NS_ERROR_FAILURE; // The binding isn't ready yet.
   }
 
-  // If our prototype already has a base, then don't check for an "extends" attribute.
-  nsRefPtr<nsXBLBinding> baseBinding;
-  bool hasBase = protoBinding->HasBasePrototype();
+  rv = protoBinding->ResolveBaseBinding();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsIURI* baseBindingURI;
   nsXBLPrototypeBinding* baseProto = protoBinding->GetBasePrototype();
   if (baseProto) {
-    // Use the NodePrincipal() of the <binding> element in question
-    // for the security check.
-    rv = GetBinding(aBoundElement, baseProto->BindingURI(), aPeekOnly,
+    baseBindingURI = baseProto->BindingURI();
+  }
+  else {
+    baseBindingURI = protoBinding->GetBaseBindingURI();
+    if (baseBindingURI) {
+      PRUint32 count = aDontExtendURIs.Length();
+      for (PRUint32 index = 0; index < count; ++index) {
+        bool equal;
+        rv = aDontExtendURIs[index]->Equals(baseBindingURI, &equal);
+        NS_ENSURE_SUCCESS(rv, rv);
+        if (equal) {
+          nsCAutoString spec, basespec;
+          protoBinding->BindingURI()->GetSpec(spec);
+          NS_ConvertUTF8toUTF16 protoSpec(spec);
+          baseBindingURI->GetSpec(basespec);
+          NS_ConvertUTF8toUTF16 baseSpecUTF16(basespec);
+          const PRUnichar* params[] = { protoSpec.get(), baseSpecUTF16.get() };
+          nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES,
+                                          "CircularExtendsBinding",
+                                          params, NS_ARRAY_LENGTH(params),
+                                          boundDocument->GetDocumentURI(),
+                                          EmptyString(), 0, 0,
+                                          nsIScriptError::warningFlag,
+                                          "XBL");
+          return NS_ERROR_ILLEGAL_VALUE;
+        }
+      }
+    }
+  }
+
+  nsRefPtr<nsXBLBinding> baseBinding;
+  if (baseBindingURI) {
+    nsCOMPtr<nsIContent> child = protoBinding->GetBindingElement();
+    rv = GetBinding(aBoundElement, baseBindingURI, aPeekOnly,
                     child->NodePrincipal(), aIsReady,
                     getter_AddRefs(baseBinding), aDontExtendURIs);
     if (NS_FAILED(rv))
       return rv; // We aren't ready yet.
   }
-  else if (hasBase) {
-    // Check for the presence of 'extends' and 'display' attributes
-    nsAutoString display, extends;
-    child->GetAttr(kNameSpaceID_None, nsGkAtoms::display, display);
-    child->GetAttr(kNameSpaceID_None, nsGkAtoms::extends, extends);
-    bool hasDisplay = !display.IsEmpty();
-    bool hasExtends = !extends.IsEmpty();
-    
-    nsAutoString value(extends);
-         
-    if (!hasExtends) 
-      protoBinding->SetHasBasePrototype(false);
-    else {
-      // Now slice 'em up to see what we've got.
-      nsAutoString prefix;
-      PRInt32 offset;
-      if (hasDisplay) {
-        offset = display.FindChar(':');
-        if (-1 != offset) {
-          display.Left(prefix, offset);
-          display.Cut(0, offset+1);
-        }
-      }
-      else if (hasExtends) {
-        offset = extends.FindChar(':');
-        if (-1 != offset) {
-          extends.Left(prefix, offset);
-          extends.Cut(0, offset+1);
-          display = extends;
-        }
-      }
-
-      nsAutoString nameSpace;
-
-      if (!prefix.IsEmpty()) {
-        child->LookupNamespaceURI(prefix, nameSpace);
-
-        if (!nameSpace.IsEmpty()) {
-          if (!hasDisplay) {
-            // We extend some widget/frame. We don't really have a
-            // base binding.
-            protoBinding->SetHasBasePrototype(false);
-            //child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::extends, false);
-          }
-
-          PRInt32 nameSpaceID =
-            nsContentUtils::NameSpaceManager()->GetNameSpaceID(nameSpace);
-
-          nsCOMPtr<nsIAtom> tagName = do_GetAtom(display);
-          // Check the white list
-          if (!CheckTagNameWhiteList(nameSpaceID, tagName)) {
-            const PRUnichar* params[] = { display.get() };
-            nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES,
-                                            "InvalidExtendsBinding",
-                                            params, ArrayLength(params),
-                                            nsnull,
-                                            EmptyString(), 0, 0,
-                                            nsIScriptError::errorFlag,
-                                            "XBL", doc);
-            NS_ASSERTION(!IsChromeOrResourceURI(aURI),
-                         "Invalid extends value");
-            return NS_ERROR_ILLEGAL_VALUE;
-          }
-
-          protoBinding->SetBaseTag(nameSpaceID, tagName);
-        }
-      }
-
-      if (hasExtends && (hasDisplay || nameSpace.IsEmpty())) {
-        // Look up the prefix.
-        // We have a base class binding. Load it right now.
-        nsCOMPtr<nsIURI> bindingURI;
-        rv = NS_NewURI(getter_AddRefs(bindingURI), value,
-                       doc->GetDocumentCharacterSet().get(),
-                       doc->GetDocBaseURI());
-        NS_ENSURE_SUCCESS(rv, rv);
-        
-        PRUint32 count = aDontExtendURIs.Length();
-        for (PRUint32 index = 0; index < count; ++index) {
-          bool equal;
-          rv = aDontExtendURIs[index]->Equals(bindingURI, &equal);
-          NS_ENSURE_SUCCESS(rv, rv);
-          if (equal) {
-            nsCAutoString spec;
-            protoBinding->BindingURI()->GetSpec(spec);
-            NS_ConvertUTF8toUTF16 protoSpec(spec);
-            const PRUnichar* params[] = { protoSpec.get(), value.get() };
-            nsContentUtils::ReportToConsole(nsContentUtils::eXBL_PROPERTIES,
-                                            "CircularExtendsBinding",
-                                            params, ArrayLength(params),
-                                            nsnull,
-                                            EmptyString(), 0, 0,
-                                            nsIScriptError::warningFlag,
-                                            "XBL", boundDocument);
-            return NS_ERROR_ILLEGAL_VALUE;
-          }
-        }
-
-        // Use the NodePrincipal() of the <binding> element in question
-        // for the security check.
-        rv = GetBinding(aBoundElement, bindingURI, aPeekOnly,
-                        child->NodePrincipal(), aIsReady,
-                        getter_AddRefs(baseBinding), aDontExtendURIs);
-        if (NS_FAILED(rv))
-          return rv; // Binding not yet ready or an error occurred.
-        if (!aPeekOnly) {
-          // Make sure to set the base prototype.
-          baseProto = baseBinding->PrototypeBinding();
-          protoBinding->SetBasePrototype(baseProto);
-          child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::extends, false);
-          child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::display, false);
-        }
-      }
-    }
-  }
 
   *aIsReady = true;
+
   if (!aPeekOnly) {
     // Make a new binding
     nsXBLBinding *newBinding = new nsXBLBinding(protoBinding);
     NS_ENSURE_TRUE(newBinding, NS_ERROR_OUT_OF_MEMORY);
 
-    if (baseBinding)
-      newBinding->SetBaseBinding(baseBinding);
+    if (baseBinding) {
+      if (!baseProto) {
+        protoBinding->SetBasePrototype(baseBinding->PrototypeBinding());
+      }
+       newBinding->SetBaseBinding(baseBinding);
+    }
 
     NS_ADDREF(*aResult = newBinding);
   }
 
   return NS_OK;
 }
 
 static bool SchemeIs(nsIURI* aURI, const char* aScheme)
--- a/content/xbl/src/nsXBLService.h
+++ b/content/xbl/src/nsXBLService.h
@@ -59,16 +59,18 @@ class nsSupportsHashtable;
 class nsHashtable;
 
 class nsXBLService : public nsIXBLService,
                      public nsIObserver,
                      public nsSupportsWeakReference
 {
   NS_DECL_ISUPPORTS
 
+  static bool IsChromeOrResourceURI(nsIURI* aURI);
+
   // This function loads a particular XBL file and installs all of the bindings
   // onto the element.  aOriginPrincipal must not be null here.
   NS_IMETHOD LoadBindings(nsIContent* aContent, nsIURI* aURL,
                           nsIPrincipal* aOriginPrincipal, bool aAugmentFlag,
                           nsXBLBinding** aBinding, bool* aResolveStyle);
 
   // Indicates whether or not a binding is fully loaded.
   NS_IMETHOD BindingReady(nsIContent* aBoundElement, nsIURI* aURI, bool* aIsReady);