forked from mirrors/gecko-dev
Bug 478251. Implement the Null and Undefined annotations from webidl in quickstubs. r=jst,bsmedberg,jorendorff
This commit is contained in:
parent
177d076ace
commit
6607af54ad
10 changed files with 206 additions and 67 deletions
|
|
@ -360,7 +360,7 @@
|
|||
try {
|
||||
root.querySelectorAll(undefined);
|
||||
} catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
|
||||
assert_todo( pass, type + ".querySelectorAll undefined" );
|
||||
assert( pass, type + ".querySelectorAll undefined" );
|
||||
|
||||
pass = false;
|
||||
try {
|
||||
|
|
@ -385,7 +385,7 @@
|
|||
try {
|
||||
root.querySelector(undefined);
|
||||
} catch(e){ pass = e.code == DOMException.SYNTAX_ERR; }
|
||||
assert_todo( pass, type + ".querySelector undefined" );
|
||||
assert( pass, type + ".querySelector undefined" );
|
||||
|
||||
pass = false;
|
||||
try {
|
||||
|
|
@ -487,14 +487,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
function assert_todo(pass, title) {
|
||||
if (window.parent && window.parent.SimpleTest) {
|
||||
window.parent.SimpleTest.todo(pass, title);
|
||||
} else {
|
||||
assert(pass, title);
|
||||
}
|
||||
}
|
||||
|
||||
function jqTests(type, root, select) {
|
||||
|
||||
function query(q, resolver){
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ _TEST_FILES = test_bug1682.html \
|
|||
bug448564-iframe-3.html \
|
||||
bug448564-echo.sjs \
|
||||
bug448564-submit.js \
|
||||
test_bug478251.html \
|
||||
test_bug481440.html \
|
||||
test_bug481647.html \
|
||||
test_bug482659.html \
|
||||
|
|
|
|||
65
content/html/document/test/test_bug478251.html
Normal file
65
content/html/document/test/test_bug478251.html
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=478251
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 478251</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=478251">Mozilla Bug 478251</a>
|
||||
<p id="display"><iframe id="t"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 478251 **/
|
||||
var doc = $("t").contentDocument;
|
||||
doc.open();
|
||||
doc.write(null);
|
||||
doc.close();
|
||||
is(doc.documentElement.textContent, "null", "Writing |null| failed");
|
||||
|
||||
doc.open();
|
||||
doc.write(null, null);
|
||||
doc.close();
|
||||
is(doc.documentElement.textContent, "nullnull", "Writing |null, null| failed");
|
||||
|
||||
doc.open();
|
||||
doc.write(undefined);
|
||||
doc.close();
|
||||
is(doc.documentElement.textContent, "undefined", "Writing |undefined| failed");
|
||||
|
||||
doc.open();
|
||||
doc.write(undefined, undefined);
|
||||
doc.close();
|
||||
is(doc.documentElement.textContent, "undefinedundefined", "Writing |undefined, undefined| failed");
|
||||
|
||||
doc.open();
|
||||
doc.writeln(null);
|
||||
doc.close();
|
||||
is(doc.documentElement.textContent, "null\n", "Writing |null\\n| failed");
|
||||
|
||||
doc.open();
|
||||
doc.writeln(null, null);
|
||||
doc.close();
|
||||
is(doc.documentElement.textContent, "nullnull\n", "Writing |null, null\\n| failed");
|
||||
|
||||
doc.open();
|
||||
doc.writeln(undefined);
|
||||
doc.close();
|
||||
is(doc.documentElement.textContent, "undefined\n", "Writing |undefined\\n| failed");
|
||||
|
||||
doc.open();
|
||||
doc.writeln(undefined, undefined);
|
||||
doc.close();
|
||||
is(doc.documentElement.textContent, "undefinedundefined\n", "Writing |undefined, undefined\\n| failed");
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -48,6 +48,6 @@
|
|||
[scriptable, uuid(7cebc153-168a-416c-ba5a-56a8c2ddb2ec)]
|
||||
interface nsIDOMNodeSelector : nsISupports
|
||||
{
|
||||
nsIDOMElement querySelector(in DOMString selectors);
|
||||
nsIDOMNodeList querySelectorAll(in DOMString selectors);
|
||||
nsIDOMElement querySelector([Null(Empty), Undefined(Empty)] in DOMString selectors);
|
||||
nsIDOMNodeList querySelectorAll([Null(Empty), Undefined(Empty)] in DOMString selectors);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ interface nsIDOMHTMLDocument : nsIDOMDocument
|
|||
[noscript] void open();
|
||||
void close();
|
||||
|
||||
void write([optional] in DOMString text);
|
||||
void writeln([optional] in DOMString text);
|
||||
void write([optional, Null(Stringify)] in DOMString text);
|
||||
void writeln([optional, Null(Stringify)] in DOMString text);
|
||||
|
||||
nsIDOMNodeList getElementsByName(in DOMString elementName);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -520,7 +520,9 @@ nsIDOMNode_GetChildNodes_customMethodCallCode = """
|
|||
nsIDOMHTMLDocument_Write_customMethodCallCode = """
|
||||
nsAString &str = arg0;
|
||||
for (uintN i = 1; i < argc; ++i) {
|
||||
xpc_qsDOMString next_arg(cx, argv[i], &argv[i]);
|
||||
xpc_qsDOMString next_arg(cx, argv[i], &argv[i],
|
||||
xpc_qsDOMString::eStringify,
|
||||
xpc_qsDOMString::eStringify);
|
||||
if (!next_arg.IsValid())
|
||||
return JS_FALSE;
|
||||
|
||||
|
|
|
|||
|
|
@ -399,7 +399,9 @@ argumentUnboxingTemplates = {
|
|||
" return JS_FALSE;\n",
|
||||
|
||||
'[domstring]':
|
||||
" xpc_qsDOMString ${name}(cx, ${argVal}, ${argPtr});\n"
|
||||
" xpc_qsDOMString ${name}(cx, ${argVal}, ${argPtr},\n"
|
||||
" xpc_qsDOMString::e${nullBehavior},\n"
|
||||
" xpc_qsDOMString::e${undefinedBehavior});\n"
|
||||
" if (!${name}.IsValid())\n"
|
||||
" return JS_FALSE;\n",
|
||||
|
||||
|
|
@ -424,7 +426,8 @@ argumentUnboxingTemplates = {
|
|||
# Omitted optional arguments are treated as though the caller had passed JS
|
||||
# `null`; this behavior is from XPCWrappedNative::CallMethod.
|
||||
#
|
||||
def writeArgumentUnboxing(f, i, name, type, haveCcx, optional, rvdeclared):
|
||||
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,
|
||||
|
|
@ -450,7 +453,9 @@ def writeArgumentUnboxing(f, i, name, type, haveCcx, optional, rvdeclared):
|
|||
params = {
|
||||
'name': name,
|
||||
'argVal': argVal,
|
||||
'argPtr': argPtr
|
||||
'argPtr': argPtr,
|
||||
'nullBehavior': nullBehavior or 'DefaultNullBehavior',
|
||||
'undefinedBehavior': undefinedBehavior or 'DefaultUndefinedBehavior'
|
||||
}
|
||||
|
||||
typeName = getBuiltinOrNativeTypeName(type)
|
||||
|
|
@ -791,11 +796,15 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
|
|||
f, i, 'arg%d' % i, param.realtype,
|
||||
haveCcx=haveCcx,
|
||||
optional=param.optional,
|
||||
rvdeclared=rvdeclared)
|
||||
rvdeclared=rvdeclared,
|
||||
nullBehavior=param.null,
|
||||
undefinedBehavior=param.undefined)
|
||||
elif isSetter:
|
||||
rvdeclared = writeArgumentUnboxing(f, None, 'arg0', member.realtype,
|
||||
haveCcx=False, optional=False,
|
||||
rvdeclared=rvdeclared)
|
||||
rvdeclared=rvdeclared,
|
||||
nullBehavior=member.null,
|
||||
undefinedBehavior=member.undefined)
|
||||
|
||||
canFail = customMethodCall is None or customMethodCall.get('canFail', False)
|
||||
if canFail and not rvdeclared:
|
||||
|
|
|
|||
|
|
@ -679,7 +679,9 @@ xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv,
|
|||
ThrowBadArg(cx, rv, ifaceName, memberName, 0);
|
||||
}
|
||||
|
||||
xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval)
|
||||
xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
|
||||
StringificationBehavior nullBehavior,
|
||||
StringificationBehavior undefinedBehavior)
|
||||
{
|
||||
// From the T_DOMSTRING case in XPCConvert::JSData2Native.
|
||||
typedef implementation_type::char_traits traits;
|
||||
|
|
@ -693,47 +695,20 @@ xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval)
|
|||
}
|
||||
else
|
||||
{
|
||||
StringificationBehavior behavior = eStringify;
|
||||
if(JSVAL_IS_NULL(v))
|
||||
{
|
||||
(new(mBuf) implementation_type(
|
||||
traits::sEmptyBuffer, PRUint32(0)))->SetIsVoid(PR_TRUE);
|
||||
mValid = JS_TRUE;
|
||||
return;
|
||||
behavior = nullBehavior;
|
||||
}
|
||||
else if(JSVAL_IS_VOID(v))
|
||||
{
|
||||
behavior = undefinedBehavior;
|
||||
}
|
||||
|
||||
s = JS_ValueToString(cx, v);
|
||||
if(!s)
|
||||
{
|
||||
mValid = JS_FALSE;
|
||||
return;
|
||||
}
|
||||
*pval = STRING_TO_JSVAL(s); // Root the new string.
|
||||
}
|
||||
|
||||
len = JS_GetStringLength(s);
|
||||
chars = (len == 0 ? traits::sEmptyBuffer : (const PRUnichar*)JS_GetStringChars(s));
|
||||
new(mBuf) implementation_type(chars, len);
|
||||
mValid = JS_TRUE;
|
||||
}
|
||||
|
||||
xpc_qsAString::xpc_qsAString(JSContext *cx, jsval v, jsval *pval)
|
||||
{
|
||||
// From the T_ASTRING case in XPCConvert::JSData2Native.
|
||||
typedef implementation_type::char_traits traits;
|
||||
JSString *s;
|
||||
const PRUnichar *chars;
|
||||
size_t len;
|
||||
|
||||
if(JSVAL_IS_STRING(v))
|
||||
{
|
||||
s = JSVAL_TO_STRING(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v))
|
||||
if (behavior != eStringify)
|
||||
{
|
||||
(new(mBuf) implementation_type(
|
||||
traits::sEmptyBuffer, PRUint32(0)))->SetIsVoid(PR_TRUE);
|
||||
traits::sEmptyBuffer, PRUint32(0)))->SetIsVoid(behavior == eNull);
|
||||
mValid = JS_TRUE;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,17 +257,41 @@ protected:
|
|||
class xpc_qsDOMString : public xpc_qsBasicString<nsAString, nsDependentString>
|
||||
{
|
||||
public:
|
||||
xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval);
|
||||
/* Enum that defines how JS |null| and |undefined| should be treated. See
|
||||
* the WebIDL specification. eStringify means convert to the string "null"
|
||||
* or "undefined" respectively, via the standard JS ToString() operation;
|
||||
* eEmpty means convert to the string ""; eNull means convert to an empty
|
||||
* string with the void bit set.
|
||||
*
|
||||
* Per webidl the default behavior of an unannotated interface is
|
||||
* eStringify, but our de-facto behavior has been eNull for |null| and
|
||||
* eStringify for |undefined|, so leaving it that way for now. If we ever
|
||||
* get to a point where we go through and annotate our interfaces as
|
||||
* needed, we can change that.
|
||||
*/
|
||||
enum StringificationBehavior {
|
||||
eStringify,
|
||||
eEmpty,
|
||||
eNull,
|
||||
eDefaultNullBehavior = eNull,
|
||||
eDefaultUndefinedBehavior = eStringify
|
||||
};
|
||||
|
||||
xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
|
||||
StringificationBehavior nullBehavior,
|
||||
StringificationBehavior undefinedBehavior);
|
||||
};
|
||||
|
||||
/**
|
||||
* The same as xpc_qsDOMString, but with slightly different conversion behavior,
|
||||
* corresponding to the [astring] magic XPIDL annotation rather than [domstring].
|
||||
*/
|
||||
class xpc_qsAString : public xpc_qsBasicString<nsAString, nsDependentString>
|
||||
class xpc_qsAString : public xpc_qsDOMString
|
||||
{
|
||||
public:
|
||||
xpc_qsAString(JSContext *cx, jsval v, jsval *pval);
|
||||
xpc_qsAString(JSContext *cx, jsval v, jsval *pval)
|
||||
: xpc_qsDOMString(cx, v, pval, eNull, eNull)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -99,6 +99,22 @@ def paramAttlistToIDL(attlist):
|
|||
return '[%s] ' % ', '.join(["%s%s" % (name, value is not None and ' (%s)' % value or '')
|
||||
for name, value, aloc in sorted])
|
||||
|
||||
def unaliasType(t):
|
||||
while t.kind == 'typedef':
|
||||
t = t.realtype
|
||||
assert t is not None
|
||||
return t
|
||||
|
||||
def getBuiltinOrNativeTypeName(t):
|
||||
t = unaliasType(t)
|
||||
if t.kind == 'builtin':
|
||||
return t.name
|
||||
elif t.kind == 'native':
|
||||
assert t.specialtype is not None
|
||||
return '[%s]' % t.specialtype
|
||||
else:
|
||||
return None
|
||||
|
||||
class BuiltinLocation(object):
|
||||
def get(self):
|
||||
return "<builtin type>"
|
||||
|
|
@ -624,6 +640,8 @@ class Attribute(object):
|
|||
notxpcom = False
|
||||
readonly = False
|
||||
binaryname = None
|
||||
null = None
|
||||
undefined = None
|
||||
|
||||
def __init__(self, type, name, attlist, readonly, location, doccomments):
|
||||
self.type = type
|
||||
|
|
@ -642,19 +660,48 @@ class Attribute(object):
|
|||
self.binaryname = value
|
||||
continue
|
||||
|
||||
if value is not None:
|
||||
raise IDLError("Unexpected attribute value", aloc)
|
||||
|
||||
if name == 'noscript':
|
||||
self.noscript = True
|
||||
elif name == 'notxpcom':
|
||||
self.notxpcom = True
|
||||
if name == 'Null':
|
||||
if value is None:
|
||||
raise IDLError("'Null' attribute requires a value", aloc)
|
||||
if readonly:
|
||||
raise IDLError("'Null' attribute only makes sense for setters",
|
||||
aloc);
|
||||
if value not in ('Empty', 'Null', 'Stringify'):
|
||||
raise IDLError("'Null' attribute value must be 'Empty', 'Null' or 'Stringify'",
|
||||
aloc);
|
||||
self.null = value
|
||||
elif name == 'Undefined':
|
||||
if value is None:
|
||||
raise IDLError("'Undefined' attribute requires a value", aloc)
|
||||
if readonly:
|
||||
raise IDLError("'Undefined' attribute only makes sense for setters",
|
||||
aloc);
|
||||
if value not in ('Empty', 'Null'):
|
||||
raise IDLError("'Undefined' attribute value must be 'Empty' or 'Null'",
|
||||
aloc);
|
||||
self.undefined = value
|
||||
else:
|
||||
raise IDLError("Unexpected attribute '%s'", aloc)
|
||||
if value is not None:
|
||||
raise IDLError("Unexpected attribute value", aloc)
|
||||
|
||||
if name == 'noscript':
|
||||
self.noscript = True
|
||||
elif name == 'notxpcom':
|
||||
self.notxpcom = True
|
||||
else:
|
||||
raise IDLError("Unexpected attribute '%s'", aloc)
|
||||
|
||||
def resolve(self, iface):
|
||||
self.iface = iface
|
||||
self.realtype = iface.idl.getName(self.type, self.location)
|
||||
if (self.null is not None and
|
||||
getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
|
||||
raise IDLError("'Null' attribute can only be used on DOMString",
|
||||
self.location)
|
||||
if (self.undefined is not None and
|
||||
getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
|
||||
raise IDLError("'Undefined' attribute can only be used on DOMString",
|
||||
self.location)
|
||||
|
||||
def toIDL(self):
|
||||
attribs = attlistToIDL(self.attlist)
|
||||
|
|
@ -741,6 +788,8 @@ class Param(object):
|
|||
retval = False
|
||||
shared = False
|
||||
optional = False
|
||||
null = None
|
||||
undefined = None
|
||||
|
||||
def __init__(self, paramtype, type, name, attlist, location, realtype=None):
|
||||
self.paramtype = paramtype
|
||||
|
|
@ -760,6 +809,20 @@ class Param(object):
|
|||
if value is None:
|
||||
raise IDLError("'iid_is' must specify a parameter", aloc)
|
||||
self.iid_is = value
|
||||
elif name == 'Null':
|
||||
if value is None:
|
||||
raise IDLError("'Null' must specify a parameter", aloc)
|
||||
if value not in ('Empty', 'Null', 'Stringify'):
|
||||
raise IDLError("'Null' parameter value must be 'Empty', 'Null', or 'Stringify'",
|
||||
aloc);
|
||||
self.null = value
|
||||
elif name == 'Undefined':
|
||||
if value is None:
|
||||
raise IDLError("'Undefined' must specify a parameter", aloc)
|
||||
if value not in ('Empty', 'Null'):
|
||||
raise IDLError("'Undefined' parameter value must be 'Empty' or 'Null'",
|
||||
aloc);
|
||||
self.undefined = value
|
||||
else:
|
||||
if value is not None:
|
||||
raise IDLError("Unexpected value for attribute '%s'" % name,
|
||||
|
|
@ -782,6 +845,14 @@ class Param(object):
|
|||
self.realtype = method.iface.idl.getName(self.type, self.location)
|
||||
if self.array:
|
||||
self.realtype = Array(self.realtype)
|
||||
if (self.null is not None and
|
||||
getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
|
||||
raise IDLError("'Null' attribute can only be used on DOMString",
|
||||
self.location)
|
||||
if (self.undefined is not None and
|
||||
getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
|
||||
raise IDLError("'Undefined' attribute can only be used on DOMString",
|
||||
self.location)
|
||||
|
||||
def nativeType(self):
|
||||
kwargs = {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue