зеркало из https://github.com/mozilla/gecko-dev.git
Bug 648801 (new DOM list bindings) - Generate new DOM bindings. r=bz/jst/mrbkap.
--HG-- extra : rebase_source : 6b34182856cbb4ba3fba8d3001de648b10157a29
This commit is contained in:
Родитель
4ef486c32d
Коммит
075926c483
|
@ -46,12 +46,11 @@ class nsIContent;
|
|||
|
||||
// IID for the nsINodeList interface
|
||||
#define NS_INODELIST_IID \
|
||||
{ 0xe683725e, 0xe75a, 0x4d62, \
|
||||
{ 0x88, 0x5e, 0x5d, 0xd3, 0x1c, 0x27, 0x4b, 0xcc } }
|
||||
{ 0xe60b773e, 0x5d20, 0x43f6, \
|
||||
{ 0xb0, 0x8c, 0xfd, 0x65, 0x26, 0xce, 0xe0, 0x7a } }
|
||||
|
||||
/**
|
||||
* An internal interface that allows QI-less getting of nodes from
|
||||
* node lists and reasonably fast indexOf.
|
||||
* An internal interface for a reasonably fast indexOf.
|
||||
*/
|
||||
class nsINodeList : public nsIDOMNodeList,
|
||||
public nsWrapperCache
|
||||
|
@ -59,11 +58,6 @@ class nsINodeList : public nsIDOMNodeList,
|
|||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODELIST_IID)
|
||||
|
||||
/**
|
||||
* Get the node at the index. Returns null if the index is out of bounds
|
||||
*/
|
||||
virtual nsIContent* GetNodeAt(PRUint32 aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Get the index of the given node in the list. Will return -1 if the node
|
||||
* is not in the list.
|
||||
|
|
|
@ -97,7 +97,6 @@ public:
|
|||
NS_DECL_NSIDOMNODELIST
|
||||
|
||||
// nsINodeList
|
||||
virtual nsIContent* GetNodeAt(PRUint32 aIndex);
|
||||
virtual PRInt32 IndexOf(nsIContent* aContent);
|
||||
|
||||
PRUint32 Length() const {
|
||||
|
@ -294,18 +293,12 @@ public:
|
|||
|
||||
// nsBaseContentList overrides
|
||||
virtual PRInt32 IndexOf(nsIContent *aContent, bool aDoFlush);
|
||||
virtual nsIContent* GetNodeAt(PRUint32 aIndex);
|
||||
virtual PRInt32 IndexOf(nsIContent* aContent);
|
||||
virtual nsINode* GetParentObject()
|
||||
{
|
||||
return mRootNode;
|
||||
}
|
||||
|
||||
// nsIHTMLCollection
|
||||
// GetNodeAt already declared as part of nsINodeList
|
||||
virtual nsISupports* GetNamedItem(const nsAString& aName,
|
||||
nsWrapperCache** aCache);
|
||||
|
||||
// nsContentList public methods
|
||||
NS_HIDDEN_(PRUint32) Length(bool aDoFlush);
|
||||
NS_HIDDEN_(nsIContent*) Item(PRUint32 aIndex, bool aDoFlush);
|
||||
|
|
|
@ -114,7 +114,6 @@ public:
|
|||
NS_DECL_NSIDOMNODELIST
|
||||
|
||||
// nsINodeList interface
|
||||
virtual nsIContent* GetNodeAt(PRUint32 aIndex);
|
||||
virtual PRInt32 IndexOf(nsIContent* aContent);
|
||||
|
||||
void DropReference()
|
||||
|
|
|
@ -46,29 +46,17 @@ class nsWrapperCache;
|
|||
|
||||
// IID for the nsIHTMLCollection interface
|
||||
#define NS_IHTMLCOLLECTION_IID \
|
||||
{ 0x3fe47ab6, 0xb60f, 0x49aa, \
|
||||
{ 0xb5, 0x93, 0xcc, 0xf8, 0xbe, 0xd0, 0x83, 0x19 } }
|
||||
{ 0xdea91ad6, 0x57d1, 0x4e7a, \
|
||||
{ 0xb5, 0x5a, 0xdb, 0xfc, 0x36, 0x7b, 0xc8, 0x22 } }
|
||||
|
||||
/**
|
||||
* An internal interface that allows QI-less getting of nodes from HTML
|
||||
* collections
|
||||
* An internal interface
|
||||
*/
|
||||
class nsIHTMLCollection : public nsIDOMHTMLCollection
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IHTMLCOLLECTION_IID)
|
||||
|
||||
/**
|
||||
* Get the node at the index. Returns null if the index is out of bounds.
|
||||
*/
|
||||
virtual nsIContent* GetNodeAt(PRUint32 aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Get the node for the name. Returns null if no node exists for the name.
|
||||
*/
|
||||
virtual nsISupports* GetNamedItem(const nsAString& aName,
|
||||
nsWrapperCache** aCache) = 0;
|
||||
|
||||
/**
|
||||
* Get the root node for this HTML collection.
|
||||
*/
|
||||
|
|
|
@ -123,19 +123,6 @@ public:
|
|||
// nsIDOMHTMLCollection interface
|
||||
NS_DECL_NSIDOMHTMLCOLLECTION
|
||||
|
||||
virtual nsIContent* GetNodeAt(PRUint32 aIndex)
|
||||
{
|
||||
FlushPendingNotifications();
|
||||
|
||||
return mElements.SafeElementAt(aIndex, nsnull);
|
||||
}
|
||||
virtual nsISupports* GetNamedItem(const nsAString& aName,
|
||||
nsWrapperCache **aCache)
|
||||
{
|
||||
nsISupports *item = NamedItemInternal(aName, PR_TRUE);
|
||||
*aCache = nsnull;
|
||||
return item;
|
||||
}
|
||||
virtual nsINode* GetParentObject()
|
||||
{
|
||||
return mForm;
|
||||
|
@ -2567,3 +2554,19 @@ nsFormControlList::GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aContr
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
nsFormControlList::GetNodeAt(PRUint32 aIndex)
|
||||
{
|
||||
FlushPendingNotifications();
|
||||
|
||||
return mElements.SafeElementAt(aIndex, nsnull);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
nsFormControlList::GetNamedItem(const nsAString& aName, nsWrapperCache **aCache)
|
||||
{
|
||||
nsISupports *item = NamedItemInternal(aName, true);
|
||||
*aCache = nsnull;
|
||||
return item;
|
||||
}
|
||||
|
|
|
@ -71,9 +71,6 @@ public:
|
|||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_NSIDOMHTMLCOLLECTION
|
||||
|
||||
virtual nsIContent* GetNodeAt(PRUint32 aIndex);
|
||||
virtual nsISupports* GetNamedItem(const nsAString& aName,
|
||||
nsWrapperCache **aCache);
|
||||
virtual nsINode* GetParentObject()
|
||||
{
|
||||
return mParent;
|
||||
|
|
|
@ -103,7 +103,6 @@ public:
|
|||
NS_DECL_NSIDOMNODELIST
|
||||
|
||||
// nsINodeList interface
|
||||
virtual nsIContent* GetNodeAt(PRUint32 aIndex);
|
||||
virtual PRInt32 IndexOf(nsIContent* aContent);
|
||||
virtual nsINode *GetParentObject()
|
||||
{
|
||||
|
|
|
@ -8427,9 +8427,9 @@ nsHTMLDocumentSH::GetDocumentAllNodeList(JSContext *cx, JSObject *obj,
|
|||
if (!JSVAL_IS_PRIMITIVE(collection)) {
|
||||
// We already have a node list in our reserved slot, use it.
|
||||
JSObject *obj = JSVAL_TO_OBJECT(collection);
|
||||
if (mozilla::dom::binding::HTMLCollection::objIsList(obj)) {
|
||||
if (mozilla::dom::binding::HTMLCollection::objIsWrapper(obj)) {
|
||||
nsIHTMLCollection *native =
|
||||
mozilla::dom::binding::HTMLCollection::getListObject(obj);
|
||||
mozilla::dom::binding::HTMLCollection::getNative(obj);
|
||||
NS_ADDREF(*nodeList = static_cast<nsContentList*>(native));
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -39,6 +39,12 @@
|
|||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
%{C++
|
||||
class nsWrapperCache;
|
||||
%}
|
||||
|
||||
[ptr] native nsWrapperCachePtr(nsWrapperCache);
|
||||
|
||||
typedef unsigned long long DOMTimeStamp;
|
||||
typedef unsigned long long DOMTimeMilliSec;
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
|
||||
#include "domstubs.idl"
|
||||
|
||||
interface nsIContent;
|
||||
|
||||
/**
|
||||
* The nsIDOMNodeList interface provides the abstraction of an ordered
|
||||
* collection of nodes, without defining or constraining how this collection
|
||||
|
@ -49,9 +51,14 @@
|
|||
* http://www.w3.org/TR/DOM-Level-2-Core/
|
||||
*/
|
||||
|
||||
[scriptable, uuid(a6cf907d-15b3-11d2-932e-00805f8add32)]
|
||||
[scriptable, uuid(496852ba-e48d-4fa5-982e-e0dc1b475bf1)]
|
||||
interface nsIDOMNodeList : nsISupports
|
||||
{
|
||||
nsIDOMNode item(in unsigned long index);
|
||||
readonly attribute unsigned long length;
|
||||
[getter,forward(getNodeAt)] nsIDOMNode item(in unsigned long index);
|
||||
readonly attribute unsigned long length;
|
||||
|
||||
/**
|
||||
* Get the node at the index. Returns null if the index is out of bounds
|
||||
*/
|
||||
[noscript,notxpcom,nostdcall] nsIContent getNodeAt(in unsigned long index);
|
||||
};
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
|
||||
#include "domstubs.idl"
|
||||
|
||||
interface nsIContent;
|
||||
|
||||
/**
|
||||
* The nsIDOMHTMLCollection interface is an interface to a collection
|
||||
* of [X]HTML elements.
|
||||
|
@ -50,11 +52,22 @@
|
|||
* http://www.whatwg.org/specs/web-apps/current-work/
|
||||
*/
|
||||
|
||||
[scriptable, uuid(1af9e026-011d-4d0e-91db-09bcfa3e9622)]
|
||||
[scriptable, uuid(b7ccd7b3-86aa-4322-a50c-b972643bb662)]
|
||||
interface nsIDOMHTMLCollection : nsISupports
|
||||
{
|
||||
readonly attribute unsigned long length;
|
||||
|
||||
nsIDOMNode item(in unsigned long index);
|
||||
nsIDOMNode namedItem(in DOMString name);
|
||||
[getter,forward(getNodeAt)] nsIDOMNode item(in unsigned long index);
|
||||
[getter,forward(getNamedItem)] nsIDOMNode namedItem(in DOMString name);
|
||||
|
||||
/**
|
||||
* Get the node at the index. Returns null if the index is out of bounds.
|
||||
*/
|
||||
[noscript,notxpcom,nostdcall] nsIContent getNodeAt(in unsigned long index);
|
||||
|
||||
/**
|
||||
* Get the node for the name. Returns null if no node exists for the name.
|
||||
*/
|
||||
[noscript,notxpcom,nostdcall] nsISupports getNamedItem(in DOMString name,
|
||||
out nsWrapperCachePtr cache);
|
||||
};
|
||||
|
|
|
@ -49,7 +49,9 @@ MODULE = xpconnect
|
|||
LIBRARY_NAME = xpconnect_s
|
||||
FORCE_STATIC_LIB = 1
|
||||
LIBXUL_LIBRARY = 1
|
||||
EXPORTS = xpcpublic.h
|
||||
EXPORTS = \
|
||||
xpcpublic.h \
|
||||
dombindings_gen.h
|
||||
|
||||
CPPSRCS = \
|
||||
nsScriptError.cpp \
|
||||
|
@ -172,11 +174,50 @@ dom_quickstubs.cpp: $(srcdir)/dom_quickstubs.qsconf \
|
|||
$(ENABLE_TRACEABLE_FLAGS) \
|
||||
$(srcdir)/dom_quickstubs.qsconf
|
||||
|
||||
dombindings.$(OBJ_SUFFIX): dombindings_gen.h \
|
||||
dombindings_gen.cpp
|
||||
|
||||
dombindings_gen.h: $(srcdir)/dombindings.conf \
|
||||
$(srcdir)/dombindingsgen.py \
|
||||
$(srcdir)/codegen.py \
|
||||
$(topsrcdir)/xpcom/idl-parser/header.py \
|
||||
$(topsrcdir)/xpcom/idl-parser/xpidl.py \
|
||||
$(DEPTH)/js/src/js-confdefs.h
|
||||
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||
-I$(topsrcdir)/other-licenses/ply \
|
||||
-I$(topsrcdir)/xpcom/idl-parser \
|
||||
$(srcdir)/dombindingsgen.py \
|
||||
--idlpath=$(DEPTH)/dist/idl \
|
||||
--cachedir=$(DEPTH)/xpcom/idl-parser/cache \
|
||||
--header-output dombindings_gen.h \
|
||||
$(srcdir)/dombindings.conf
|
||||
|
||||
exports:: dombindings_gen.h
|
||||
|
||||
dombindings_gen.cpp: $(srcdir)/dombindings.conf \
|
||||
$(srcdir)/dombindingsgen.py \
|
||||
$(srcdir)/codegen.py \
|
||||
$(topsrcdir)/xpcom/idl-parser/header.py \
|
||||
$(topsrcdir)/xpcom/idl-parser/xpidl.py \
|
||||
$(DEPTH)/js/src/js-confdefs.h
|
||||
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||
-I$(topsrcdir)/other-licenses/ply \
|
||||
-I$(topsrcdir)/xpcom/idl-parser \
|
||||
$(srcdir)/dombindingsgen.py \
|
||||
--idlpath=$(DEPTH)/dist/idl \
|
||||
--cachedir=$(DEPTH)/xpcom/idl-parser/cache \
|
||||
--stub-output dombindings_gen.cpp \
|
||||
--makedepend-output $(MDDEPDIR)/dombindingsgen.pp \
|
||||
$(srcdir)/dombindings.conf
|
||||
|
||||
GARBAGE += \
|
||||
dom_quickstubs.h \
|
||||
dom_quickstubs.cpp \
|
||||
dombindings_gen.h \
|
||||
dombindings_gen.cpp \
|
||||
xpidl_debug \
|
||||
$(MDDEPDIR)/dom_qsgen.pp \
|
||||
$(MDDEPDIR)/dombindingsgen.pp \
|
||||
$(wildcard $(topsrcdir)/other-licenses/ply/ply/*.pyc) \
|
||||
$(wildcard $(topsrcdir)/xpcom/idl-parser/*.pyc) \
|
||||
$(NULL)
|
||||
|
|
|
@ -0,0 +1,685 @@
|
|||
#!/usr/bin/env/python
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Jason Orendorff <jorendorff@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
import xpidl
|
||||
import header
|
||||
import sys
|
||||
import os
|
||||
import string
|
||||
|
||||
# === Utils
|
||||
|
||||
def warn(msg):
|
||||
sys.stderr.write(msg + '\n')
|
||||
|
||||
def makeQuote(filename):
|
||||
return filename.replace(' ', '\\ ') # enjoy!
|
||||
|
||||
# === Types
|
||||
|
||||
def isVoidType(type):
|
||||
""" Return True if the given xpidl type is void. """
|
||||
return type.kind == 'builtin' and type.name == 'void'
|
||||
|
||||
def isStringType(t):
|
||||
t = xpidl.unaliasType(t)
|
||||
return t.kind == 'native' and (t.specialtype == 'astring' or t.specialtype == 'domstring');
|
||||
|
||||
def isInterfaceType(t):
|
||||
t = xpidl.unaliasType(t)
|
||||
assert t.kind in ('builtin', 'native', 'interface', 'forward')
|
||||
return t.kind in ('interface', 'forward')
|
||||
|
||||
def isSpecificInterfaceType(t, name):
|
||||
""" True if `t` is an interface type with the given name, or a forward
|
||||
declaration or typedef aliasing it.
|
||||
|
||||
`name` must not be the name of a typedef but the actual name of the
|
||||
interface.
|
||||
"""
|
||||
t = xpidl.unaliasType(t)
|
||||
return t.kind in ('interface', 'forward') and t.name == name
|
||||
|
||||
def isVariantType(t):
|
||||
return isSpecificInterfaceType(t, 'nsIVariant')
|
||||
|
||||
# === Reading the file
|
||||
|
||||
class UserError(Exception):
|
||||
pass
|
||||
|
||||
def findIDL(includePath, irregularFilenames, interfaceName):
|
||||
filename = irregularFilenames.get(interfaceName, interfaceName) + '.idl'
|
||||
for d in includePath:
|
||||
# Not os.path.join: we need a forward slash even on Windows because
|
||||
# this filename ends up in makedepend output.
|
||||
path = d + '/' + filename
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
raise UserError("No IDL file found for interface %s "
|
||||
"in include path %r"
|
||||
% (interfaceName, includePath))
|
||||
|
||||
# === Generating code
|
||||
|
||||
argumentUnboxingTemplates = {
|
||||
'octet':
|
||||
" uint32 ${name}_u32;\n"
|
||||
" if (!JS_ValueToECMAUint32(cx, ${argVal}, &${name}_u32))\n"
|
||||
" return JS_FALSE;\n"
|
||||
" uint8 ${name} = (uint8) ${name}_u32;\n",
|
||||
|
||||
'short':
|
||||
" int32 ${name}_i32;\n"
|
||||
" if (!JS_ValueToECMAInt32(cx, ${argVal}, &${name}_i32))\n"
|
||||
" return JS_FALSE;\n"
|
||||
" int16 ${name} = (int16) ${name}_i32;\n",
|
||||
|
||||
'unsigned short':
|
||||
" uint32 ${name}_u32;\n"
|
||||
" if (!JS_ValueToECMAUint32(cx, ${argVal}, &${name}_u32))\n"
|
||||
" return JS_FALSE;\n"
|
||||
" uint16 ${name} = (uint16) ${name}_u32;\n",
|
||||
|
||||
'long':
|
||||
" int32 ${name};\n"
|
||||
" if (!JS_ValueToECMAInt32(cx, ${argVal}, &${name}))\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
'unsigned long':
|
||||
" uint32 ${name};\n"
|
||||
" if (!JS_ValueToECMAUint32(cx, ${argVal}, &${name}))\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
'long long':
|
||||
" PRInt64 ${name};\n"
|
||||
" if (!xpc_qsValueToInt64(cx, ${argVal}, &${name}))\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
'unsigned long long':
|
||||
" PRUint64 ${name};\n"
|
||||
" if (!xpc_qsValueToUint64(cx, ${argVal}, &${name}))\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
'float':
|
||||
" jsdouble ${name}_dbl;\n"
|
||||
" if (!JS_ValueToNumber(cx, ${argVal}, &${name}_dbl))\n"
|
||||
" return JS_FALSE;\n"
|
||||
" float ${name} = (float) ${name}_dbl;\n",
|
||||
|
||||
'double':
|
||||
" jsdouble ${name};\n"
|
||||
" if (!JS_ValueToNumber(cx, ${argVal}, &${name}))\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
'boolean':
|
||||
" bool ${name};\n"
|
||||
" JS_ValueToBoolean(cx, ${argVal}, &${name});\n",
|
||||
|
||||
'[astring]':
|
||||
" xpc_qsAString ${name}(cx, ${argVal}, ${argPtr});\n"
|
||||
" if (!${name}.IsValid())\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
'[domstring]':
|
||||
" xpc_qsDOMString ${name}(cx, ${argVal}, ${argPtr}, "
|
||||
"xpc_qsDOMString::e${nullBehavior}, "
|
||||
"xpc_qsDOMString::e${undefinedBehavior});\n"
|
||||
" if (!${name}.IsValid())\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
'string':
|
||||
" JSAutoByteString ${name}_bytes;\n"
|
||||
" if (!xpc_qsJsvalToCharStr(cx, ${argVal}, &${name}_bytes))\n"
|
||||
" return JS_FALSE;\n"
|
||||
" char *${name} = ${name}_bytes.ptr();\n",
|
||||
|
||||
'wstring':
|
||||
" PRUnichar *${name};\n"
|
||||
" if (!xpc_qsJsvalToWcharStr(cx, ${argVal}, ${argPtr}, &${name}))\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
'[cstring]':
|
||||
" xpc_qsACString ${name}(cx, ${argVal}, ${argPtr});\n"
|
||||
" if (!${name}.IsValid())\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
'[utf8string]':
|
||||
" xpc_qsAUTF8String ${name}(cx, ${argVal}, ${argPtr});\n"
|
||||
" if (!${name}.IsValid())\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
'[jsval]':
|
||||
" jsval ${name} = ${argVal};\n"
|
||||
}
|
||||
|
||||
# From JSData2Native.
|
||||
#
|
||||
# Omitted optional arguments are treated as though the caller had passed JS
|
||||
# `null`; this behavior is from XPCWrappedNative::CallMethod. The 'jsval' type,
|
||||
# however, defaults to 'undefined'.
|
||||
#
|
||||
def writeArgumentUnboxing(f, i, name, type, haveCcx, optional, rvdeclared,
|
||||
nullBehavior, undefinedBehavior):
|
||||
# f - file to write to
|
||||
# i - int or None - Indicates the source jsval. If i is an int, the source
|
||||
# jsval is argv[i]; otherwise it is *vp. But if Python i >= C++ argc,
|
||||
# which can only happen if optional is True, the argument is missing;
|
||||
# use JSVAL_NULL as the source jsval instead.
|
||||
# name - str - name of the native C++ variable to create.
|
||||
# type - xpidl.{Interface,Native,Builtin} - IDL type of argument
|
||||
# optional - bool - True if the parameter is optional.
|
||||
# rvdeclared - bool - False if no |nsresult rv| has been declared earlier.
|
||||
|
||||
typeName = xpidl.getBuiltinOrNativeTypeName(type)
|
||||
|
||||
isSetter = (i is None)
|
||||
|
||||
if isSetter:
|
||||
argPtr = "vp"
|
||||
argVal = "*vp"
|
||||
elif optional:
|
||||
if typeName == "[jsval]":
|
||||
val = "JSVAL_VOID"
|
||||
else:
|
||||
val = "JSVAL_NULL"
|
||||
argVal = "(%d < argc ? argv[%d] : %s)" % (i, i, val)
|
||||
argPtr = "(%d < argc ? &argv[%d] : NULL)" % (i, i)
|
||||
else:
|
||||
argVal = "argv[%d]" % i
|
||||
argPtr = "&" + argVal
|
||||
|
||||
params = {
|
||||
'name': name,
|
||||
'argVal': argVal,
|
||||
'argPtr': argPtr,
|
||||
'nullBehavior': nullBehavior or 'DefaultNullBehavior',
|
||||
'undefinedBehavior': undefinedBehavior or 'DefaultUndefinedBehavior'
|
||||
}
|
||||
|
||||
if typeName is not None:
|
||||
template = argumentUnboxingTemplates.get(typeName)
|
||||
if template is not None:
|
||||
f.write(string.Template(template).substitute(params))
|
||||
return rvdeclared
|
||||
# else fall through; the type isn't supported yet.
|
||||
elif isInterfaceType(type):
|
||||
if type.name == 'nsIVariant':
|
||||
# Totally custom.
|
||||
assert haveCcx
|
||||
template = (
|
||||
" nsCOMPtr<nsIVariant> ${name}(already_AddRefed<nsIVariant>("
|
||||
"XPCVariant::newVariant(ccx, ${argVal})));\n"
|
||||
" if (!${name}) {\n"
|
||||
" xpc_qsThrowBadArgWithCcx(ccx, NS_ERROR_XPC_BAD_CONVERT_JS, %d);\n"
|
||||
" return JS_FALSE;\n"
|
||||
" }\n") % i
|
||||
f.write(string.Template(template).substitute(params))
|
||||
return rvdeclared
|
||||
elif type.name == 'nsIAtom':
|
||||
# Should have special atomizing behavior. Fall through.
|
||||
pass
|
||||
else:
|
||||
if not rvdeclared:
|
||||
f.write(" nsresult rv;\n");
|
||||
f.write(" %s *%s;\n" % (type.name, name))
|
||||
f.write(" xpc_qsSelfRef %sref;\n" % name)
|
||||
f.write(" rv = xpc_qsUnwrapArg<%s>("
|
||||
"cx, %s, &%s, &%sref.ptr, %s);\n"
|
||||
% (type.name, argVal, name, name, argPtr))
|
||||
f.write(" if (NS_FAILED(rv)) {\n")
|
||||
if isSetter:
|
||||
f.write(" xpc_qsThrowBadSetterValue("
|
||||
"cx, rv, JSVAL_TO_OBJECT(*tvr.jsval_addr()), id);\n")
|
||||
elif haveCcx:
|
||||
f.write(" xpc_qsThrowBadArgWithCcx(ccx, rv, %d);\n" % i)
|
||||
else:
|
||||
f.write(" xpc_qsThrowBadArg(cx, rv, vp, %d);\n" % i)
|
||||
f.write(" return JS_FALSE;\n"
|
||||
" }\n")
|
||||
return True
|
||||
|
||||
warn("Unable to unbox argument of type %s (native type %s)" % (type.name, typeName))
|
||||
if i is None:
|
||||
src = '*vp'
|
||||
else:
|
||||
src = 'argv[%d]' % i
|
||||
f.write(" !; // TODO - Unbox argument %s = %s\n" % (name, src))
|
||||
return rvdeclared
|
||||
|
||||
def writeResultDecl(f, member, varname):
|
||||
type = member.realtype
|
||||
|
||||
if isVoidType(type):
|
||||
return # nothing to declare
|
||||
|
||||
t = xpidl.unaliasType(type)
|
||||
if t.kind == 'builtin':
|
||||
if not t.nativename.endswith('*'):
|
||||
if type.kind == 'typedef':
|
||||
typeName = type.name # use it
|
||||
else:
|
||||
typeName = t.nativename
|
||||
f.write(" %s %s;\n" % (typeName, varname))
|
||||
return
|
||||
elif t.kind == 'native':
|
||||
name = xpidl.getBuiltinOrNativeTypeName(t)
|
||||
if name in ('[domstring]', '[astring]'):
|
||||
f.write(" nsString %s;\n" % varname)
|
||||
return
|
||||
elif name == '[jsval]':
|
||||
return # nothing to declare; see special case in outParamForm
|
||||
elif t.kind in ('interface', 'forward'):
|
||||
if member.kind == 'method' and member.notxpcom:
|
||||
f.write(" %s *%s;\n" % (type.name, varname))
|
||||
else:
|
||||
f.write(" nsCOMPtr<%s> %s;\n" % (type.name, varname))
|
||||
return
|
||||
|
||||
warn("Unable to declare result of type %s" % type.name)
|
||||
f.write(" !; // TODO - Declare out parameter `%s`.\n" % varname)
|
||||
|
||||
def outParamForm(name, type):
|
||||
type = xpidl.unaliasType(type)
|
||||
# If we start allowing [jsval] return types here, we need to tack
|
||||
# the return value onto the arguments list in the callers,
|
||||
# possibly, and handle properly returning it too. See bug 604198.
|
||||
assert type.kind != 'native' or type.specialtype != 'jsval'
|
||||
if type.kind == 'builtin':
|
||||
return '&' + name
|
||||
elif type.kind == 'native':
|
||||
if type.specialtype == 'jsval':
|
||||
return 'vp'
|
||||
elif type.modifier == 'ref':
|
||||
return name
|
||||
else:
|
||||
return '&' + name
|
||||
else:
|
||||
return 'getter_AddRefs(%s)' % name
|
||||
|
||||
# From NativeData2JS.
|
||||
resultConvTemplates = {
|
||||
'void':
|
||||
" ${jsvalRef} = JSVAL_VOID;\n"
|
||||
" return JS_TRUE;\n",
|
||||
|
||||
'octet':
|
||||
" ${jsvalRef} = INT_TO_JSVAL((int32) result);\n"
|
||||
" return JS_TRUE;\n",
|
||||
|
||||
'short':
|
||||
" ${jsvalRef} = INT_TO_JSVAL((int32) result);\n"
|
||||
" return JS_TRUE;\n",
|
||||
|
||||
'long':
|
||||
" return xpc_qsInt32ToJsval(cx, result, ${jsvalPtr});\n",
|
||||
|
||||
'long long':
|
||||
" return xpc_qsInt64ToJsval(cx, result, ${jsvalPtr};\n",
|
||||
|
||||
'unsigned short':
|
||||
" ${jsvalRef} = INT_TO_JSVAL((int32) result);\n"
|
||||
" return JS_TRUE;\n",
|
||||
|
||||
'unsigned long':
|
||||
" return xpc_qsUint32ToJsval(cx, result, ${jsvalPtr});\n",
|
||||
|
||||
'unsigned long long':
|
||||
" return xpc_qsUint64ToJsval(cx, result, ${jsvalPtr});\n",
|
||||
|
||||
'float':
|
||||
" return JS_NewNumberValue(cx, result, ${jsvalPtr});\n",
|
||||
|
||||
'double':
|
||||
" return JS_NewNumberValue(cx, result, ${jsvalPtr});\n",
|
||||
|
||||
'boolean':
|
||||
" ${jsvalRef} = (result ? JSVAL_TRUE : JSVAL_FALSE);\n"
|
||||
" return JS_TRUE;\n",
|
||||
|
||||
'[astring]':
|
||||
" return xpc_qsStringToJsval(cx, result, ${jsvalPtr});\n",
|
||||
|
||||
'[domstring]':
|
||||
" return xpc_qsStringToJsval(cx, result, ${jsvalPtr});\n",
|
||||
|
||||
'[jsval]':
|
||||
# Here there's nothing to convert, because the result has already been
|
||||
# written directly to *rv. See the special case in outParamForm.
|
||||
" return JS_TRUE;\n"
|
||||
}
|
||||
|
||||
def writeResultConv(f, type, interfaceResultTemplate, jsvalPtr, jsvalRef):
|
||||
""" Emit code to convert the C++ variable `result` to a jsval.
|
||||
|
||||
The emitted code contains a return statement; it returns JS_TRUE on
|
||||
success, JS_FALSE on error.
|
||||
"""
|
||||
# From NativeData2JS.
|
||||
typeName = xpidl.getBuiltinOrNativeTypeName(type)
|
||||
if typeName is not None:
|
||||
template = resultConvTemplates.get(typeName)
|
||||
elif isInterfaceType(type):
|
||||
if isVariantType(type):
|
||||
template = " return xpc_qsVariantToJsval(lccx, result, ${jsvalPtr});\n"
|
||||
else:
|
||||
template = (" if (!result) {\n"
|
||||
" *${jsvalPtr} = JSVAL_NULL;\n"
|
||||
" return JS_TRUE;\n"
|
||||
" }\n")
|
||||
template += interfaceResultTemplate
|
||||
|
||||
if template is not None:
|
||||
values = {'jsvalRef': jsvalRef,
|
||||
'jsvalPtr': jsvalPtr,
|
||||
'typeName': type.name}
|
||||
f.write(string.Template(template).substitute(values))
|
||||
return
|
||||
# else fall through; this type isn't supported yet
|
||||
|
||||
warn("Unable to convert result of type %s" % type.name)
|
||||
f.write(" !; // TODO - Convert `result` to jsval, store in `%s`.\n"
|
||||
% jsvalRef)
|
||||
f.write(" return xpc_qsThrow(cx, NS_ERROR_UNEXPECTED); // FIXME\n")
|
||||
|
||||
def anyParamRequiresCcx(member):
|
||||
for p in member.params:
|
||||
if isVariantType(p.realtype):
|
||||
return True
|
||||
return False
|
||||
|
||||
def memberNeedsCcx(member):
|
||||
return member.kind == 'method' and anyParamRequiresCcx(member)
|
||||
|
||||
def validateParam(member, param):
|
||||
def pfail(msg):
|
||||
raise UserError(
|
||||
member.iface.name + '.' + member.name + ": "
|
||||
"parameter " + param.name + ": " + msg)
|
||||
|
||||
if param.iid_is is not None:
|
||||
pfail("iid_is parameters are not supported.")
|
||||
if param.size_is is not None:
|
||||
pfail("size_is parameters are not supported.")
|
||||
if param.retval:
|
||||
pfail("Unexpected retval parameter!")
|
||||
if param.paramtype in ('out', 'inout'):
|
||||
pfail("inout parameters are not supported.")
|
||||
if param.const or param.array or param.shared:
|
||||
pfail("I am a simple caveman.")
|
||||
|
||||
# returns the number of arguments that a method takes in JS (including optional arguments)
|
||||
def argumentsLength(member):
|
||||
assert member.kind == 'method'
|
||||
|
||||
inArgs = len(member.params)
|
||||
if inArgs and member.notxpcom and member.params[inArgs - 1].paramtype == 'out':
|
||||
if member.params[inArgs - 1].realtype.kind != 'native' or member.params[inArgs - 1].realtype.nativename != 'nsWrapperCache':
|
||||
pfail("We only support a wrapper cache as out argument")
|
||||
inArgs -= 1
|
||||
return inArgs
|
||||
|
||||
def writeStub(f, customMethodCalls, member, stubName, writeThisUnwrapping, writeCheckForFailure, writeResultWrapping, isSetter=False):
|
||||
""" Write a single quick stub (a custom SpiderMonkey getter/setter/method)
|
||||
for the specified XPCOM interface-member.
|
||||
"""
|
||||
if member.kind == 'method' and member.forward:
|
||||
member = member.iface.namemap[member.forward]
|
||||
|
||||
isAttr = (member.kind == 'attribute')
|
||||
isMethod = (member.kind == 'method')
|
||||
assert isAttr or isMethod
|
||||
isNotxpcom = isMethod and member.notxpcom
|
||||
isGetter = isAttr and not isSetter
|
||||
|
||||
signature = "static JSBool\n"
|
||||
if isAttr:
|
||||
# JSPropertyOp signature.
|
||||
if isSetter:
|
||||
signature += "%s(JSContext *cx, JSObject *obj, jsid id, JSBool strict,%s jsval *vp)\n"
|
||||
else:
|
||||
signature += "%s(JSContext *cx, JSObject *obj, jsid id,%s jsval *vp)\n"
|
||||
else:
|
||||
# JSFastNative.
|
||||
signature += "%s(JSContext *cx, uintN argc,%s jsval *vp)\n"
|
||||
|
||||
customMethodCall = customMethodCalls.get(stubName, None)
|
||||
|
||||
if customMethodCall is None:
|
||||
customMethodCall = customMethodCalls.get(member.iface.name + '_', None)
|
||||
if customMethodCall is not None:
|
||||
if isMethod:
|
||||
code = customMethodCall.get('code', None)
|
||||
elif isGetter:
|
||||
code = customMethodCall.get('getter_code', None)
|
||||
else:
|
||||
code = customMethodCall.get('setter_code', None)
|
||||
else:
|
||||
code = None
|
||||
|
||||
if code is not None:
|
||||
templateName = member.iface.name
|
||||
if isGetter:
|
||||
templateName += '_Get'
|
||||
elif isSetter:
|
||||
templateName += '_Set'
|
||||
|
||||
# Generate the code for the stub, calling the template function
|
||||
# that's shared between the stubs. The stubs can't have additional
|
||||
# arguments, only the template function can.
|
||||
callTemplate = signature % (stubName, '')
|
||||
callTemplate += "{\n"
|
||||
|
||||
argumentValues = (customMethodCall['additionalArgumentValues']
|
||||
% header.methodNativeName(member))
|
||||
if isAttr:
|
||||
callTemplate += (" return %s(cx, obj, id%s, %s, vp);\n"
|
||||
% (templateName, ", strict" if isSetter else "", argumentValues))
|
||||
else:
|
||||
callTemplate += (" return %s(cx, argc, %s, vp);\n"
|
||||
% (templateName, argumentValues))
|
||||
callTemplate += "}\n\n"
|
||||
|
||||
# Fall through and create the template function stub called from the
|
||||
# real stubs, but only generate the stub once. Otherwise, just write
|
||||
# out the call to the template function and return.
|
||||
templateGenerated = templateName + '_generated'
|
||||
if templateGenerated in customMethodCall:
|
||||
f.write(callTemplate)
|
||||
return
|
||||
customMethodCall[templateGenerated] = True
|
||||
|
||||
stubName = templateName
|
||||
else:
|
||||
callTemplate = ""
|
||||
else:
|
||||
callTemplate = ""
|
||||
code = customMethodCall.get('code', None)
|
||||
|
||||
# Function prolog.
|
||||
|
||||
# Only template functions can have additional arguments.
|
||||
if customMethodCall is None or not 'additionalArguments' in customMethodCall:
|
||||
additionalArguments = ''
|
||||
else:
|
||||
additionalArguments = " %s," % customMethodCall['additionalArguments']
|
||||
f.write(signature % (stubName, additionalArguments))
|
||||
f.write("{\n")
|
||||
f.write(" XPC_QS_ASSERT_CONTEXT_OK(cx);\n")
|
||||
|
||||
# For methods, compute "this".
|
||||
if isMethod:
|
||||
f.write(" JSObject *obj = JS_THIS_OBJECT(cx, vp);\n"
|
||||
" if (!obj)\n"
|
||||
" return JS_FALSE;\n")
|
||||
|
||||
# Create ccx if needed.
|
||||
haveCcx = memberNeedsCcx(member)
|
||||
if haveCcx:
|
||||
f.write(" XPCCallContext ccx(JS_CALLER, cx, obj, "
|
||||
"JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));\n")
|
||||
if isInterfaceType(member.realtype):
|
||||
f.write(" XPCLazyCallContext lccx(ccx);\n")
|
||||
|
||||
selfname = writeThisUnwrapping(f, member, isMethod, isGetter, customMethodCall, haveCcx)
|
||||
|
||||
rvdeclared = False
|
||||
if isMethod:
|
||||
inArgs = argumentsLength(member)
|
||||
# If there are any required arguments, check argc.
|
||||
requiredArgs = inArgs
|
||||
while requiredArgs and member.params[requiredArgs-1].optional:
|
||||
requiredArgs -= 1
|
||||
if requiredArgs:
|
||||
f.write(" if (argc < %d)\n" % requiredArgs)
|
||||
f.write(" return xpc_qsThrow(cx, "
|
||||
"NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n")
|
||||
|
||||
# Convert in-parameters.
|
||||
if inArgs > 0:
|
||||
f.write(" jsval *argv = JS_ARGV(cx, vp);\n")
|
||||
for i in range(inArgs):
|
||||
param = member.params[i]
|
||||
argName = 'arg%d' % i
|
||||
argTypeKey = argName + 'Type'
|
||||
if customMethodCall is None or not argTypeKey in customMethodCall:
|
||||
validateParam(member, param)
|
||||
realtype = param.realtype
|
||||
else:
|
||||
realtype = xpidl.Forward(name=customMethodCall[argTypeKey],
|
||||
location='', doccomments='')
|
||||
# Emit code to convert this argument from jsval.
|
||||
rvdeclared = writeArgumentUnboxing(
|
||||
f, i, argName, realtype,
|
||||
haveCcx=haveCcx,
|
||||
optional=param.optional,
|
||||
rvdeclared=rvdeclared,
|
||||
nullBehavior=param.null,
|
||||
undefinedBehavior=param.undefined)
|
||||
if inArgs < len(member.params):
|
||||
f.write(" nsWrapperCache *cache;\n")
|
||||
elif isSetter:
|
||||
rvdeclared = writeArgumentUnboxing(f, None, 'arg0', member.realtype,
|
||||
haveCcx=False, optional=False,
|
||||
rvdeclared=rvdeclared,
|
||||
nullBehavior=member.null,
|
||||
undefinedBehavior=member.undefined)
|
||||
|
||||
canFail = not isNotxpcom and (customMethodCall is None or customMethodCall.get('canFail', True))
|
||||
if canFail and not rvdeclared:
|
||||
f.write(" nsresult rv;\n")
|
||||
rvdeclared = True
|
||||
|
||||
if code is not None:
|
||||
f.write("%s\n" % code)
|
||||
|
||||
if code is None or (isGetter and callTemplate is ""):
|
||||
debugGetter = code is not None
|
||||
if debugGetter:
|
||||
f.write("#ifdef DEBUG\n")
|
||||
f.write(" nsresult debug_rv;\n")
|
||||
f.write(" nsCOMPtr<%s> debug_self;\n"
|
||||
" CallQueryInterface(self, getter_AddRefs(debug_self));\n"
|
||||
% member.iface.name);
|
||||
prefix = 'debug_'
|
||||
else:
|
||||
prefix = ''
|
||||
|
||||
resultname = prefix + 'result'
|
||||
selfname = prefix + selfname
|
||||
nsresultname = prefix + 'rv'
|
||||
|
||||
# Prepare out-parameter.
|
||||
if isMethod or isGetter:
|
||||
writeResultDecl(f, member, resultname)
|
||||
|
||||
# Call the method.
|
||||
if isMethod:
|
||||
comName = header.methodNativeName(member)
|
||||
argv = ['arg' + str(i) for i in range(inArgs)]
|
||||
if inArgs < len(member.params):
|
||||
argv.append(outParamForm('cache', member.params[inArgs].realtype))
|
||||
if member.implicit_jscontext:
|
||||
argv.append('cx')
|
||||
if member.optional_argc:
|
||||
argv.append('argc - %d' % requiredArgs)
|
||||
if not isNotxpcom and not isVoidType(member.realtype):
|
||||
argv.append(outParamForm(resultname, member.realtype))
|
||||
args = ', '.join(argv)
|
||||
else:
|
||||
comName = header.attributeNativeName(member, isGetter)
|
||||
if isGetter:
|
||||
args = outParamForm(resultname, member.realtype)
|
||||
else:
|
||||
args = "arg0"
|
||||
if member.implicit_jscontext:
|
||||
args = "cx, " + args
|
||||
|
||||
f.write(" ")
|
||||
if canFail or debugGetter:
|
||||
f.write("%s = " % nsresultname)
|
||||
elif isNotxpcom:
|
||||
f.write("%s = " % resultname)
|
||||
f.write("%s->%s(%s);\n" % (selfname, comName, args))
|
||||
|
||||
if debugGetter:
|
||||
checkSuccess = "NS_SUCCEEDED(debug_rv)"
|
||||
if canFail:
|
||||
checkSuccess += " == NS_SUCCEEDED(rv)"
|
||||
f.write(" NS_ASSERTION(%s && "
|
||||
"xpc_qsSameResult(debug_result, result),\n"
|
||||
" \"Got the wrong answer from the custom "
|
||||
"method call!\");\n" % checkSuccess)
|
||||
f.write("#endif\n")
|
||||
|
||||
if canFail:
|
||||
# Check for errors.
|
||||
writeCheckForFailure(f, isMethod, isGetter, haveCcx)
|
||||
|
||||
# Convert the return value.
|
||||
if isMethod or isGetter:
|
||||
writeResultWrapping(f, member, 'vp', '*vp')
|
||||
else:
|
||||
f.write(" return JS_TRUE;\n")
|
||||
|
||||
# Epilog.
|
||||
f.write("}\n\n")
|
||||
|
||||
# Now write out the call to the template function.
|
||||
if customMethodCall is not None:
|
||||
f.write(callTemplate)
|
|
@ -0,0 +1,4 @@
|
|||
classes = {
|
||||
'NodeList': 'nsINodeList',
|
||||
'HTMLCollection': 'nsIHTMLCollection',
|
||||
}
|
|
@ -58,8 +58,6 @@ static jsid s_constructor_id = JSID_VOID;
|
|||
static jsid s_prototype_id = JSID_VOID;
|
||||
|
||||
static jsid s_length_id = JSID_VOID;
|
||||
static jsid s_item_id = JSID_VOID;
|
||||
static jsid s_namedItem_id = JSID_VOID;
|
||||
|
||||
bool
|
||||
DefineStaticJSVal(JSContext *cx, jsid &id, const char *string)
|
||||
|
@ -82,8 +80,7 @@ DefineStaticJSVals(JSContext *cx)
|
|||
return SET_JSID_TO_STRING(cx, constructor) &&
|
||||
SET_JSID_TO_STRING(cx, prototype) &&
|
||||
SET_JSID_TO_STRING(cx, length) &&
|
||||
SET_JSID_TO_STRING(cx, item) &&
|
||||
SET_JSID_TO_STRING(cx, namedItem);
|
||||
DefinePropertyStaticJSVals(cx);
|
||||
}
|
||||
|
||||
|
||||
|
@ -225,18 +222,6 @@ Unwrap(JSContext *cx, jsval v, NoType **ppArg, nsISupports **ppArgRef, jsval *vp
|
|||
template<class LC>
|
||||
ListBase<LC> ListBase<LC>::instance;
|
||||
|
||||
void
|
||||
Register(nsDOMClassInfoData *aData)
|
||||
{
|
||||
#define REGISTER_PROTO(_dom_class) \
|
||||
aData[eDOMClassInfo_##_dom_class##_id].mDefineDOMInterface = _dom_class::getPrototype
|
||||
|
||||
REGISTER_PROTO(NodeList);
|
||||
REGISTER_PROTO(HTMLCollection);
|
||||
|
||||
#undef REGISTER_PROTO
|
||||
}
|
||||
|
||||
bool
|
||||
DefineConstructor(JSContext *cx, JSObject *obj, DefineInterface aDefine, nsresult *aResult)
|
||||
{
|
||||
|
@ -349,29 +334,6 @@ ListBase<LC>::setNamedItem(ListType *list, const nsAString& aName, NameSetterTyp
|
|||
return false;
|
||||
}
|
||||
|
||||
template<class LC>
|
||||
JSBool
|
||||
ListBase<LC>::item(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JSObject *obj = JS_THIS_OBJECT(cx, vp);
|
||||
JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
|
||||
if (!obj || !instanceIsListObject(cx, obj, callee))
|
||||
return false;
|
||||
if (argc < 1)
|
||||
return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
|
||||
jsval *argv = JS_ARGV(cx, vp);
|
||||
uint32 u;
|
||||
if (!JS_ValueToECMAUint32(cx, argv[0], &u))
|
||||
return false;
|
||||
IndexGetterType result;
|
||||
if (!getItemAt(getListObject(obj), u, result)) {
|
||||
*vp = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
return Wrap(cx, obj, result, vp);
|
||||
}
|
||||
|
||||
|
||||
template<class LC>
|
||||
bool
|
||||
ListBase<LC>::namedItem(JSContext *cx, JSObject *obj, jsval *name, NameGetterType &result,
|
||||
|
@ -386,28 +348,6 @@ ListBase<LC>::namedItem(JSContext *cx, JSObject *obj, jsval *name, NameGetterTyp
|
|||
return true;
|
||||
}
|
||||
|
||||
template<class LC>
|
||||
JSBool
|
||||
ListBase<LC>::namedItem(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JSObject *obj = JS_THIS_OBJECT(cx, vp);
|
||||
JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
|
||||
if (!obj || !instanceIsListObject(cx, obj, callee))
|
||||
return false;
|
||||
if (argc < 1)
|
||||
return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
|
||||
jsval *argv = JS_ARGV(cx, vp);
|
||||
bool hasResult;
|
||||
NameGetterType result;
|
||||
if (!namedItem(cx, obj, &argv[0], result, &hasResult))
|
||||
return JS_FALSE;
|
||||
if (!hasResult) {
|
||||
*vp = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
return Wrap(cx, obj, result, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
interface_hasInstance(JSContext *cx, JSObject *obj, const js::Value *vp, JSBool *bp)
|
||||
{
|
||||
|
@ -1129,111 +1069,7 @@ NoBase::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
|
|||
}
|
||||
|
||||
|
||||
// NodeList
|
||||
|
||||
template
|
||||
JSObject*
|
||||
NodeList::create(JSContext *cx, XPCWrappedNativeScope *scope, NodeList::ListType *aList,
|
||||
nsWrapperCache* aWrapperCache, bool *triedToWrap);
|
||||
|
||||
template<>
|
||||
Class NodeList::sInterfaceClass = {
|
||||
"NodeList",
|
||||
0,
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_PropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
NULL, /* finalize */
|
||||
NULL, /* reserved0 */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
interface_hasInstance
|
||||
};
|
||||
|
||||
template<>
|
||||
NodeList::Properties NodeList::sProtoProperties[] = {
|
||||
{ s_length_id, length_getter, NULL }
|
||||
};
|
||||
|
||||
template<>
|
||||
NodeList::Methods NodeList::sProtoMethods[] = {
|
||||
{ s_item_id, &item, 1 }
|
||||
};
|
||||
|
||||
template<>
|
||||
bool
|
||||
NodeList::getItemAt(nsINodeList *list, uint32 i, nsIContent *&item)
|
||||
{
|
||||
return !!(item = list->GetNodeAt(i));
|
||||
}
|
||||
|
||||
|
||||
// HTMLCollection
|
||||
|
||||
template
|
||||
JSObject*
|
||||
HTMLCollection::create(JSContext *cx, XPCWrappedNativeScope *scope,
|
||||
HTMLCollection::ListType *aList, nsWrapperCache* aWrapperCache,
|
||||
bool *triedToWrap);
|
||||
|
||||
template
|
||||
nsIHTMLCollection*
|
||||
HTMLCollection::getListObject(JSObject *obj);
|
||||
|
||||
template<>
|
||||
Class HTMLCollection::sInterfaceClass = {
|
||||
"HTMLCollection",
|
||||
0,
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_PropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
NULL, /* finalize */
|
||||
NULL, /* reserved0 */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
interface_hasInstance
|
||||
};
|
||||
|
||||
template<>
|
||||
HTMLCollection::Properties HTMLCollection::sProtoProperties[] = {
|
||||
{ s_length_id, length_getter, NULL }
|
||||
};
|
||||
|
||||
template<>
|
||||
HTMLCollection::Methods HTMLCollection::sProtoMethods[] = {
|
||||
{ s_item_id, &item, 1 },
|
||||
{ s_namedItem_id, &namedItem, 1 }
|
||||
};
|
||||
|
||||
template<>
|
||||
bool
|
||||
HTMLCollection::getItemAt(nsIHTMLCollection *list, uint32 i, nsIContent *&item)
|
||||
{
|
||||
return !!(item = list->GetNodeAt(i));
|
||||
}
|
||||
|
||||
template<>
|
||||
bool
|
||||
HTMLCollection::getNamedItem(nsIHTMLCollection *list, const nsAString& aName,
|
||||
nsISupportsResult &item)
|
||||
{
|
||||
item.mResult = list->GetNamedItem(aName, &item.mCache);
|
||||
return !!item.mResult;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "dombindings_gen.cpp"
|
||||
|
|
|
@ -44,10 +44,6 @@
|
|||
#include "jsproxy.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsINodeList;
|
||||
class nsIHTMLCollection;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace binding {
|
||||
|
@ -70,6 +66,7 @@ GetWrapperCache(void *p)
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
|
||||
class ProxyHandler : public js::ProxyHandler {
|
||||
protected:
|
||||
ProxyHandler() : js::ProxyHandler(ProxyFamily())
|
||||
|
@ -194,8 +191,6 @@ private:
|
|||
static void setProtoShape(JSObject *obj, uint32 shape);
|
||||
|
||||
static JSBool length_getter(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
|
||||
static JSBool item(JSContext *cx, uintN argc, jsval *vp);
|
||||
static JSBool namedItem(JSContext *cx, uintN argc, jsval *vp);
|
||||
|
||||
static inline bool getItemAt(ListType *list, uint32 i, IndexGetterType &item);
|
||||
static inline bool setItemAt(ListType *list, uint32 i, IndexSetterType item);
|
||||
|
@ -215,16 +210,10 @@ private:
|
|||
return !nativeGet(cx, proxy, js::GetObjectProto(proxy), id, &found, NULL) || found;
|
||||
}
|
||||
|
||||
public:
|
||||
static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope, ListType *list,
|
||||
nsWrapperCache* cache, bool *triedToWrap);
|
||||
|
||||
public:
|
||||
template <typename I>
|
||||
static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope, I *aList, bool *triedToWrap)
|
||||
{
|
||||
return create(cx, scope, aList, GetWrapperCache(aList), triedToWrap);
|
||||
}
|
||||
|
||||
static JSObject *getPrototype(JSContext *cx, XPCWrappedNativeScope *scope, bool *enabled);
|
||||
|
||||
bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
|
||||
|
@ -282,14 +271,10 @@ struct nsISupportsResult
|
|||
nsWrapperCache *mCache;
|
||||
};
|
||||
|
||||
typedef ListClass<nsINodeList, Ops<Getter<nsIContent*> > > NodeListClass;
|
||||
typedef ListBase<NodeListClass> NodeList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef ListClass<nsIHTMLCollection, Ops<Getter<nsIContent*> >, Ops<Getter<nsISupportsResult> > > HTMLCollectionClass;
|
||||
typedef ListBase<HTMLCollectionClass> HTMLCollection;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "dombindings_gen.h"
|
||||
|
||||
#endif /* dombindings_h */
|
||||
|
|
|
@ -0,0 +1,728 @@
|
|||
#!/usr/bin/env/python
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
from codegen import *
|
||||
import xpidl
|
||||
import os, re
|
||||
import string
|
||||
import UserDict
|
||||
|
||||
# === Preliminaries
|
||||
|
||||
# --makedepend-output support.
|
||||
make_dependencies = []
|
||||
make_targets = []
|
||||
|
||||
# === Reading the file
|
||||
|
||||
def addStubMember(memberId, member):
|
||||
# Add this member to the list.
|
||||
member.iface.stubMembers.append(member)
|
||||
|
||||
def checkStubMember(member):
|
||||
memberId = member.iface.name + "." + member.name
|
||||
if member.kind not in ('method', 'attribute'):
|
||||
raise UserError("Member %s is %r, not a method or attribute."
|
||||
% (memberId, member.kind))
|
||||
if member.noscript:
|
||||
raise UserError("%s %s is noscript."
|
||||
% (member.kind.capitalize(), memberId))
|
||||
if member.notxpcom:
|
||||
raise UserError(
|
||||
"%s %s: notxpcom methods are not supported."
|
||||
% (member.kind.capitalize(), memberId))
|
||||
|
||||
# Check for unknown properties.
|
||||
for attrname, value in vars(member).items():
|
||||
if value is True and attrname not in ('readonly','optional_argc',
|
||||
'implicit_jscontext','getter',
|
||||
'stringifier'):
|
||||
raise UserError("%s %s: unrecognized property %r"
|
||||
% (member.kind.capitalize(), memberId,
|
||||
attrname))
|
||||
|
||||
def loadIDL(parser, includePath, filename):
|
||||
make_dependencies.append(filename)
|
||||
text = open(filename, 'r').read()
|
||||
idl = parser.parse(text, filename=filename)
|
||||
idl.resolve(includePath, parser)
|
||||
return idl
|
||||
|
||||
|
||||
def firstCap(str):
|
||||
return str[0].upper() + str[1:]
|
||||
|
||||
class DOMClass(UserDict.DictMixin):
|
||||
def __init__(self, name, nativeClass):
|
||||
self.name = name
|
||||
self.base = None
|
||||
self.isBase = False
|
||||
self.nativeClass = nativeClass
|
||||
self.indexGetter = None
|
||||
self.nameGetter = None
|
||||
self.stringifier = False
|
||||
self.members = set()
|
||||
|
||||
@staticmethod
|
||||
def getterNativeType(getter):
|
||||
if isStringType(getter.realtype):
|
||||
return 'nsString'
|
||||
type = getter.realtype
|
||||
if type.kind in ('interface', 'forward'):
|
||||
if not getter.notxpcom:
|
||||
return "nsCOMPtr<%s>" % type.name
|
||||
if len(getter.params) > 1:
|
||||
assert len(getter.params) == 2
|
||||
assert getter.params[1].realtype.kind == 'native' and getter.params[1].realtype.nativename == 'nsWrapperCache'
|
||||
return 'nsISupportsResult'
|
||||
return type.nativeType('in').strip()
|
||||
|
||||
@staticmethod
|
||||
def getterNativeCall(getter):
|
||||
if isStringType(getter.realtype):
|
||||
template = (" list->%s(index, item);\n"
|
||||
" return !DOMStringIsNull(item);\n")
|
||||
else:
|
||||
type = getter.realtype
|
||||
if type.kind in ('interface', 'forward'):
|
||||
if not getter.notxpcom:
|
||||
template = " return NS_SUCCEEDED(list->%s(index, getter_AddRefs(item)));\n"
|
||||
elif len(getter.params) > 1:
|
||||
template = (" item.mResult = list->%s(index, &item.mCache);\n"
|
||||
" return !!item.mResult;\n")
|
||||
else:
|
||||
template = (" item = list->%s(index);\n"
|
||||
" return !!item;\n")
|
||||
else:
|
||||
template = (" item = list->%s(index);\n"
|
||||
" return !!item;\n")
|
||||
|
||||
return template % header.methodNativeName(getter)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
self.__dict__[name] = value
|
||||
if value:
|
||||
if name == 'indexGetter':
|
||||
if value.forward:
|
||||
self.realIndexGetter = value.iface.namemap[value.forward]
|
||||
else:
|
||||
self.realIndexGetter = value
|
||||
self.indexGetterType = self.getterNativeType(self.realIndexGetter)
|
||||
elif name == 'nameGetter':
|
||||
if value.forward:
|
||||
self.realNameGetter = value.iface.namemap[value.forward]
|
||||
else:
|
||||
self.realNameGetter = value
|
||||
self.nameGetterType = self.getterNativeType(self.realNameGetter)
|
||||
|
||||
def __getitem__(self, key):
|
||||
assert type(key) == str
|
||||
|
||||
if key == 'indexGet':
|
||||
return DOMClass.getterNativeCall(self.realIndexGetter)
|
||||
|
||||
if key == 'nameGet':
|
||||
return DOMClass.getterNativeCall(self.realNameGetter)
|
||||
|
||||
def ops(getterType):
|
||||
def opType(type):
|
||||
return type + (" " if type.endswith('>') else "")
|
||||
|
||||
if getterType:
|
||||
opsClass = ", Ops<"
|
||||
opsClass += "Getter<" + opType(getterType) + ">"
|
||||
opsClass += " >"
|
||||
else:
|
||||
opsClass = ", NoOps"
|
||||
return opsClass
|
||||
|
||||
if key == 'indexOps':
|
||||
return ops(self.indexGetter and self.indexGetterType)
|
||||
if key == 'nameOps':
|
||||
return ops(self.nameGetter and self.nameGetterType) if self.nameGetter else ""
|
||||
|
||||
if key == 'listClass':
|
||||
if self.base:
|
||||
template = "DerivedListClass<${nativeClass}, ${base}Wrapper${indexOps}${nameOps} >"
|
||||
else:
|
||||
template = "ListClass<${nativeClass}${indexOps}${nameOps} >"
|
||||
return string.Template(template).substitute(self)
|
||||
|
||||
return self.__dict__[key]
|
||||
|
||||
def __cmp__(x, y):
|
||||
if x.isBase != y.isBase:
|
||||
return -1 if x.isBase else 1
|
||||
return cmp(x.name, y.name)
|
||||
|
||||
class Configuration:
|
||||
def __init__(self, filename, includePath):
|
||||
self.includePath = includePath
|
||||
config = {}
|
||||
execfile(filename, config)
|
||||
|
||||
# required settings
|
||||
if 'classes' not in config:
|
||||
raise UserError(filename + ": `%s` was not defined." % name)
|
||||
self.classes = {}
|
||||
for clazz in config['classes']:
|
||||
self.classes[clazz] = DOMClass(name=clazz, nativeClass=config['classes'][clazz])
|
||||
# optional settings
|
||||
self.customInheritance = config.get('customInheritance', {})
|
||||
self.derivedClasses = {}
|
||||
self.irregularFilenames = config.get('irregularFilenames', {})
|
||||
self.customIncludes = config.get('customIncludes', [])
|
||||
|
||||
def readConfigFile(filename, includePath):
|
||||
# Read the config file.
|
||||
return Configuration(filename, includePath)
|
||||
|
||||
def completeConfiguration(conf, includePath, cachedir):
|
||||
# Now read IDL files to connect the information in the config file to
|
||||
# actual XPCOM interfaces, methods, and attributes.
|
||||
interfaces = []
|
||||
interfacesByName = {}
|
||||
parser = xpidl.IDLParser(cachedir)
|
||||
|
||||
def getInterface(interfaceName, errorLoc):
|
||||
iface = interfacesByName.get(interfaceName)
|
||||
if iface is None:
|
||||
idlFile = findIDL(conf.includePath, conf.irregularFilenames,
|
||||
interfaceName)
|
||||
idl = loadIDL(parser, conf.includePath, idlFile)
|
||||
if not idl.hasName(interfaceName):
|
||||
raise UserError("The interface %s was not found "
|
||||
"in the idl file %r."
|
||||
% (interfaceName, idlFile))
|
||||
iface = idl.getName(interfaceName, errorLoc)
|
||||
if not iface.attributes.scriptable:
|
||||
raise UserError("Interface %s is not scriptable. "
|
||||
"IDL file: %r." % (interfaceName, idlFile))
|
||||
iface.stubMembers = []
|
||||
interfaces.append(iface)
|
||||
interfacesByName[interfaceName] = iface
|
||||
return iface
|
||||
|
||||
stubbedInterfaces = []
|
||||
|
||||
for clazz in conf.classes.itervalues():
|
||||
interfaceName = 'nsIDOM' + clazz.name
|
||||
|
||||
iface = getInterface(interfaceName, errorLoc='looking for %r' % clazz.name)
|
||||
|
||||
for member in iface.members:
|
||||
if member.kind in ('method', 'attribute') and not member.noscript:
|
||||
#addStubMember(iface.name + '.' + member.name, member)
|
||||
clazz.members.add(member)
|
||||
|
||||
# Stub all scriptable members of this interface.
|
||||
while True:
|
||||
if iface not in stubbedInterfaces:
|
||||
stubbedInterfaces.append(iface)
|
||||
if not clazz.indexGetter and iface.ops['index']['getter']:
|
||||
clazz.indexGetter = iface.ops['index']['getter']
|
||||
if not clazz.nameGetter and iface.ops['name']['getter']:
|
||||
clazz.nameGetter = iface.ops['name']['getter']
|
||||
if not clazz.stringifier and iface.ops['stringifier']:
|
||||
clazz.stringifier = iface.ops['stringifier']
|
||||
interfaceName = conf.customInheritance.get(iface.name, iface.base)
|
||||
iface = getInterface(interfaceName, errorLoc='looking for %r' % clazz.name)
|
||||
if iface.name == 'nsISupports':
|
||||
break
|
||||
|
||||
assert iface.name.startswith('nsIDOM') and not iface.name.startswith('nsIDOMNS')
|
||||
clazz.base = iface.name[6:]
|
||||
# For now we only support base classes that are real DOM classes
|
||||
assert clazz.base in conf.classes
|
||||
if not conf.classes[clazz.base].isBase:
|
||||
conf.classes[clazz.base].isBase = True
|
||||
conf.derivedClasses[clazz.base] = []
|
||||
conf.derivedClasses[clazz.base].append(clazz.name)
|
||||
|
||||
# Now go through and check all the interfaces' members
|
||||
for iface in stubbedInterfaces:
|
||||
for member in iface.stubMembers:
|
||||
checkStubMember(member)
|
||||
|
||||
return interfaces
|
||||
|
||||
# === Generating the header file
|
||||
|
||||
def needsForwardDeclaration(type):
|
||||
return isInterfaceType(type) or (type.kind == 'native' and type.specialtype is None)
|
||||
|
||||
def getTypes(classes, map={}):
|
||||
def getTranslatedType(type):
|
||||
return map.get(type, type)
|
||||
|
||||
types = set()
|
||||
for clazz in classes.itervalues():
|
||||
types.add(getTranslatedType(clazz.nativeClass))
|
||||
if clazz.indexGetter and needsForwardDeclaration(clazz.realIndexGetter.realtype):
|
||||
types.add(getTranslatedType(clazz.realIndexGetter.realtype.name))
|
||||
if clazz.nameGetter and needsForwardDeclaration(clazz.realNameGetter.realtype):
|
||||
types.add(getTranslatedType(clazz.realNameGetter.realtype.name))
|
||||
return sorted(types)
|
||||
|
||||
listDefinitionTemplate = (
|
||||
"class ${name} {\n"
|
||||
"public:\n"
|
||||
" template<typename I>\n"
|
||||
" static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope, I *list, bool *triedToWrap)\n"
|
||||
" {\n"
|
||||
" return create(cx, scope, list, GetWrapperCache(list), triedToWrap);\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static bool objIsWrapper(JSObject *obj);\n"
|
||||
" static ${nativeClass} *getNative(JSObject *obj);\n"
|
||||
"\n"
|
||||
"private:\n"
|
||||
" static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope, ${nativeClass} *list, nsWrapperCache *cache, bool *triedToWrap);\n"
|
||||
"};"
|
||||
"\n"
|
||||
"\n")
|
||||
|
||||
def writeHeaderFile(filename, config):
|
||||
print "Creating header file", filename
|
||||
|
||||
headerMacro = '__gen_%s__' % filename.replace('.', '_')
|
||||
f = open(filename, 'w')
|
||||
try:
|
||||
f.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
|
||||
"#ifndef " + headerMacro + "\n"
|
||||
"#define " + headerMacro + "\n\n")
|
||||
|
||||
namespaces = []
|
||||
for type in getTypes(config.classes, {}):
|
||||
newNamespaces = type.split('::')
|
||||
type = newNamespaces.pop()
|
||||
j = 0
|
||||
for i in range(min(len(namespaces), len(newNamespaces))):
|
||||
if namespaces[i] != newNamespaces[i]:
|
||||
break
|
||||
j += 1
|
||||
for i in range(j, len(namespaces)):
|
||||
f.write("}\n")
|
||||
namespaces.pop()
|
||||
for i in range(j, len(newNamespaces)):
|
||||
f.write("namespace %s {\n" % newNamespaces[i])
|
||||
namespaces.append(newNamespaces[i])
|
||||
f.write("class %s;\n" % type)
|
||||
for namespace in namespaces:
|
||||
f.write("}\n")
|
||||
f.write("\n")
|
||||
|
||||
f.write("namespace mozilla {\n"
|
||||
"namespace dom {\n"
|
||||
"namespace binding {\n\n")
|
||||
f.write("bool\n"
|
||||
"DefinePropertyStaticJSVals(JSContext *cx);\n\n")
|
||||
|
||||
for clazz in config.classes.itervalues():
|
||||
f.write(string.Template(listDefinitionTemplate).substitute(clazz))
|
||||
|
||||
f.write("\n"
|
||||
"}\n"
|
||||
"}\n"
|
||||
"}\n\n")
|
||||
f.write("#endif\n")
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def writeMakeDependOutput(filename):
|
||||
print "Creating makedepend file", filename
|
||||
f = open(filename, 'w')
|
||||
try:
|
||||
if len(make_targets) > 0:
|
||||
f.write("%s:" % makeQuote(make_targets[0]))
|
||||
for filename in make_dependencies:
|
||||
f.write(' \\\n\t\t%s' % makeQuote(filename))
|
||||
f.write('\n\n')
|
||||
for filename in make_targets[1:]:
|
||||
f.write('%s: %s\n' % (makeQuote(filename), makeQuote(make_targets[0])))
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
# === Generating the source file
|
||||
|
||||
listTemplateHeader = (
|
||||
"// ${name}\n"
|
||||
"\n"
|
||||
"typedef ${listClass} ${name}Class;\n"
|
||||
"typedef ListBase<${name}Class> ${name}Wrapper;\n"
|
||||
"\n"
|
||||
"\n")
|
||||
|
||||
listTemplate = (
|
||||
"// ${name}\n"
|
||||
"\n"
|
||||
"template<>\n"
|
||||
"js::Class ${name}Wrapper::sInterfaceClass = {\n"
|
||||
" \"${name}\",\n"
|
||||
" 0,\n"
|
||||
" JS_PropertyStub, /* addProperty */\n"
|
||||
" JS_PropertyStub, /* delProperty */\n"
|
||||
" JS_PropertyStub, /* getProperty */\n"
|
||||
" JS_StrictPropertyStub, /* setProperty */\n"
|
||||
" JS_EnumerateStub,\n"
|
||||
" JS_ResolveStub,\n"
|
||||
" JS_ConvertStub,\n"
|
||||
" NULL, /* finalize */\n"
|
||||
" NULL, /* reserved0 */\n"
|
||||
" NULL, /* checkAccess */\n"
|
||||
" NULL, /* call */\n"
|
||||
" NULL, /* construct */\n"
|
||||
" NULL, /* xdrObject */\n"
|
||||
" interface_hasInstance\n"
|
||||
"};\n"
|
||||
"\n")
|
||||
|
||||
derivedClassTemplate = (
|
||||
"template<>\n"
|
||||
"bool\n"
|
||||
"${name}Wrapper::objIsList(JSObject *obj)\n"
|
||||
"{\n"
|
||||
" if (!js::IsProxy(obj))\n"
|
||||
" return false;\n"
|
||||
" js::ProxyHandler *handler = js::GetProxyHandler(obj);\n"
|
||||
" return proxyHandlerIsList(handler) ||\n"
|
||||
"${checkproxyhandlers};\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"template<>\n"
|
||||
"${nativeClass}*\n"
|
||||
"${name}Wrapper::getNative(JSObject *obj)\n"
|
||||
"{\n"
|
||||
" js::ProxyHandler *handler = js::GetProxyHandler(obj);\n"
|
||||
" if (proxyHandlerIsList(handler))\n"
|
||||
" return static_cast<${nativeClass}*>(js::GetProxyPrivate(obj).toPrivate());\n"
|
||||
"${castproxyhandlers}"
|
||||
"\n"
|
||||
" NS_RUNTIMEABORT(\"Unknown list type!\");\n"
|
||||
" return NULL;\n"
|
||||
"}\n"
|
||||
"\n")
|
||||
|
||||
toStringTemplate = (
|
||||
"template<>\n"
|
||||
"JSString *\n"
|
||||
"${name}Wrapper::obj_toString(JSContext *cx, JSObject *proxy)\n"
|
||||
"{\n"
|
||||
" nsString result;\n"
|
||||
" nsresult rv = ${name}Wrapper::getListObject(proxy)->ToString(result);\n"
|
||||
" JSString *jsresult;\n"
|
||||
" return NS_SUCCEEDED(rv) && xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;\n"
|
||||
"}\n"
|
||||
"\n")
|
||||
|
||||
indexGetterTemplate = (
|
||||
"template<>\n"
|
||||
"bool\n"
|
||||
"${name}Wrapper::getItemAt(${nativeClass} *list, uint32 index, ${indexGetterType} &item)\n"
|
||||
"{\n"
|
||||
"${indexGet}"
|
||||
"}\n"
|
||||
"\n")
|
||||
|
||||
nameGetterTemplate = (
|
||||
"template<>\n"
|
||||
"bool\n"
|
||||
"${name}Wrapper::getNamedItem(${nativeClass} *list, const nsAString& index, ${nameGetterType} &item)\n"
|
||||
"{\n"
|
||||
"${nameGet}"
|
||||
"}\n"
|
||||
"\n")
|
||||
|
||||
listTemplateFooter = (
|
||||
"template<>\n"
|
||||
"${name}Wrapper::Properties ${name}Wrapper::sProtoProperties[] = {\n"
|
||||
"${properties}\n"
|
||||
"};\n"
|
||||
"\n""template<>\n"
|
||||
"${name}Wrapper::Methods ${name}Wrapper::sProtoMethods[] = {\n"
|
||||
"${methods}\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"JSObject*\n"
|
||||
"${name}::create(JSContext *cx, XPCWrappedNativeScope *scope, ${nativeClass} *list, nsWrapperCache *cache, bool *triedToWrap)\n"
|
||||
"{\n"
|
||||
" return ${name}Wrapper::create(cx, scope, list, cache, triedToWrap);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"bool\n"
|
||||
"${name}::objIsWrapper(JSObject *obj)\n"
|
||||
"{\n"
|
||||
" return ${name}Wrapper::objIsList(obj);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"${nativeClass}*\n"
|
||||
"${name}::getNative(JSObject *obj)\n"
|
||||
"{\n"
|
||||
" return ${name}Wrapper::getListObject(obj);\n"
|
||||
"}\n"
|
||||
"\n")
|
||||
|
||||
def writeBindingStub(f, classname, member, stubName, isSetter=False):
|
||||
def writeThisUnwrapping(f, member, isMethod, isGetter, customMethodCall, haveCcx):
|
||||
if isMethod:
|
||||
f.write(" JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));\n"
|
||||
" if (!%sWrapper::instanceIsListObject(cx, obj, callee))\n"
|
||||
" return false;\n" % classname)
|
||||
else:
|
||||
f.write(" if (!%sWrapper::instanceIsListObject(cx, obj, NULL))\n"
|
||||
" return false;\n" % classname)
|
||||
return "%sWrapper::getListObject(obj)" % classname
|
||||
def writeCheckForFailure(f, isMethod, isGeter, haveCcx):
|
||||
f.write(" if (NS_FAILED(rv)) {\n"
|
||||
" xpc_qsThrowMethodFailedWithDetails(cx, rv, \"%s\", \"%s\");\n"
|
||||
" return JS_FALSE;\n"
|
||||
" }\n" % (classname, member.name))
|
||||
def writeResultWrapping(f, member, jsvalPtr, jsvalRef):
|
||||
if member.kind == 'method' and member.notxpcom and len(member.params) > 0 and member.params[len(member.params) - 1].paramtype == 'out':
|
||||
assert member.params[len(member.params) - 1].realtype.kind == 'native' and member.params[len(member.params) - 1].realtype.nativename == 'nsWrapperCache'
|
||||
template = " return Wrap(cx, obj, result, cache, ${jsvalPtr});\n"
|
||||
else:
|
||||
template = " return Wrap(cx, obj, result, ${jsvalPtr});\n"
|
||||
writeResultConv(f, member.realtype, template, jsvalPtr, jsvalRef)
|
||||
|
||||
writeStub(f, {}, member, stubName, writeThisUnwrapping, writeCheckForFailure, writeResultWrapping, isSetter)
|
||||
|
||||
def writeAttrStubs(f, classname, attr):
|
||||
getterName = classname + '_' + header.attributeNativeName(attr, True)
|
||||
writeBindingStub(f, classname, attr, getterName)
|
||||
if attr.readonly:
|
||||
setterName = 'xpc_qsGetterOnlyPropertyStub'
|
||||
else:
|
||||
setterName = (classname + '_'
|
||||
+ header.attributeNativeName(attr, False))
|
||||
writeBindingStub(f, classname, attr, setterName, isSetter=True)
|
||||
|
||||
return " { s_%s_id, %s, %s }" % (attr.name, getterName, setterName)
|
||||
|
||||
def writeMethodStub(f, classname, method):
|
||||
stubName = classname + '_' + header.methodNativeName(method)
|
||||
writeBindingStub(f, classname, method, stubName)
|
||||
return " { s_%s_id, %s, %i }" % (method.name, stubName, argumentsLength(method))
|
||||
|
||||
def writeStubFile(filename, config, interfaces):
|
||||
print "Creating stub file", filename
|
||||
make_targets.append(filename)
|
||||
|
||||
f = open(filename, 'w')
|
||||
filesIncluded = set()
|
||||
|
||||
def includeType(type):
|
||||
type = unaliasType(type)
|
||||
if type.kind in ('builtin', 'native'):
|
||||
return None
|
||||
file = conf.irregularFilenames.get(type.name, type.name) + '.h'
|
||||
if file not in filesIncluded:
|
||||
f.write('#include "%s"\n' % file)
|
||||
filesIncluded.add(file)
|
||||
return type
|
||||
|
||||
def writeIncludesForMember(member):
|
||||
assert member.kind in ('attribute', 'method')
|
||||
resulttype = includeType(member.realtype)
|
||||
if member.kind == 'method':
|
||||
for p in member.params:
|
||||
includeType(p.realtype)
|
||||
return resulttype
|
||||
|
||||
headerFilename = re.sub(r'(\.cpp)?$', '.h', filename)
|
||||
|
||||
try:
|
||||
f.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n")
|
||||
|
||||
f.write("".join([("#include \"%s.h\"\n" % re.sub(r'(([^:]+::)*)', '', type)) for type in getTypes(config.classes, config.irregularFilenames)]))
|
||||
f.write("\n")
|
||||
|
||||
f.write("namespace mozilla {\n"
|
||||
"namespace dom {\n"
|
||||
"namespace binding {\n\n")
|
||||
|
||||
f.write("// Property name ids\n\n")
|
||||
|
||||
ids = set()
|
||||
for clazz in config.classes.itervalues():
|
||||
assert clazz.indexGetter
|
||||
ids.add(clazz.indexGetter.name)
|
||||
if clazz.nameGetter:
|
||||
ids.add(clazz.nameGetter.name)
|
||||
if clazz.stringifier:
|
||||
ids.add('toString')
|
||||
for member in clazz.members:
|
||||
if member.name != 'length':
|
||||
ids.add(member.name)
|
||||
|
||||
ids = sorted(ids)
|
||||
for id in ids:
|
||||
f.write("static jsid s_%s_id = JSID_VOID;\n" % id)
|
||||
f.write("\n"
|
||||
"bool\n"
|
||||
"DefinePropertyStaticJSVals(JSContext *cx)\n"
|
||||
"{\n")
|
||||
f.write(" return %s;" % (" &&\n ".join([("SET_JSID_TO_STRING(cx, %s)" % id) for id in ids])))
|
||||
f.write("\n"
|
||||
"}\n\n")
|
||||
|
||||
classes = sorted(config.classes.values())
|
||||
|
||||
f.write("// Typedefs\n\n")
|
||||
|
||||
for clazz in classes:
|
||||
f.write(string.Template(listTemplateHeader).substitute(clazz))
|
||||
|
||||
f.write("// Implementation\n\n")
|
||||
|
||||
for clazz in classes:
|
||||
f.write(string.Template(listTemplate).substitute(clazz))
|
||||
derivedClasses = config.derivedClasses.get(clazz.name, None)
|
||||
if derivedClasses:
|
||||
# If this hits we might need to do something better than just compare instance pointers
|
||||
assert len(derivedClasses) <= 3
|
||||
checkproxyhandlers = "||\n".join(map(lambda d: " %sWrapper::proxyHandlerIsList(handler)" % d, derivedClasses))
|
||||
castproxyhandlers = "\n".join(map(lambda d: " if (%sWrapper::proxyHandlerIsList(handler))\n return %sWrapper::getNative(obj);\n" % (d, d), derivedClasses))
|
||||
f.write(string.Template(derivedClassTemplate).substitute(clazz, checkproxyhandlers=checkproxyhandlers, castproxyhandlers=castproxyhandlers))
|
||||
methodsList = []
|
||||
propertiesList = []
|
||||
if clazz.stringifier:
|
||||
f.write(string.Template(toStringTemplate).substitute(clazz))
|
||||
if clazz.stringifier.name != 'toString':
|
||||
methodsList.append(" { s_toString_id, %s_%s, 0 }", clazz.name, header.methodNativeName(clazz.stringifier))
|
||||
if clazz.indexGetter:
|
||||
#methodsList.append(" { s_%s_id, &item, 1 }" % clazz.indexGetter.name)
|
||||
f.write(string.Template(indexGetterTemplate).substitute(clazz))
|
||||
if clazz.nameGetter:
|
||||
#methodsList.append(" { s_%s_id, &namedItem, 1 }" % clazz.nameGetter.name)
|
||||
f.write(string.Template(nameGetterTemplate).substitute(clazz))
|
||||
for member in clazz.members:
|
||||
if member.name == 'length':
|
||||
if not member.readonly:
|
||||
setterName = (clazz.name + '_' + header.attributeNativeName(member, False))
|
||||
writeBindingStub(f, clazz.name, member, setterName, isSetter=True)
|
||||
else:
|
||||
setterName = "NULL"
|
||||
|
||||
propertiesList.append(" { s_length_id, length_getter, %s }" % setterName)
|
||||
continue
|
||||
|
||||
isAttr = (member.kind == 'attribute')
|
||||
isMethod = (member.kind == 'method')
|
||||
assert isAttr or isMethod
|
||||
|
||||
if isMethod:
|
||||
methodsList.append(writeMethodStub(f, clazz.name, member))
|
||||
else:
|
||||
propertiesList.append(writeAttrStubs(f, clazz.name, member))
|
||||
|
||||
f.write(string.Template(listTemplateFooter).substitute(clazz, methods=",\n".join(methodsList), properties=",\n".join(propertiesList)))
|
||||
|
||||
f.write("// Register prototypes\n\n")
|
||||
|
||||
f.write("void\n"
|
||||
"Register(nsDOMClassInfoData *aData)\n"
|
||||
"{\n"
|
||||
"#define REGISTER_PROTO(_dom_class) \\\n"
|
||||
" aData[eDOMClassInfo_##_dom_class##_id].mDefineDOMInterface = _dom_class##Wrapper::getPrototype\n"
|
||||
"\n")
|
||||
for clazz in config.classes.itervalues():
|
||||
f.write(" REGISTER_PROTO(%s);\n" % clazz.name)
|
||||
f.write("\n"
|
||||
"#undef REGISTER_PROTO\n"
|
||||
"}\n\n")
|
||||
|
||||
f.write("}\n"
|
||||
"}\n"
|
||||
"}\n")
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def main():
|
||||
from optparse import OptionParser
|
||||
o = OptionParser(usage="usage: %prog [options] configfile")
|
||||
o.add_option('-o', "--stub-output",
|
||||
type='string', dest='stub_output', default=None,
|
||||
help="Quick stub C++ source output file", metavar="FILE")
|
||||
o.add_option('--header-output', type='string', default=None,
|
||||
help="Quick stub header output file", metavar="FILE")
|
||||
o.add_option('--makedepend-output', type='string', default=None,
|
||||
help="gnumake dependencies output file", metavar="FILE")
|
||||
o.add_option('--idlpath', type='string', default='.',
|
||||
help="colon-separated directories to search for idl files",
|
||||
metavar="PATH")
|
||||
o.add_option('--cachedir', dest='cachedir', default='',
|
||||
help="Directory in which to cache lex/parse tables.")
|
||||
o.add_option("--verbose-errors", action='store_true', default=False,
|
||||
help="When an error happens, display the Python traceback.")
|
||||
(options, filenames) = o.parse_args()
|
||||
|
||||
if len(filenames) != 1:
|
||||
o.error("Exactly one config filename is needed.")
|
||||
filename = filenames[0]
|
||||
|
||||
if options.cachedir != '':
|
||||
sys.path.append(options.cachedir)
|
||||
if not os.path.isdir(options.cachedir):
|
||||
os.makedirs(options.cachedir)
|
||||
|
||||
try:
|
||||
includePath = options.idlpath.split(':')
|
||||
conf = readConfigFile(filename,
|
||||
includePath=includePath)
|
||||
if options.header_output is not None:
|
||||
writeHeaderFile(options.header_output, conf)
|
||||
elif options.stub_output is not None:
|
||||
interfaces = completeConfiguration(conf,
|
||||
includePath=includePath,
|
||||
cachedir=options.cachedir)
|
||||
writeStubFile(options.stub_output, conf, interfaces)
|
||||
if options.makedepend_output is not None:
|
||||
writeMakeDependOutput(options.makedepend_output)
|
||||
except Exception, exc:
|
||||
if options.verbose_errors:
|
||||
raise
|
||||
elif isinstance(exc, (UserError, xpidl.IDLError)):
|
||||
warn(str(exc))
|
||||
elif isinstance(exc, OSError):
|
||||
warn("%s: %s" % (exc.__class__.__name__, exc))
|
||||
else:
|
||||
raise
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -256,7 +256,8 @@ def checkStubMember(member, isCustom):
|
|||
# Check for unknown properties.
|
||||
for attrname, value in vars(member).items():
|
||||
if value is True and attrname not in ('readonly','optional_argc',
|
||||
'traceable','implicit_jscontext'):
|
||||
'traceable','implicit_jscontext',
|
||||
'getter', 'stringifier'):
|
||||
raise UserError("%s %s: unrecognized property %r"
|
||||
% (member.kind.capitalize(), memberId,
|
||||
attrname))
|
||||
|
|
|
@ -502,6 +502,18 @@ class Interface(object):
|
|||
if not isinstance(m, CDATA):
|
||||
self.namemap.set(m)
|
||||
|
||||
self.ops = {
|
||||
'index':
|
||||
{
|
||||
'getter': None
|
||||
},
|
||||
'name':
|
||||
{
|
||||
'getter': None
|
||||
},
|
||||
'stringifier': None
|
||||
}
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.name == other.name and self.location == other.location
|
||||
|
||||
|
@ -530,8 +542,16 @@ class Interface(object):
|
|||
if self.attributes.scriptable and not realbase.attributes.scriptable:
|
||||
print >>sys.stderr, IDLError("interface '%s' is scriptable but derives from non-scriptable '%s'" % (self.name, self.base), self.location, warning=True)
|
||||
|
||||
forwardedMembers = set()
|
||||
for member in self.members:
|
||||
member.resolve(self)
|
||||
if member.kind is 'method' and member.forward:
|
||||
forwardedMembers.add(member.forward)
|
||||
for member in self.members:
|
||||
if member.kind is 'method' and member.name in forwardedMembers:
|
||||
forwardedMembers.remove(member.name)
|
||||
for member in forwardedMembers:
|
||||
raise IDLError("member '%s' on interface '%s' forwards to '%s' which is not on the interface itself" % (member.name, self.name, member.forward), self.location)
|
||||
|
||||
# The number 250 is NOT arbitrary; this number is the maximum number of
|
||||
# stub entries defined in xpcom/reflect/xptcall/public/genstubs.pl
|
||||
|
@ -795,6 +815,9 @@ class Method(object):
|
|||
nostdcall = False
|
||||
optional_argc = False
|
||||
deprecated = False
|
||||
getter = False
|
||||
stringifier = False
|
||||
forward = None
|
||||
|
||||
def __init__(self, type, name, attlist, paramlist, location, doccomments, raises):
|
||||
self.type = type
|
||||
|
@ -813,6 +836,13 @@ class Method(object):
|
|||
|
||||
self.binaryname = value
|
||||
continue
|
||||
if name == 'forward':
|
||||
if value is None:
|
||||
raise IDLError("forward attribute requires a value",
|
||||
aloc)
|
||||
|
||||
self.forward = value
|
||||
continue
|
||||
|
||||
if value is not None:
|
||||
raise IDLError("Unexpected attribute value", aloc)
|
||||
|
@ -829,6 +859,14 @@ class Method(object):
|
|||
self.deprecated = True
|
||||
elif name == 'nostdcall':
|
||||
self.nostdcall = True
|
||||
elif name == 'getter':
|
||||
if (len(self.params) != 1):
|
||||
raise IDLError("Methods marked as getter must take 1 argument", aloc)
|
||||
self.getter = True
|
||||
elif name == 'stringifier':
|
||||
if (len(self.params) != 0):
|
||||
raise IDLError("Methods marked as stringifier must take 0 arguments", aloc)
|
||||
self.stringifier = True
|
||||
else:
|
||||
raise IDLError("Unexpected attribute '%s'" % name, aloc)
|
||||
|
||||
|
@ -841,6 +879,23 @@ class Method(object):
|
|||
self.realtype = self.iface.idl.getName(self.type, self.location)
|
||||
for p in self.params:
|
||||
p.resolve(self)
|
||||
if self.getter:
|
||||
if getBuiltinOrNativeTypeName(self.params[0].realtype) == 'unsigned long':
|
||||
ops = 'index'
|
||||
else:
|
||||
if getBuiltinOrNativeTypeName(self.params[0].realtype) != '[domstring]':
|
||||
raise IDLError("a getter must take a single unsigned long or DOMString argument" % self.iface.name, self.location)
|
||||
ops = 'name'
|
||||
if self.iface.ops[ops]['getter']:
|
||||
raise IDLError("a %s getter was already defined on interface '%s'" % (ops, self.iface.name), self.location)
|
||||
self.iface.ops[ops]['getter'] = self
|
||||
if self.stringifier:
|
||||
if self.iface.ops['stringifier']:
|
||||
raise IDLError("a stringifier was already defined on interface '%s'" % self.iface.name, self.location)
|
||||
if getBuiltinOrNativeTypeName(self.realtype) != '[domstring]':
|
||||
raise IDLError("'stringifier' attribute can only be used on methods returning DOMString",
|
||||
self.location)
|
||||
self.iface.ops['stringifier'] = self
|
||||
|
||||
def isScriptable(self):
|
||||
if not self.iface.attributes.scriptable: return False
|
||||
|
|
Загрузка…
Ссылка в новой задаче