Bug 661980: Add ability to make interfaces scriptable but not scriptimplementable. r=bsmedberg

This commit is contained in:
Jonas Sicking 2011-06-16 12:21:25 -07:00
parent 8bfa7dd3e7
commit caef7c47a8
16 changed files with 132 additions and 20 deletions

View File

@ -53,7 +53,7 @@ interface nsIDOMBlob;
#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;
@ -64,7 +64,7 @@ interface nsIXMLHttpRequestEventTarget : nsIDOMEventTarget {
attribute nsIDOMEventListener onloadend;
};
[scriptable, uuid(09ff3682-7759-4441-a765-f70e1a1fabcf)]
[scriptable, builtinclass, uuid(09ff3682-7759-4441-a765-f70e1a1fabcf)]
interface nsIXMLHttpRequestUpload : nsIXMLHttpRequestEventTarget {
// for future use
};

View File

@ -47,7 +47,7 @@
* 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
{
/**

View File

@ -128,13 +128,13 @@ interface nsIWorkerScope : nsIWorkerGlobalScope
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 */);

View File

@ -166,8 +166,9 @@ nsXPCWrappedJSClass::GetNewOrUsed(XPCCallContext& ccx, REFNSIID aIID,
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);
@ -295,8 +296,9 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(XPCCallContext& ccx,
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;
}

View File

@ -89,6 +89,7 @@ _TEST_FILES = bug500931_helper.html \
test2_bug629331.html \
test_bug618017.html \
test_bug636097.html \
test_bug661980.html \
test_bug650273.html \
file_bug650273.html \
file_bug658560.html \

View File

@ -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>

View File

@ -49,7 +49,7 @@
* pointer identity.
*/
[scriptable, uuid(1f341018-521a-49de-b806-1bef5c9a00b0)]
[scriptable, builtinclass, uuid(1f341018-521a-49de-b806-1bef5c9a00b0)]
interface nsIAtom : nsISupports
{
/**

View File

@ -549,6 +549,7 @@ class Interface(object):
class InterfaceAttributes(object):
uuid = None
scriptable = False
builtinclass = False
function = False
deprecated = False
noscript = False
@ -565,12 +566,16 @@ class InterfaceAttributes(object):
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),
@ -605,6 +610,8 @@ class InterfaceAttributes(object):
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)

View File

@ -76,7 +76,7 @@ NS_GetXPTCallStub(REFNSIID aIID, nsIXPTCProxy* aOuter,
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);

View File

@ -58,13 +58,14 @@ 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;

View File

@ -273,6 +273,7 @@ xptiInterfaceInfoManager::VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* ifa
//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);

View File

@ -250,7 +250,7 @@ public:
};
// Additional bit flags...
enum {SCRIPTABLE = 4};
enum {SCRIPTABLE = 4, BUILTINCLASS = 8};
PRUint8 GetResolveState() const {return mFlags.GetState();}
@ -261,6 +261,10 @@ public:
{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;}
@ -288,6 +292,10 @@ public:
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);
@ -363,6 +371,7 @@ public:
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)
{

View File

@ -520,6 +520,9 @@ typelib_interface(TreeState *state)
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) {

View File

@ -885,23 +885,40 @@ xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data)
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;

View File

@ -264,12 +264,14 @@ struct XPTInterfaceDescriptor {
#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,

View File

@ -845,7 +845,7 @@ class Interface(object):
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
@ -857,6 +857,7 @@ class Interface(object):
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:
@ -922,11 +923,13 @@ class Interface(object):
(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):
@ -965,6 +968,8 @@ class Interface(object):
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):
@ -1260,7 +1265,9 @@ class Typelib(object):
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: