Bug 661980: Add ability to make interfaces scriptable but not scriptimplementable. r=bsmedberg
authorJonas Sicking <jonas@sicking.cc>
Thu, 16 Jun 2011 12:21:25 -0700
changeset 72061 8e30eba8ff6456654f618071faa71b7ca8a7ea82
parent 72060 37db25250817ccb627a212a730ef6e0911974a1e
child 72062 56854b8cf1a6a146f52bd0f2aed944e08960b7e8
push id159
push usereakhgari@mozilla.com
push dateTue, 16 Aug 2011 17:53:11 +0000
treeherdermozilla-beta@8786e3e49240 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs661980
milestone7.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 661980: Add ability to make interfaces scriptable but not scriptimplementable. r=bsmedberg
content/base/public/nsIXMLHttpRequest.idl
dom/interfaces/events/nsIDOMEventTarget.idl
dom/interfaces/threads/nsIDOMWorkers.idl
js/src/xpconnect/src/xpcwrappedjsclass.cpp
js/src/xpconnect/tests/mochitest/Makefile.in
js/src/xpconnect/tests/mochitest/test_bug661980.html
xpcom/ds/nsIAtom.idl
xpcom/idl-parser/xpidl.py
xpcom/reflect/xptcall/src/xptcall.cpp
xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl
xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
xpcom/reflect/xptinfo/src/xptiprivate.h
xpcom/typelib/xpidl/xpidl_typelib.c
xpcom/typelib/xpidl/xpidl_util.c
xpcom/typelib/xpt/public/xpt_struct.h
xpcom/typelib/xpt/tools/xpt.py
--- a/content/base/public/nsIXMLHttpRequest.idl
+++ b/content/base/public/nsIXMLHttpRequest.idl
@@ -48,28 +48,28 @@ interface nsPIDOMWindow;
 interface nsIInputStream;
 interface nsIDOMBlob;
 
 %{C++
 // for jsval
 #include "jsapi.h"
 %}
 
-[scriptable, uuid(dea238a1-240f-45f4-9f07-7769bc69eb76)]
+[scriptable, builtinclass, uuid(dea238a1-240f-45f4-9f07-7769bc69eb76)]
 interface nsIXMLHttpRequestEventTarget : nsIDOMEventTarget {
   // event handler attributes
   attribute nsIDOMEventListener onabort;
   attribute nsIDOMEventListener onerror;
   attribute nsIDOMEventListener onload;
   attribute nsIDOMEventListener onloadstart;
   attribute nsIDOMEventListener onprogress;
   attribute nsIDOMEventListener onloadend;
 };
 
-[scriptable, uuid(09ff3682-7759-4441-a765-f70e1a1fabcf)]
+[scriptable, builtinclass, uuid(09ff3682-7759-4441-a765-f70e1a1fabcf)]
 interface nsIXMLHttpRequestUpload : nsIXMLHttpRequestEventTarget {
   // for future use
 };
 
 /**
  * Mozilla's XMLHttpRequest is modelled after Microsoft's IXMLHttpRequest
  * object. The goal has been to make Mozilla's version match Microsoft's
  * version as closely as possible, but there are bound to be some differences.
--- a/dom/interfaces/events/nsIDOMEventTarget.idl
+++ b/dom/interfaces/events/nsIDOMEventTarget.idl
@@ -42,17 +42,17 @@
 /**
  * The nsIDOMEventTarget interface is the interface implemented by all
  * event targets in the Document Object Model.
  *
  * For more information on this interface please see 
  * http://www.w3.org/TR/DOM-Level-2-Events/
  */
 
-[scriptable, uuid(1c773b30-d1cf-11d2-bd95-00805f8ae3f4)]
+[scriptable, builtinclass, uuid(1c773b30-d1cf-11d2-bd95-00805f8ae3f4)]
 interface nsIDOMEventTarget : nsISupports
 {
   /**
    * This method allows the registration of event listeners on the event target.
    * If an EventListener is added to an EventTarget while it is processing an
    * event, it will not be triggered by the current actions but may be 
    * triggered during a later stage of event flow, such as the bubbling phase.
    * 
--- a/dom/interfaces/threads/nsIDOMWorkers.idl
+++ b/dom/interfaces/threads/nsIDOMWorkers.idl
@@ -123,23 +123,23 @@ interface nsIWorkerScope : nsIWorkerGlob
   void postMessage(/* in JSObject aMessage */);
 
   void close();
 
   attribute nsIDOMEventListener onmessage;
   attribute nsIDOMEventListener onclose;
 };
 
-[scriptable, uuid(b90b7561-b5e2-4545-84b0-280dbaaa94ea)]
+[scriptable, builtinclass, uuid(b90b7561-b5e2-4545-84b0-280dbaaa94ea)]
 interface nsIAbstractWorker : nsIDOMEventTarget
 {
   attribute nsIDOMEventListener onerror;
 };
 
-[scriptable, uuid(daf945c3-8d29-4724-8939-dd383f7d27a7)]
+[scriptable, builtinclass, uuid(daf945c3-8d29-4724-8939-dd383f7d27a7)]
 interface nsIWorker : nsIAbstractWorker
 {
   void postMessage(/* in JSObject aMessage */);
 
   attribute nsIDOMEventListener onmessage;
 
   void terminate();
 };
--- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp
+++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp
@@ -161,18 +161,19 @@ nsXPCWrappedJSClass::GetNewOrUsed(XPCCal
     }
 
     if(!clazz)
     {
         nsCOMPtr<nsIInterfaceInfo> info;
         ccx.GetXPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
         if(info)
         {
-            PRBool canScript;
+            PRBool canScript, isBuiltin;
             if(NS_SUCCEEDED(info->IsScriptable(&canScript)) && canScript &&
+               NS_SUCCEEDED(info->IsBuiltinClass(&isBuiltin)) && !isBuiltin &&
                nsXPConnect::IsISupportsDescendant(info))
             {
                 clazz = new nsXPCWrappedJSClass(ccx, aIID, info);
                 if(clazz && !clazz->mDescriptors)
                     NS_RELEASE(clazz);  // sets clazz to nsnull
             }
         }
     }
@@ -290,18 +291,19 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
     // implement intentionally (for security) unscriptable interfaces.
     // We so often ask for nsISupports that we can short-circuit the test...
     if(!aIID.Equals(NS_GET_IID(nsISupports)))
     {
         nsCOMPtr<nsIInterfaceInfo> info;
         ccx.GetXPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
         if(!info)
             return nsnull;
-        PRBool canScript;
-        if(NS_FAILED(info->IsScriptable(&canScript)) || !canScript)
+        PRBool canScript, isBuiltin;
+        if(NS_FAILED(info->IsScriptable(&canScript)) || !canScript ||
+           NS_FAILED(info->IsBuiltinClass(&isBuiltin)) || isBuiltin)
             return nsnull;
     }
 
     id = xpc_NewIDObject(cx, jsobj, aIID);
     if(id)
     {
         // Throwing NS_NOINTERFACE is the prescribed way to fail QI from JS. It
         // is not an exception that is ever worth reporting, but we don't want
--- a/js/src/xpconnect/tests/mochitest/Makefile.in
+++ b/js/src/xpconnect/tests/mochitest/Makefile.in
@@ -84,16 +84,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug629227.html \
 		file1_bug629227.html \
 		file2_bug629227.html \
 		test_bug629331.html \
 		test1_bug629331.html \
 		test2_bug629331.html \
 		test_bug618017.html \
 		test_bug636097.html \
+		test_bug661980.html \
 		test_bug650273.html \
 		file_bug650273.html \
 		file_bug658560.html \
 		$(NULL)
 
 ifneq ($(OS_TARGET),Android)
 ifndef MOZ_PLATFORM_MAEMO
 _TEST_FILES +=	test_bug657267.html \
new file mode 100644
--- /dev/null
+++ b/js/src/xpconnect/tests/mochitest/test_bug661980.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=661980
+-->
+<head>
+  <title>Test for Bug 661980</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=661980">Mozilla Bug 661980</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 661980 **/
+
+// While not currently needed, make this as similar as possible to a real
+// EventTarget just to make sure that we're tripping on the wrapping and
+// nothing else.
+var fakeTarget = {
+  addEventListener: function() {},
+  removeEventListener: function() {},
+  dispatchEvent: function() {}
+}
+
+var mouseevent = document.createEvent("MouseEvent");
+var didThrow = false;
+dump("hello nurse");
+try {
+  mouseevent.initMouseEvent("mouseover",
+                            false, false,
+                            window,
+                            1, 2, 3, 4, 5,
+                            false, false, false, false,
+                            0,
+                            fakeTarget);
+}
+catch (ex) {
+  didThrow = true;
+}
+ok(didThrow, "should not be able to implement EventTarget using script");
+
+mouseevent.initMouseEvent("mouseout",
+                          false, false,
+                          window,
+                          1, 2, 3, 4, 5,
+                          false, false, false, false,
+                          0,
+                          document.body);
+is(mouseevent.type, "mouseout",
+   "should able to implement EventTarget using Element");
+
+</script>
+</pre>
+</body>
+</html>
--- a/xpcom/ds/nsIAtom.idl
+++ b/xpcom/ds/nsIAtom.idl
@@ -44,17 +44,17 @@
 %}
 
 /*
  * Should this really be scriptable?  Using atoms from script or proxies
  * could be dangerous since double-wrapping could lead to loss of
  * pointer identity.
  */
  
-[scriptable, uuid(1f341018-521a-49de-b806-1bef5c9a00b0)]
+[scriptable, builtinclass, uuid(1f341018-521a-49de-b806-1bef5c9a00b0)]
 interface nsIAtom : nsISupports
 {
   /**
    * Get the Unicode or UTF8 value for the string
    */
   [binaryname(ScriptableToString)] AString toString(); 
   [noscript] AUTF8String toUTF8String();
   
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -544,38 +544,43 @@ class Interface(object):
         if c.kind != 'const':
             raise IDLError("symbol '%s' is not a constant", c.location)
 
         return c.getValue()
 
 class InterfaceAttributes(object):
     uuid = None
     scriptable = False
+    builtinclass = False
     function = False
     deprecated = False
     noscript = False
 
     def setuuid(self, value):
         self.uuid = value.lower()
 
     def setscriptable(self):
         self.scriptable = True
 
     def setfunction(self):
         self.function = True
 
     def setnoscript(self):
         self.noscript = True
 
+    def setbuiltinclass(self):
+        self.builtinclass = True
+
     def setdeprecated(self):
         self.deprecated = True
 
     actions = {
         'uuid':       (True, setuuid),
         'scriptable': (False, setscriptable),
+        'builtinclass': (False, setbuiltinclass),
         'function':   (False, setfunction),
         'noscript':   (False, setnoscript),
         'deprecated': (False, setdeprecated),
         'object':     (False, lambda self: True),
         }
 
     def __init__(self, attlist, location):
         def badattribute(self):
@@ -600,16 +605,18 @@ class InterfaceAttributes(object):
             raise IDLError("interface has no uuid", location)
 
     def __str__(self):
         l = []
         if self.uuid:
             l.append("\tuuid: %s\n" % self.uuid)
         if self.scriptable:
             l.append("\tscriptable\n")
+        if self.builtinclass:
+            l.append("\tbuiltinclass\n")
         if self.function:
             l.append("\tfunction\n")
         return "".join(l)
 
 class ConstMember(object):
     kind = 'const'
     def __init__(self, type, name, value, location, doccomments):
         self.type = type
--- a/xpcom/reflect/xptcall/src/xptcall.cpp
+++ b/xpcom/reflect/xptcall/src/xptcall.cpp
@@ -71,17 +71,17 @@ NS_GetXPTCallStub(REFNSIID aIID, nsIXPTC
 {
     NS_ENSURE_ARG(aOuter && aResult);
 
     xptiInterfaceInfoManager *iim =
         xptiInterfaceInfoManager::GetSingleton();
     NS_ENSURE_TRUE(iim, NS_ERROR_NOT_INITIALIZED);
 
     xptiInterfaceEntry *iie = iim->GetInterfaceEntryForIID(&aIID);
-    if (!iie || !iie->EnsureResolved())
+    if (!iie || !iie->EnsureResolved() || iie->GetBuiltinClassFlag())
         return NS_ERROR_FAILURE;
 
     nsXPTCStubBase* newbase = new nsXPTCStubBase(aOuter, iie);
     if (!newbase)
         return NS_ERROR_OUT_OF_MEMORY;
 
     *aResult = newbase;
     return NS_OK;
--- a/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl
+++ b/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl
@@ -53,23 +53,24 @@
 %{C++
 class nsXPTMethodInfo;
 class nsXPTConstant;
 class nsXPTParamInfo;
 class nsXPTType;
 %}
 
 /* this is NOT intended to be scriptable */
-[uuid(215DBE04-94A7-11d2-BA58-00805F8A5DD7)]
+[uuid(7de126a2-ef4b-4e3b-a952-78ce4c133e38)]
 interface nsIInterfaceInfo : nsISupports
 {
     readonly attribute string   name;
     readonly attribute nsIIDPtr InterfaceIID;
 
     PRBool isScriptable();
+    PRBool isBuiltinClass();
 
     readonly attribute nsIInterfaceInfo parent;
 
     /**
     * These include counts for parent (and all ancestors).
     */
     readonly attribute PRUint16 methodCount;
     readonly attribute PRUint16 constantCount;
--- a/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
+++ b/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
@@ -268,16 +268,17 @@ xptiInterfaceInfoManager::VerifyAndAddEn
                                        iface->iid,
                                        iface->interface_descriptor,
                                        typelib);
     if (!entry)
         return;
 
     //XXX  We should SetHeader too as part of the validation, no?
     entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags));
+    entry->SetBuiltinClassFlag(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags));
 
     mWorkingSet.mIIDTable.Put(entry->IID(), entry);
     mWorkingSet.mNameTable.Put(entry->GetTheName(), entry);
 
     typelib->SetEntryAt(idx, entry);
 
     LOG_AUTOREG(("      added interface: %s\n", iface->name));
 }
--- a/xpcom/reflect/xptinfo/src/xptiprivate.h
+++ b/xpcom/reflect/xptinfo/src/xptiprivate.h
@@ -245,27 +245,31 @@ public:
 
     enum {
         PARTIALLY_RESOLVED    = 1,
         FULLY_RESOLVED        = 2,
         RESOLVE_FAILED        = 3
     };
     
     // Additional bit flags...
-    enum {SCRIPTABLE = 4};
+    enum {SCRIPTABLE = 4, BUILTINCLASS = 8};
 
     PRUint8 GetResolveState() const {return mFlags.GetState();}
     
     PRBool IsFullyResolved() const 
         {return GetResolveState() == (PRUint8) FULLY_RESOLVED;}
 
     void   SetScriptableFlag(PRBool on)
                 {mFlags.SetFlagBit(PRUint8(SCRIPTABLE),on);}
     PRBool GetScriptableFlag() const
                 {return mFlags.GetFlagBit(PRUint8(SCRIPTABLE));}
+    void   SetBuiltinClassFlag(PRBool on)
+                {mFlags.SetFlagBit(PRUint8(BUILTINCLASS),on);}
+    PRBool GetBuiltinClassFlag() const
+                {return mFlags.GetFlagBit(PRUint8(BUILTINCLASS));}
 
     const nsID* GetTheIID()  const {return &mIID;}
     const char* GetTheName() const {return mName;}
 
     PRBool EnsureResolved()
         {return IsFullyResolved() ? PR_TRUE : Resolve();}
 
     nsresult GetInterfaceInfo(xptiInterfaceInfo** info);
@@ -283,16 +287,20 @@ public:
     const nsID& IID() const { return mIID; }
 
     //////////////////////
     // These non-virtual methods handle the delegated nsIInterfaceInfo methods.
 
     nsresult GetName(char * *aName);
     nsresult GetIID(nsIID * *aIID);
     nsresult IsScriptable(PRBool *_retval);
+    nsresult IsBuiltinClass(PRBool *_retval) {
+        *_retval = GetBuiltinClassFlag();
+        return NS_OK;
+    }
     // Except this one.
     //nsresult GetParent(nsIInterfaceInfo * *aParent);
     nsresult GetMethodCount(PRUint16 *aMethodCount);
     nsresult GetConstantCount(PRUint16 *aConstantCount);
     nsresult GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info);
     nsresult GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info);
     nsresult GetConstant(PRUint16 index, const nsXPTConstant * *constant);
     nsresult GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval);
@@ -358,16 +366,17 @@ class xptiInterfaceInfo : public nsIInte
 {
 public:
     NS_DECL_ISUPPORTS
 
     // Use delegation to implement (most!) of nsIInterfaceInfo.
     NS_IMETHOD GetName(char * *aName) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName); }
     NS_IMETHOD GetInterfaceIID(nsIID * *aIID) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID); }
     NS_IMETHOD IsScriptable(PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval); }
+    NS_IMETHOD IsBuiltinClass(PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsBuiltinClass(_retval); }
     // Except this one.
     NS_IMETHOD GetParent(nsIInterfaceInfo * *aParent) 
     {
         if(!EnsureResolved() || !EnsureParent())
             return NS_ERROR_UNEXPECTED;
         NS_IF_ADDREF(*aParent = mParent);
         return NS_OK;
     }
--- a/xpcom/typelib/xpidl/xpidl_typelib.c
+++ b/xpcom/typelib/xpidl/xpidl_typelib.c
@@ -515,16 +515,19 @@ typelib_interface(TreeState *state)
         return FALSE;
 
     if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable"))
         interface_flags |= XPT_ID_SCRIPTABLE;
 
     if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "function"))
         interface_flags |= XPT_ID_FUNCTION;
 
+    if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "builtinclass"))
+        interface_flags |= XPT_ID_BUILTINCLASS;
+
     ide = FindInterfaceByName(HEADER(state)->interface_directory,
                               HEADER(state)->num_interfaces, name);
     if (!ide) {
         IDL_tree_error(iface, "ERROR: didn't find interface %s in "
                        "IDE block. Giving up.\n", name);
         return FALSE;
     }
 
--- a/xpcom/typelib/xpidl/xpidl_util.c
+++ b/xpcom/typelib/xpidl/xpidl_util.c
@@ -880,33 +880,50 @@ xpidl_list_foreach(IDL_tree p, IDL_tree_
 }
 
 /*
  * Verify that the interface declaration is correct
  */
 gboolean
 verify_interface_declaration(IDL_tree interface_tree)
 {
+    gboolean scriptable =
+      IDL_tree_property_get(IDL_INTERFACE(interface_tree).ident,
+                            "scriptable") != NULL;
+    gboolean builtinclass =
+      IDL_tree_property_get(IDL_INTERFACE(interface_tree).ident,
+                            "builtinclass") != NULL;
+
     IDL_tree iter;
     /* 
      * If we have the scriptable attribute then make sure all of our direct
      * parents have it as well.
-     * NOTE: We don't recurse since all interfaces will fall through here
+     * NOTE: We don't recurse since all interfaces will come through here
      */
-    if (IDL_tree_property_get(IDL_INTERFACE(interface_tree).ident, 
-        "scriptable")) {
+    if (scriptable || !builtinclass) {
         for (iter = IDL_INTERFACE(interface_tree).inheritance_spec; iter; 
             iter = IDL_LIST(iter).next) {
-            if (IDL_tree_property_get(
-                IDL_INTERFACE(iter).ident, "scriptable") == 0) {
+            if (scriptable &&
+                IDL_tree_property_get(
+                  IDL_INTERFACE(iter).ident, "scriptable") == 0) {
                 XPIDL_WARNING((interface_tree,IDL_WARNING1,
                     "%s is scriptable but inherits from the non-scriptable interface %s\n",
                     IDL_IDENT(IDL_INTERFACE(interface_tree).ident).str,
                     IDL_IDENT(IDL_INTERFACE(iter).ident).str));
             }
+            if (!builtinclass &&
+                IDL_tree_property_get(
+                  IDL_INTERFACE(iter).ident, "builtinclass")) {
+                IDL_tree_error(interface_tree,
+                               "%s is not [builtinclass] but extends "
+                               "[builtinclass] interface %s",
+                               IDL_IDENT(IDL_INTERFACE(interface_tree).ident).str,
+                               IDL_IDENT(IDL_INTERFACE(iter).ident).str);
+                return FALSE;
+            }
         }
     }
     return TRUE;
 }
 
 /*
  * Return a pointer to the start of the base filename of path
  */
--- a/xpcom/typelib/xpt/public/xpt_struct.h
+++ b/xpcom/typelib/xpt/public/xpt_struct.h
@@ -259,22 +259,24 @@ struct XPTInterfaceDescriptor {
     */
 
     XPTTypeDescriptor       *additional_types;
     PRUint16                num_additional_types;
 };
 
 #define XPT_ID_SCRIPTABLE           0x80
 #define XPT_ID_FUNCTION             0x40
-#define XPT_ID_FLAGMASK             0xc0
+#define XPT_ID_BUILTINCLASS         0x20
+#define XPT_ID_FLAGMASK             0xe0
 #define XPT_ID_TAGMASK              (~XPT_ID_FLAGMASK)
 #define XPT_ID_TAG(id)              ((id).flags & XPT_ID_TAGMASK)
 
 #define XPT_ID_IS_SCRIPTABLE(flags) (!!(flags & XPT_ID_SCRIPTABLE))
 #define XPT_ID_IS_FUNCTION(flags) (!!(flags & XPT_ID_FUNCTION))
+#define XPT_ID_IS_BUILTINCLASS(flags) (!!(flags & XPT_ID_BUILTINCLASS))
 
 extern XPT_PUBLIC_API(PRBool)
 XPT_GetInterfaceIndexByName(XPTInterfaceDirectoryEntry *ide_block,
                             PRUint16 num_interfaces, char *name, 
                             PRUint16 *indexp);
 
 extern XPT_PUBLIC_API(XPTInterfaceDescriptor *)
 XPT_NewInterfaceDescriptor(XPTArena *arena, 
--- a/xpcom/typelib/xpt/tools/xpt.py
+++ b/xpcom/typelib/xpt/tools/xpt.py
@@ -840,28 +840,29 @@ class Interface(object):
     """
     _direntry = struct.Struct(">16sIII")    
     _descriptorstart = struct.Struct(">HH")
 
     UNRESOLVED_IID = "00000000-0000-0000-0000-000000000000"
     
     def __init__(self, name, iid=UNRESOLVED_IID, namespace="",
                  resolved=False, parent=None, methods=[], constants=[],
-                 scriptable=False, function=False):
+                 scriptable=False, function=False, builtinclass=False):
         self.resolved = resolved
         #TODO: should validate IIDs!
         self.iid = iid
         self.name = name
         self.namespace = namespace
         # if unresolved, all the members following this are unusable
         self.parent = parent
         self.methods = list(methods)
         self.constants = list(constants)
         self.scriptable = scriptable
         self.function = function
+        self.builtinclass = builtinclass
         # For sanity, if someone constructs an Interface and passes
         # in methods or constants, then it's resolved.
         if self.methods or self.constants:
             # make sure it has a valid IID
             if self.iid == Interface.UNRESOLVED_IID:
                 raise DataError, "Cannot instantiate Interface %s containing methods or constants with an unresolved IID" % self.name
             self.resolved = True
         # These are only used for writing out the interface
@@ -917,21 +918,23 @@ class Interface(object):
         for i in range(num_constants):
             c, offset = Constant.read(typelib, map, data_pool, offset)
             self.constants.append(c)
         # Read flags
         start = data_pool + offset - 1
         (flags, ) = struct.unpack(">B", map[start:start + struct.calcsize(">B")])
         offset = offset + struct.calcsize(">B")
         # only the first two bits are flags
-        flags &= 0xC0
+        flags &= 0xE0
         if flags & 0x80:
             self.scriptable = True
         if flags & 0x40:
             self.function = True
+        if flags & 0x20:
+            self.builtinclass = True
         self.resolved = True
 
     def write_directory_entry(self, file):
         """
         Write an InterfaceDirectoryEntry for this interface
         to |file|, which is assumed to be seeked to the correct offset.
 
         """
@@ -960,16 +963,18 @@ class Interface(object):
         file.write(struct.pack(">H", len(self.constants)))
         for c in self.constants:
             c.write(typelib, file)
         flags = 0
         if self.scriptable:
             flags |= 0x80
         if self.function:
             flags |= 0x40
+        if self.builtinclass:
+            flags |= 0x20
         file.write(struct.pack(">B", flags))
         
     def write_names(self, file, data_pool_offset):
         """
         Write this interface's name and namespace to |file|,
         as well as the names of all of its methods and constants.
         Assumes that |file| is currently seeked to an unused portion
         of the data pool.
@@ -1255,17 +1260,19 @@ class Typelib(object):
             if not i.resolved:
                 out.write("      [Unresolved]\n")
             else:
                 if i.parent:
                     out.write("      Parent: %s::%s\n" % (i.parent.namespace,
                                                     i.parent.name))
                 out.write("""      Flags:
          Scriptable: %s
+         BuiltinClass: %s
          Function: %s\n""" % (i.scriptable and "TRUE" or "FALSE",
+                              i.builtinclass and "TRUE" or "FALSE",
                               i.function and "TRUE" or "FALSE"))
                 out.write("      Methods:\n")
                 if len(i.methods) == 0:
                     out.write("         No Methods\n")
                 else:
                     for m in i.methods:
                         out.write("   %s%s%s%s%s%s%s %s %s(%s);\n" % (
                             m.getter and "G" or " ",