use of com.gargoylesoftware.htmlunit.javascript.host.Reflect in project htmlunit by HtmlUnit.
the class JavaScriptEngine method init.
/**
* Initializes all the JS stuff for the window.
* @param webWindow the web window
* @param context the current context
* @throws Exception if something goes wrong
*/
private void init(final WebWindow webWindow, final Page page, final Context context) throws Exception {
final WebClient webClient = webWindow.getWebClient();
final BrowserVersion browserVersion = webClient.getBrowserVersion();
final Window window = new Window();
window.setClassName("Window");
context.initSafeStandardObjects(window);
final ClassConfiguration windowConfig = jsConfig_.getClassConfiguration("Window");
if (windowConfig.getJsConstructor() != null) {
final FunctionObject functionObject = new RecursiveFunctionObject("Window", windowConfig.getJsConstructor(), window);
ScriptableObject.defineProperty(window, "constructor", functionObject, ScriptableObject.DONTENUM | ScriptableObject.PERMANENT | ScriptableObject.READONLY);
} else {
defineConstructor(window, window, new Window());
}
// remove some objects, that Rhino defines in top scope but that we don't want
deleteProperties(window, "Continuation", "Iterator", "StopIteration", "BigInt");
if (!browserVersion.hasFeature(JS_PROMISE)) {
deleteProperties(window, "Promise");
}
if (!browserVersion.hasFeature(JS_SYMBOL)) {
deleteProperties(window, "Symbol");
}
final ScriptableObject errorObject = (ScriptableObject) ScriptableObject.getProperty(window, "Error");
if (browserVersion.hasFeature(JS_ERROR_STACK_TRACE_LIMIT)) {
errorObject.defineProperty("stackTraceLimit", 10, ScriptableObject.EMPTY);
} else {
ScriptableObject.deleteProperty(errorObject, "stackTraceLimit");
}
if (!browserVersion.hasFeature(JS_ERROR_CAPTURE_STACK_TRACE)) {
ScriptableObject.deleteProperty(errorObject, "captureStackTrace");
}
if (browserVersion.hasFeature(JS_URL_SEARCH_PARMS_ITERATOR_SIMPLE_NAME)) {
URLSearchParams.NativeParamsIterator.init(window, "Iterator");
} else {
URLSearchParams.NativeParamsIterator.init(window, "URLSearchParams Iterator");
}
if (browserVersion.hasFeature(JS_FORM_DATA_ITERATOR_SIMPLE_NAME)) {
FormData.FormDataIterator.init(window, "Iterator");
} else {
FormData.FormDataIterator.init(window, "FormData Iterator");
}
final Intl intl = new Intl();
intl.setParentScope(window);
window.defineProperty(intl.getClassName(), intl, ScriptableObject.DONTENUM);
if (browserVersion.hasFeature(JS_INTL_NAMED_OBJECT)) {
intl.setClassName("Object");
}
intl.defineProperties(browserVersion);
if (browserVersion.hasFeature(JS_REFLECT)) {
final Reflect reflect = new Reflect();
reflect.setParentScope(window);
window.defineProperty(reflect.getClassName(), reflect, ScriptableObject.DONTENUM);
}
final Map<Class<? extends Scriptable>, Scriptable> prototypes = new HashMap<>();
final Map<String, Scriptable> prototypesPerJSName = new HashMap<>();
final String windowClassName = Window.class.getName();
for (final ClassConfiguration config : jsConfig_.getAll()) {
final boolean isWindow = windowClassName.equals(config.getHostClass().getName());
if (isWindow) {
configureConstantsPropertiesAndFunctions(config, window);
final HtmlUnitScriptable prototype = configureClass(config, window, browserVersion);
prototypesPerJSName.put(config.getClassName(), prototype);
} else {
final HtmlUnitScriptable prototype = configureClass(config, window, browserVersion);
if (config.isJsObject()) {
// Place object with prototype property in Window scope
final HtmlUnitScriptable obj = config.getHostClass().newInstance();
prototype.defineProperty("__proto__", prototype, ScriptableObject.DONTENUM);
// but not setPrototype!
obj.defineProperty("prototype", prototype, ScriptableObject.DONTENUM);
obj.setParentScope(window);
obj.setClassName(config.getClassName());
ScriptableObject.defineProperty(window, obj.getClassName(), obj, ScriptableObject.DONTENUM);
// this obj won't have prototype, constants need to be configured on it again
configureConstants(config, obj);
}
prototypes.put(config.getHostClass(), prototype);
prototypesPerJSName.put(config.getClassName(), prototype);
}
}
for (final ClassConfiguration config : jsConfig_.getAll()) {
final Executable jsConstructor = config.getJsConstructor();
final String jsClassName = config.getClassName();
Scriptable prototype = prototypesPerJSName.get(jsClassName);
final String hostClassSimpleName = config.getHostClassSimpleName();
if ("Image".equals(hostClassSimpleName)) {
prototype = prototypesPerJSName.get("HTMLImageElement");
}
if ("Option".equals(hostClassSimpleName)) {
prototype = prototypesPerJSName.get("HTMLOptionElement");
}
switch(hostClassSimpleName) {
case "WebKitMutationObserver":
prototype = prototypesPerJSName.get("MutationObserver");
break;
case "webkitURL":
prototype = prototypesPerJSName.get("URL");
break;
default:
}
if (prototype != null && config.isJsObject()) {
if (jsConstructor == null) {
final ScriptableObject constructor;
if ("Window".equals(jsClassName)) {
constructor = (ScriptableObject) ScriptableObject.getProperty(window, "constructor");
} else {
constructor = config.getHostClass().newInstance();
((HtmlUnitScriptable) constructor).setClassName(config.getClassName());
}
defineConstructor(window, prototype, constructor);
configureConstantsStaticPropertiesAndStaticFunctions(config, constructor);
} else {
final BaseFunction function;
if ("Window".equals(jsClassName)) {
function = (BaseFunction) ScriptableObject.getProperty(window, "constructor");
} else {
function = new RecursiveFunctionObject(jsClassName, jsConstructor, window);
}
if ("WebKitMutationObserver".equals(hostClassSimpleName) || "webkitURL".equals(hostClassSimpleName) || "Image".equals(hostClassSimpleName) || "Option".equals(hostClassSimpleName)) {
final Object prototypeProperty = ScriptableObject.getProperty(window, prototype.getClassName());
if (function instanceof FunctionObject) {
try {
((FunctionObject) function).addAsConstructor(window, prototype);
} catch (final Exception e) {
// TODO see issue #1897
if (LOG.isWarnEnabled()) {
final String newline = System.lineSeparator();
LOG.warn("Error during JavaScriptEngine.init(WebWindow, Context)" + newline + e.getMessage() + newline + "prototype: " + prototype.getClassName());
}
}
}
ScriptableObject.defineProperty(window, hostClassSimpleName, function, ScriptableObject.DONTENUM);
// so we restore its value
if (!hostClassSimpleName.equals(prototype.getClassName())) {
if (prototypeProperty == UniqueTag.NOT_FOUND) {
ScriptableObject.deleteProperty(window, prototype.getClassName());
} else {
ScriptableObject.defineProperty(window, prototype.getClassName(), prototypeProperty, ScriptableObject.DONTENUM);
}
}
} else {
if (function instanceof FunctionObject) {
try {
((FunctionObject) function).addAsConstructor(window, prototype);
} catch (final Exception e) {
// TODO see issue #1897
if (LOG.isWarnEnabled()) {
final String newline = System.lineSeparator();
LOG.warn("Error during JavaScriptEngine.init(WebWindow, Context)" + newline + e.getMessage() + newline + "prototype: " + prototype.getClassName());
}
}
}
}
configureConstantsStaticPropertiesAndStaticFunctions(config, function);
}
}
}
window.setPrototype(prototypesPerJSName.get(Window.class.getSimpleName()));
// once all prototypes have been build, it's possible to configure the chains
final Scriptable objectPrototype = ScriptableObject.getObjectPrototype(window);
for (final Map.Entry<String, Scriptable> entry : prototypesPerJSName.entrySet()) {
final String name = entry.getKey();
final ClassConfiguration config = jsConfig_.getClassConfiguration(name);
final Scriptable prototype = entry.getValue();
if (!StringUtils.isEmpty(config.getExtendedClassName())) {
final Scriptable parentPrototype = prototypesPerJSName.get(config.getExtendedClassName());
prototype.setPrototype(parentPrototype);
} else {
prototype.setPrototype(objectPrototype);
}
}
// if we need more in the future, we have to enhance our JSX annotations
if (browserVersion.hasFeature(JS_WINDOW_ACTIVEXOBJECT_HIDDEN)) {
final Scriptable prototype = prototypesPerJSName.get("ActiveXObject");
if (null != prototype) {
final Method jsConstructor = ActiveXObject.class.getDeclaredMethod("jsConstructor", Context.class, Object[].class, Function.class, boolean.class);
final FunctionObject functionObject = new HiddenFunctionObject("ActiveXObject", jsConstructor, window);
try {
functionObject.addAsConstructor(window, prototype);
} catch (final Exception e) {
// TODO see issue #1897
if (LOG.isWarnEnabled()) {
final String newline = System.lineSeparator();
LOG.warn("Error during JavaScriptEngine.init(WebWindow, Context)" + newline + e.getMessage() + newline + "prototype: " + prototype.getClassName());
}
}
}
}
configureRhino(webClient, browserVersion, window);
window.setPrototypes(prototypes, prototypesPerJSName);
window.initialize(webWindow, page);
applyPolyfills(webClient, browserVersion, context, window);
}
Aggregations