Search in sources :

Example 1 with ClassConfiguration

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);
    }
}
Also used : HtmlUnitScriptable(com.gargoylesoftware.htmlunit.javascript.HtmlUnitScriptable) RecursiveFunctionObject(com.gargoylesoftware.htmlunit.javascript.RecursiveFunctionObject) FunctionObject(net.sourceforge.htmlunit.corejs.javascript.FunctionObject) RecursiveFunctionObject(com.gargoylesoftware.htmlunit.javascript.RecursiveFunctionObject) ClassConfiguration(com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration)

Example 2 with ClassConfiguration

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());
        }
    }
}
Also used : ArrayList(java.util.ArrayList) Definition(com.gargoylesoftware.htmlunit.css.StyleAttributes.Definition) PropertyInfo(com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration.PropertyInfo) BrowserVersion(com.gargoylesoftware.htmlunit.BrowserVersion) ClassConfiguration(com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration) Test(org.junit.Test)

Example 3 with ClassConfiguration

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());
        }
    }
}
Also used : PropertyInfo(com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration.PropertyInfo) BrowserVersion(com.gargoylesoftware.htmlunit.BrowserVersion) File(java.io.File) Map(java.util.Map) ClassConfiguration(com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration) Test(org.junit.Test)

Example 4 with ClassConfiguration

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();
}
Also used : ConstantInfo(com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration.ConstantInfo) ArrayList(java.util.ArrayList) JavaScriptConfiguration(com.gargoylesoftware.htmlunit.javascript.configuration.JavaScriptConfiguration) ClassConfiguration(com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration)

Example 5 with ClassConfiguration

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);
}
Also used : HashMap(java.util.HashMap) IdFunctionObject(net.sourceforge.htmlunit.corejs.javascript.IdFunctionObject) FunctionObject(net.sourceforge.htmlunit.corejs.javascript.FunctionObject) Executable(java.lang.reflect.Executable) ClassConfiguration(com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration) Intl(com.gargoylesoftware.htmlunit.javascript.host.intl.Intl) WebWindow(com.gargoylesoftware.htmlunit.WebWindow) Window(com.gargoylesoftware.htmlunit.javascript.host.Window) ScriptableObject(net.sourceforge.htmlunit.corejs.javascript.ScriptableObject) Method(java.lang.reflect.Method) Scriptable(net.sourceforge.htmlunit.corejs.javascript.Scriptable) WebClient(com.gargoylesoftware.htmlunit.WebClient) RhinoException(net.sourceforge.htmlunit.corejs.javascript.RhinoException) ScriptException(com.gargoylesoftware.htmlunit.ScriptException) IOException(java.io.IOException) BaseFunction(net.sourceforge.htmlunit.corejs.javascript.BaseFunction) Reflect(com.gargoylesoftware.htmlunit.javascript.host.Reflect) IdFunctionObject(net.sourceforge.htmlunit.corejs.javascript.IdFunctionObject) ScriptableObject(net.sourceforge.htmlunit.corejs.javascript.ScriptableObject) FunctionObject(net.sourceforge.htmlunit.corejs.javascript.FunctionObject) ActiveXObject(com.gargoylesoftware.htmlunit.javascript.host.ActiveXObject) BrowserVersion(com.gargoylesoftware.htmlunit.BrowserVersion) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

ClassConfiguration (com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration)6 BrowserVersion (com.gargoylesoftware.htmlunit.BrowserVersion)4 FunctionObject (net.sourceforge.htmlunit.corejs.javascript.FunctionObject)3 ConstantInfo (com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration.ConstantInfo)2 PropertyInfo (com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration.PropertyInfo)2 ArrayList (java.util.ArrayList)2 Map (java.util.Map)2 Scriptable (net.sourceforge.htmlunit.corejs.javascript.Scriptable)2 ScriptableObject (net.sourceforge.htmlunit.corejs.javascript.ScriptableObject)2 Test (org.junit.Test)2 ScriptException (com.gargoylesoftware.htmlunit.ScriptException)1 WebClient (com.gargoylesoftware.htmlunit.WebClient)1 WebWindow (com.gargoylesoftware.htmlunit.WebWindow)1 Definition (com.gargoylesoftware.htmlunit.css.StyleAttributes.Definition)1 HtmlUnitScriptable (com.gargoylesoftware.htmlunit.javascript.HtmlUnitScriptable)1 RecursiveFunctionObject (com.gargoylesoftware.htmlunit.javascript.RecursiveFunctionObject)1 JavaScriptConfiguration (com.gargoylesoftware.htmlunit.javascript.configuration.JavaScriptConfiguration)1 ActiveXObject (com.gargoylesoftware.htmlunit.javascript.host.ActiveXObject)1 Reflect (com.gargoylesoftware.htmlunit.javascript.host.Reflect)1 Window (com.gargoylesoftware.htmlunit.javascript.host.Window)1