use of com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration in project htmlunit by HtmlUnit.
the class Intl method define.
private void define(final Class<? extends HtmlUnitScriptable> c, final BrowserVersion browserVersion) {
try {
final ClassConfiguration config = AbstractJavaScriptConfiguration.getClassConfiguration(c, browserVersion);
final HtmlUnitScriptable prototype = JavaScriptEngine.configureClass(config, this, browserVersion);
final FunctionObject functionObject = new RecursiveFunctionObject(c.getSimpleName(), config.getJsConstructor(), this);
if (c == V8BreakIterator.class) {
prototype.setClassName("v8BreakIterator");
}
functionObject.addAsConstructor(this, prototype);
} catch (final Exception e) {
throw Context.throwAsScriptRuntimeEx(e);
}
}
use of com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration in project htmlunit by HtmlUnit.
the class CSSStyleDeclarationTest method styleAttributes.
/**
* Tests that all getters and setters {@link CSSStyleDeclaration} have correct browser support
* as defined in {@link StyleAttributes}.
*
* @throws Exception if an error occurs
*/
@Test
public void styleAttributes() throws Exception {
final List<String> allProperties = new ArrayList<>();
for (final BrowserVersion browserVersion : allBrowsers()) {
final ClassConfiguration config = AbstractJavaScriptConfiguration.getClassConfiguration(CSSStyleDeclaration.class, browserVersion);
for (final Definition definition : StyleAttributes.getDefinitions(browserVersion)) {
if (!definition.name().endsWith("_")) {
final String propertyName = definition.getPropertyName();
final PropertyInfo info = config.getPropertyMap().get(propertyName);
if (info != null) {
allProperties.add(propertyName);
}
}
}
}
final BrowserVersion browserVersion = getBrowserVersion();
final ClassConfiguration config = AbstractJavaScriptConfiguration.getClassConfiguration(CSSStyleDeclaration.class, browserVersion);
for (final Definition definition : StyleAttributes.getDefinitions(browserVersion)) {
if (!definition.name().endsWith("_")) {
final String propertyName = definition.getPropertyName();
final PropertyInfo info = config.getPropertyMap().get(propertyName);
if (allProperties.contains(propertyName) && (info == null || info.getReadMethod() == null || info.getWriteMethod() == null)) {
fail("CSSStyleDeclaration: " + propertyName + " must support " + browserVersion.getNickname());
}
}
}
for (final String propertyName : config.getPropertyMap().keySet()) {
if (!"length".equals(propertyName) && !"parentRule".equals(propertyName) && !"cssText".equals(propertyName) && StyleAttributes.getDefinition(propertyName, browserVersion) == null) {
fail("CSSStyleDeclaration: incorrectly defines " + propertyName + " for " + browserVersion.getNickname());
}
}
}
use of com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration in project htmlunit by HtmlUnit.
the class CSSStyleDeclarationTest method defaultImplementation.
/**
* Ensures no default implementation is being used.
*
* When no JavaScript method is defined, {@link StyleAttributes} values are used, this can be overridden only
* when a different implementation is needed.
*
* @throws Exception if an error occurs
*/
@Test
public void defaultImplementation() throws Exception {
final BrowserVersion browserVersion = getBrowserVersion();
final ClassConfiguration config = AbstractJavaScriptConfiguration.getClassConfiguration(CSSStyleDeclaration.class, browserVersion);
final Map<String, PropertyInfo> propertyMap = config.getPropertyMap();
final File cssFolder = new File("src/main/java/com/gargoylesoftware/htmlunit/javascript/host/css/");
final List<String> cssLines = FileUtils.readLines(new File(cssFolder, "CSSStyleDeclaration.java"), ISO_8859_1);
final List<String> computedLines = FileUtils.readLines(new File(cssFolder, "ComputedCSSStyleDeclaration.java"), ISO_8859_1);
for (final Map.Entry<String, PropertyInfo> entry : propertyMap.entrySet()) {
final PropertyInfo info = entry.getValue();
if (info.getReadMethod() == null) {
fail(browserVersion.getNickname() + " CSSStyleDeclaration: no getter for " + entry.getKey());
}
if (info.getWriteMethod() == null && !"length".equals(entry.getKey())) {
fail(browserVersion.getNickname() + " CSSStyleDeclaration: no setter for " + entry.getKey());
}
if (isDefaultGetter(cssLines, info) && isDefaultSetter(cssLines, info) && isDefaultGetterComputed(computedLines, info)) {
fail(browserVersion.getNickname() + " CSSStyleDeclaration: default implementation for " + entry.getKey());
}
}
}
use of com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration in project htmlunit by HtmlUnit.
the class HostConstantsTest method getExpectedString.
private String getExpectedString() throws Exception {
if (host_.endsWith("Array") || "Image".equals(host_) || "Option".equals(host_)) {
return "";
}
if ("Error".equals(host_) && getBrowserVersion().hasFeature(JS_ERROR_STACK_TRACE_LIMIT)) {
return "stackTraceLimit:10";
}
final JavaScriptConfiguration javaScriptConfig = JavaScriptConfiguration.getInstance(getBrowserVersion());
final List<String> constants = new ArrayList<>();
ClassConfiguration classConfig = javaScriptConfig.getClassConfiguration(host_);
boolean first = true;
while (classConfig != null) {
if (first && !classConfig.isJsObject()) {
break;
}
if (first || classConfig.getJsConstructor() != null) {
final List<ConstantInfo> constantInfos = classConfig.getConstants();
if (constantInfos != null) {
for (final ConstantInfo constantInfo : constantInfos) {
constants.add(constantInfo.getName() + ":" + constantInfo.getValue());
}
}
}
classConfig = javaScriptConfig.getClassConfiguration(classConfig.getExtendedClassName());
first = false;
}
Collections.sort(constants, new Comparator<String>() {
@Override
public int compare(final String o1, final String o2) {
return o1.substring(0, o1.indexOf(':')).compareTo(o2.substring(0, o2.indexOf(':')));
}
});
final StringBuilder builder = new StringBuilder();
for (final String key : constants) {
builder.append(key).append(' ');
}
return builder.toString().trim();
}
use of com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration 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