1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript;
16
17 import static org.htmlunit.BrowserVersionFeatures.JS_NATIVE_FUNCTION_TOSTRING_COMPACT;
18 import static org.htmlunit.BrowserVersionFeatures.JS_NATIVE_FUNCTION_TOSTRING_NL;
19
20 import org.htmlunit.BrowserVersion;
21 import org.htmlunit.corejs.javascript.BaseFunction;
22 import org.htmlunit.corejs.javascript.Context;
23 import org.htmlunit.corejs.javascript.Function;
24 import org.htmlunit.corejs.javascript.Scriptable;
25 import org.htmlunit.corejs.javascript.ScriptableObject;
26 import org.htmlunit.corejs.javascript.VarScope;
27
28
29
30
31
32
33
34
35
36 public final class NativeFunctionToStringFunction {
37
38
39
40
41
42
43 public static void installFix(final VarScope scope, final BrowserVersion browserVersion) {
44 if (browserVersion.hasFeature(JS_NATIVE_FUNCTION_TOSTRING_COMPACT)) {
45 final ScriptableObject fnPrototype =
46 (ScriptableObject) ScriptableObject.getClassPrototype(scope, "Function");
47 final Function originalToString = (Function) ScriptableObject.getProperty(fnPrototype, "toString");
48 final Function newToString = new NativeFunctionToStringFunctionChrome(originalToString);
49 ScriptableObject.putProperty(fnPrototype, "toString", newToString);
50 }
51 else if (browserVersion.hasFeature(JS_NATIVE_FUNCTION_TOSTRING_NL)) {
52 final ScriptableObject fnPrototype =
53 (ScriptableObject) ScriptableObject.getClassPrototype(scope, "Function");
54 final Function originalToString = (Function) ScriptableObject.getProperty(fnPrototype, "toString");
55 final Function newToString = new NativeFunctionToStringFunctionFF(originalToString);
56 ScriptableObject.putProperty(fnPrototype, "toString", newToString);
57 }
58 }
59
60 private NativeFunctionToStringFunction() {
61 super();
62 }
63
64 static class NativeFunctionToStringFunctionChrome extends FunctionWrapper {
65
66 NativeFunctionToStringFunctionChrome(final Function wrapped) {
67 super(wrapped);
68 }
69
70
71
72
73 @Override
74 public Object call(final Context cx, final VarScope scope, final Scriptable thisObj, final Object[] args) {
75 final String s = (String) super.call(cx, scope, thisObj, args);
76
77 if (thisObj instanceof BaseFunction function && s.contains("[native code")) {
78 final String functionName = function.getFunctionName();
79 return "function " + functionName + "() { [native code] }";
80 }
81 return s.replace("function anonymous() {", "function anonymous(\n) {\n");
82 }
83 }
84
85 static class NativeFunctionToStringFunctionFF extends FunctionWrapper {
86
87 NativeFunctionToStringFunctionFF(final Function wrapped) {
88 super(wrapped);
89 }
90
91
92
93
94 @Override
95 public Object call(final Context cx, final VarScope scope, final Scriptable thisObj, final Object[] args) {
96 final String s = (String) super.call(cx, scope, thisObj, args);
97
98 if (thisObj instanceof BaseFunction function && s.contains("[native code")) {
99 final String functionName = function.getFunctionName();
100 return "function " + functionName + "() {\n [native code]\n}";
101 }
102 return s.replace("function anonymous() {", "function anonymous(\n) {\n");
103 }
104 }
105 }