mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1014114 - Self-host string HTML extensions. r=till
This commit is contained in:
parent
a92c28a9d2
commit
34dce17de4
@ -200,3 +200,102 @@ function String_static_localeCompare(str1, str2) {
|
||||
return callFunction(String_localeCompare, str1, str2, locales, options);
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.3
|
||||
function String_big() {
|
||||
CheckObjectCoercible(this);
|
||||
return "<big>" + ToString(this) + "</big>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.4
|
||||
function String_blink() {
|
||||
CheckObjectCoercible(this);
|
||||
return "<blink>" + ToString(this) + "</blink>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.5
|
||||
function String_bold() {
|
||||
CheckObjectCoercible(this);
|
||||
return "<b>" + ToString(this) + "</b>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.6
|
||||
function String_fixed() {
|
||||
CheckObjectCoercible(this);
|
||||
return "<tt>" + ToString(this) + "</tt>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.9
|
||||
function String_italics() {
|
||||
CheckObjectCoercible(this);
|
||||
return "<i>" + ToString(this) + "</i>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.11
|
||||
function String_small() {
|
||||
CheckObjectCoercible(this);
|
||||
return "<small>" + ToString(this) + "</small>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.12
|
||||
function String_strike() {
|
||||
CheckObjectCoercible(this);
|
||||
return "<strike>" + ToString(this) + "</strike>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.13
|
||||
function String_sub() {
|
||||
CheckObjectCoercible(this);
|
||||
return "<sub>" + ToString(this) + "</sub>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.14
|
||||
function String_sup() {
|
||||
CheckObjectCoercible(this);
|
||||
return "<sup>" + ToString(this) + "</sup>";
|
||||
}
|
||||
|
||||
function EscapeAttributeValue(v) {
|
||||
var inputStr = ToString(v);
|
||||
var inputLen = inputStr.length;
|
||||
var outputStr = '';
|
||||
var chunkStart = 0;
|
||||
for (var i = 0; i < inputLen; i++) {
|
||||
if (inputStr[i] === '"') {
|
||||
outputStr += callFunction(std_String_substring, inputStr, chunkStart, i) + '"';
|
||||
chunkStart = i + 1;
|
||||
}
|
||||
}
|
||||
if (chunkStart === 0)
|
||||
return inputStr;
|
||||
if (chunkStart < inputLen)
|
||||
outputStr += callFunction(std_String_substring, inputStr, chunkStart);
|
||||
return outputStr;
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.2
|
||||
function String_anchor(name) {
|
||||
CheckObjectCoercible(this);
|
||||
var S = ToString(this);
|
||||
return '<a name="' + EscapeAttributeValue(name) + '">' + S + "</a>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.7
|
||||
function String_fontcolor(color) {
|
||||
CheckObjectCoercible(this);
|
||||
var S = ToString(this);
|
||||
return '<font color="' + EscapeAttributeValue(color) + '">' + S + "</font>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.8
|
||||
function String_fontsize(size) {
|
||||
CheckObjectCoercible(this);
|
||||
var S = ToString(this);
|
||||
return '<font size="' + EscapeAttributeValue(size) + '">' + S + "</font>";
|
||||
}
|
||||
|
||||
// ES6 draft 2014-04-27 B.2.3.10
|
||||
function String_link(url) {
|
||||
CheckObjectCoercible(this);
|
||||
var S = ToString(this);
|
||||
return '<a href="' + EscapeAttributeValue(url) + '">' + S + "</a>";
|
||||
}
|
||||
|
82
js/src/jit-test/tests/basic/html-extensions.js
Normal file
82
js/src/jit-test/tests/basic/html-extensions.js
Normal file
@ -0,0 +1,82 @@
|
||||
var noParamFuns = ["".bold, "".italics, "".fixed, "".strike, "".small, "".big,
|
||||
"".blink, "".sup, "".sub];
|
||||
var noParamTags = ["b", "i", "tt", "strike", "small", "big",
|
||||
"blink", "sup", "sub"];
|
||||
|
||||
function testNoParam(s) {
|
||||
for (var i=0; i<noParamFuns.length; i++) {
|
||||
var fun = noParamFuns[i];
|
||||
assertEq(fun.length, 0);
|
||||
var res = fun.call(s);
|
||||
var tag = noParamTags[i];
|
||||
assertEq(res, "<" + tag + ">" + String(s) + "</" + tag + ">");
|
||||
}
|
||||
}
|
||||
testNoParam("Foo");
|
||||
testNoParam('aaa"bbb\'c<>123');
|
||||
testNoParam(123);
|
||||
|
||||
// toString should be called, not valueOf
|
||||
testNoParam({toString: () => 1, valueOf: () => { throw "fail"; } });
|
||||
|
||||
assertEq("".anchor.length, 1);
|
||||
assertEq("".link.length, 1);
|
||||
assertEq("".fontsize.length, 1);
|
||||
assertEq("".fontcolor.length, 1);
|
||||
|
||||
// " in the attribute value is escaped (")
|
||||
assertEq("bla\"<>'".anchor("foo'<>\"\"123\"/\\"),
|
||||
"<a name=\"foo'<>""123"/\\\">bla\"<>'</a>");
|
||||
assertEq("bla\"<>'".link("foo'<>\"\"123\"/\\"),
|
||||
"<a href=\"foo'<>""123"/\\\">bla\"<>'</a>");
|
||||
assertEq("bla\"<>'".fontsize("foo'<>\"\"123\"/\\"),
|
||||
"<font size=\"foo'<>""123"/\\\">bla\"<>'</font>");
|
||||
assertEq("bla\"<>'".fontcolor("foo'<>\"\"123\"/\\"),
|
||||
"<font color=\"foo'<>""123"/\\\">bla\"<>'</font>");
|
||||
|
||||
assertEq("".anchor('"'), '<a name="""></a>');
|
||||
assertEq("".link('"'), '<a href="""></a>');
|
||||
assertEq("".fontcolor('"'), '<font color="""></font>');
|
||||
assertEq("".fontsize('"'), '<font size="""></font>');
|
||||
|
||||
assertEq("".anchor('"1'), '<a name=""1"></a>');
|
||||
assertEq("".link('"1'), '<a href=""1"></a>');
|
||||
assertEq("".fontcolor('"1'), '<font color=""1"></font>');
|
||||
assertEq("".fontsize('"1'), '<font size=""1"></font>');
|
||||
|
||||
assertEq("".anchor('"""a"'), '<a name=""""a""></a>');
|
||||
assertEq("".link('"""a"'), '<a href=""""a""></a>');
|
||||
assertEq("".fontcolor('"""a"'), '<font color=""""a""></font>');
|
||||
assertEq("".fontsize('"""a"'), '<font size=""""a""></font>');
|
||||
|
||||
assertEq("".anchor(""), '<a name=""></a>');
|
||||
assertEq("".link(""), '<a href=""></a>');
|
||||
assertEq("".fontcolor(""), '<font color=""></font>');
|
||||
assertEq("".fontsize(""), '<font size=""></font>');
|
||||
|
||||
assertEq("foo".anchor(), "<a name=\"undefined\">foo</a>");
|
||||
assertEq("foo".link(), "<a href=\"undefined\">foo</a>");
|
||||
assertEq("foo".fontcolor(), "<font color=\"undefined\">foo</font>");
|
||||
assertEq("foo".fontsize(), "<font size=\"undefined\">foo</font>");
|
||||
|
||||
assertEq("foo".anchor(3.14), '<a name="3.14">foo</a>');
|
||||
assertEq("foo".link(3.14), '<a href="3.14">foo</a>');
|
||||
assertEq("foo".fontcolor(3.14), '<font color="3.14">foo</font>');
|
||||
assertEq("foo".fontsize(3.14), '<font size="3.14">foo</font>');
|
||||
|
||||
assertEq("foo".anchor({}), '<a name="[object Object]">foo</a>');
|
||||
assertEq("foo".link(Math), '<a href="[object Math]">foo</a>');
|
||||
assertEq("foo".fontcolor([1,2]), '<font color="1,2">foo</font>');
|
||||
assertEq("foo".fontsize({}), '<font size="[object Object]">foo</font>');
|
||||
|
||||
// toString should be called, not valueOf, and toString must be called on |this|
|
||||
// before it's called on the argument. Also makes sure toString is called only
|
||||
// once.
|
||||
var count = 0;
|
||||
var o1 = {toString: () => { return count += 1; }, valueOf: () => { throw "fail"; } };
|
||||
var o2 = {toString: () => { return count += 5; }, valueOf: () => { throw "fail"; } };
|
||||
assertEq("".anchor.call(o1, o2), '<a name="6">1</a>');
|
||||
assertEq("".link.call(o1, o2), '<a href="12">7</a>');
|
||||
assertEq("".fontcolor.call(o1, o2), '<font color="18">13</font>');
|
||||
assertEq("".fontsize.call(o1, o2), '<font size="24">19</font>');
|
||||
assertEq(count, 24);
|
193
js/src/jsstr.cpp
193
js/src/jsstr.cpp
@ -3776,170 +3776,6 @@ str_slice(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if JS_HAS_STR_HTML_HELPERS
|
||||
/*
|
||||
* HTML composition aids.
|
||||
*/
|
||||
static bool
|
||||
tagify(JSContext *cx, const char *begin, HandleLinearString param, const char *end,
|
||||
CallReceiver call)
|
||||
{
|
||||
JSString *thisstr = ThisToStringForStringProto(cx, call);
|
||||
if (!thisstr)
|
||||
return false;
|
||||
|
||||
JSLinearString *str = thisstr->ensureLinear(cx);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
if (!end)
|
||||
end = begin;
|
||||
|
||||
size_t beglen = strlen(begin);
|
||||
size_t taglen = 1 + beglen + 1; /* '<begin' + '>' */
|
||||
if (param) {
|
||||
size_t numChars = param->length();
|
||||
const jschar *parchars = param->chars();
|
||||
for (size_t i = 0, parlen = numChars; i < parlen; ++i) {
|
||||
if (parchars[i] == '"')
|
||||
numChars += 5; /* len(") - len(") */
|
||||
}
|
||||
taglen += 2 + numChars + 1; /* '="param"' */
|
||||
}
|
||||
size_t endlen = strlen(end);
|
||||
taglen += str->length() + 2 + endlen + 1; /* 'str</end>' */
|
||||
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.reserve(taglen))
|
||||
return false;
|
||||
|
||||
sb.infallibleAppend('<');
|
||||
|
||||
MOZ_ALWAYS_TRUE(sb.appendInflated(begin, beglen));
|
||||
|
||||
if (param) {
|
||||
sb.infallibleAppend('=');
|
||||
sb.infallibleAppend('"');
|
||||
const jschar *parchars = param->chars();
|
||||
for (size_t i = 0, parlen = param->length(); i < parlen; ++i) {
|
||||
if (parchars[i] != '"') {
|
||||
sb.infallibleAppend(parchars[i]);
|
||||
} else {
|
||||
MOZ_ALWAYS_TRUE(sb.append("""));
|
||||
}
|
||||
}
|
||||
sb.infallibleAppend('"');
|
||||
}
|
||||
|
||||
sb.infallibleAppend('>');
|
||||
|
||||
MOZ_ALWAYS_TRUE(sb.append(str));
|
||||
|
||||
sb.infallibleAppend('<');
|
||||
sb.infallibleAppend('/');
|
||||
|
||||
MOZ_ALWAYS_TRUE(sb.appendInflated(end, endlen));
|
||||
|
||||
sb.infallibleAppend('>');
|
||||
|
||||
JSFlatString *retstr = sb.finishString();
|
||||
if (!retstr)
|
||||
return false;
|
||||
|
||||
call.rval().setString(retstr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
tagify_value(JSContext *cx, CallArgs args, const char *begin, const char *end)
|
||||
{
|
||||
RootedLinearString param(cx, ArgToRootedString(cx, args, 0));
|
||||
if (!param)
|
||||
return false;
|
||||
|
||||
return tagify(cx, begin, param, end, args);
|
||||
}
|
||||
|
||||
static bool
|
||||
str_bold(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify(cx, "b", NullPtr(), nullptr, CallReceiverFromVp(vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
str_italics(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify(cx, "i", NullPtr(), nullptr, CallReceiverFromVp(vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
str_fixed(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify(cx, "tt", NullPtr(), nullptr, CallReceiverFromVp(vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
str_fontsize(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify_value(cx, CallArgsFromVp(argc, vp), "font size", "font");
|
||||
}
|
||||
|
||||
static bool
|
||||
str_fontcolor(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify_value(cx, CallArgsFromVp(argc, vp), "font color", "font");
|
||||
}
|
||||
|
||||
static bool
|
||||
str_link(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify_value(cx, CallArgsFromVp(argc, vp), "a href", "a");
|
||||
}
|
||||
|
||||
static bool
|
||||
str_anchor(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify_value(cx, CallArgsFromVp(argc, vp), "a name", "a");
|
||||
}
|
||||
|
||||
static bool
|
||||
str_strike(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify(cx, "strike", NullPtr(), nullptr, CallReceiverFromVp(vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
str_small(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify(cx, "small", NullPtr(), nullptr, CallReceiverFromVp(vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
str_big(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify(cx, "big", NullPtr(), nullptr, CallReceiverFromVp(vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
str_blink(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify(cx, "blink", NullPtr(), nullptr, CallReceiverFromVp(vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
str_sup(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify(cx, "sup", NullPtr(), nullptr, CallReceiverFromVp(vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
str_sub(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
return tagify(cx, "sub", NullPtr(), nullptr, CallReceiverFromVp(vp));
|
||||
}
|
||||
#endif /* JS_HAS_STR_HTML_HELPERS */
|
||||
|
||||
static const JSFunctionSpec string_methods[] = {
|
||||
#if JS_HAS_TOSOURCE
|
||||
JS_FN("quote", str_quote, 0,JSFUN_GENERIC_NATIVE),
|
||||
@ -3987,21 +3823,20 @@ static const JSFunctionSpec string_methods[] = {
|
||||
JS_FN("slice", str_slice, 2,JSFUN_GENERIC_NATIVE),
|
||||
|
||||
/* HTML string methods. */
|
||||
#if JS_HAS_STR_HTML_HELPERS
|
||||
JS_FN("bold", str_bold, 0,0),
|
||||
JS_FN("italics", str_italics, 0,0),
|
||||
JS_FN("fixed", str_fixed, 0,0),
|
||||
JS_FN("fontsize", str_fontsize, 1,0),
|
||||
JS_FN("fontcolor", str_fontcolor, 1,0),
|
||||
JS_FN("link", str_link, 1,0),
|
||||
JS_FN("anchor", str_anchor, 1,0),
|
||||
JS_FN("strike", str_strike, 0,0),
|
||||
JS_FN("small", str_small, 0,0),
|
||||
JS_FN("big", str_big, 0,0),
|
||||
JS_FN("blink", str_blink, 0,0),
|
||||
JS_FN("sup", str_sup, 0,0),
|
||||
JS_FN("sub", str_sub, 0,0),
|
||||
#endif
|
||||
JS_SELF_HOSTED_FN("bold", "String_bold", 0,0),
|
||||
JS_SELF_HOSTED_FN("italics", "String_italics", 0,0),
|
||||
JS_SELF_HOSTED_FN("fixed", "String_fixed", 0,0),
|
||||
JS_SELF_HOSTED_FN("strike", "String_strike", 0,0),
|
||||
JS_SELF_HOSTED_FN("small", "String_small", 0,0),
|
||||
JS_SELF_HOSTED_FN("big", "String_big", 0,0),
|
||||
JS_SELF_HOSTED_FN("blink", "String_blink", 0,0),
|
||||
JS_SELF_HOSTED_FN("sup", "String_sup", 0,0),
|
||||
JS_SELF_HOSTED_FN("sub", "String_sub", 0,0),
|
||||
JS_SELF_HOSTED_FN("anchor", "String_anchor", 1,0),
|
||||
JS_SELF_HOSTED_FN("link", "String_link", 1,0),
|
||||
JS_SELF_HOSTED_FN("fontcolor","String_fontcolor", 1,0),
|
||||
JS_SELF_HOSTED_FN("fontsize", "String_fontsize", 1,0),
|
||||
|
||||
JS_SELF_HOSTED_FN("@@iterator", "String_iterator", 0,0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user