[prev in list] [next in list] [prev in thread] [next in thread] 

List:       htmlunit-develop
Subject:    [HtmlUnit] SVN: [11315] trunk/htmlunit/src
From:       asashour () users ! sourceforge ! net
Date:       2015-09-28 12:26:03
Message-ID: E1ZgXVP-0000JP-Uv () sfs-ml-4 ! v29 ! ch3 ! sourceforge ! com
[Download RAW message or body]

Revision: 11315
          http://sourceforge.net/p/htmlunit/code/11315
Author:   asashour
Date:     2015-09-28 12:26:03 +0000 (Mon, 28 Sep 2015)
Log Message:
-----------
Introduce RhinoJavaScriptEngine

Modified Paths:
--------------
    trunk/htmlunit/src/changes/changes.xml
    trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/InteractivePage.java
    trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/WebClient.java
    trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/activex/javascript/msxml/XMLHTTPRequest.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/BaseFrameElement.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/DomElement.java
    trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlInput.java
    trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java
    trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/HtmlUnitContextFactory.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/SimpleScriptable.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/background/DownloadBehaviorJob.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/configuration/AbstractJavaScriptConfiguration.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/configuration/ClassConfiguration.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/MessagePort.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/WebSocket.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/geo/Geolocation.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/intl/Intl.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/xml/XMLDocument.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/xml/XMLHttpRequest.java
  trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/util/WebClientUtils.java
    trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/gae/GAELoadPageTest.java
  trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/DebugFrameImplTest.java
  trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngineTest.java
  trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/regexp/HtmlUnitRegExpProxy2Test.java


Added Paths:
-----------
    trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/RhinoJavaScriptEngine.java


Modified: trunk/htmlunit/src/changes/changes.xml
===================================================================
--- trunk/htmlunit/src/changes/changes.xml	2015-09-28 11:35:30 UTC (rev 11314)
+++ trunk/htmlunit/src/changes/changes.xml	2015-09-28 12:26:03 UTC (rev 11315)
@@ -8,6 +8,9 @@
 
     <body>
         <release version="2.19" date="" description="Bugfixes">
+            <action type="add" dev="asashour">
+                Introduce RhinoJavaScriptEngine.
+            </action>
             <action type="fix" dev="asashour" issue="1699">
                 JavaScript: collections to be iterated using the default \
Symbol.iterator.  </action>

Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/InteractivePage.java
 ===================================================================
--- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/InteractivePage.java	2015-09-28 \
                11:35:30 UTC (rev 11314)
+++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/InteractivePage.java	2015-09-28 \
12:26:03 UTC (rev 11315) @@ -25,7 +25,7 @@
 import com.gargoylesoftware.htmlunit.html.DomNode;
 import com.gargoylesoftware.htmlunit.html.impl.SelectableTextInput;
 import com.gargoylesoftware.htmlunit.html.impl.SimpleRange;
-import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
+import com.gargoylesoftware.htmlunit.javascript.RhinoJavaScriptEngine;
 import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable;
 import com.gargoylesoftware.htmlunit.javascript.host.event.Event;
 
@@ -196,7 +196,7 @@
             return new ScriptResult(null, this);
         }
 
-        final JavaScriptEngine engine = getWebClient().getJavaScriptEngine();
+        final RhinoJavaScriptEngine engine = (RhinoJavaScriptEngine) \
                getWebClient().getJavaScriptEngine();
         final Object result = engine.callFunction(this, function, thisObject, args, \
htmlElementScope);  
         return new ScriptResult(result, \
getWebClient().getCurrentWindow().getEnclosedPage());

Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/WebClient.java
===================================================================
--- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/WebClient.java	2015-09-28 \
                11:35:30 UTC (rev 11314)
+++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/WebClient.java	2015-09-28 \
12:26:03 UTC (rev 11315) @@ -75,6 +75,7 @@
 import com.gargoylesoftware.htmlunit.httpclient.HtmlUnitBrowserCompatCookieSpec;
 import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
 import com.gargoylesoftware.htmlunit.javascript.JavaScriptErrorListener;
+import com.gargoylesoftware.htmlunit.javascript.RhinoJavaScriptEngine;
 import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptJobManager;
 import com.gargoylesoftware.htmlunit.javascript.host.Location;
 import com.gargoylesoftware.htmlunit.javascript.host.Window;
@@ -234,7 +235,7 @@
         getOptions().setProxyConfig(proxyConfig);
 
         webConnection_ = createWebConnection(); // this has to be done after the \
                browser version was set
-        scriptEngine_ = new JavaScriptEngine(this);
+        scriptEngine_ = new RhinoJavaScriptEngine(this);
         // The window must be constructed AFTER the script engine.
         addWebWindowListener(new CurrentWindowTracker(this));
         currentWindow_ = new TopLevelWindow("", this);
@@ -1546,7 +1547,7 @@
      * @param timeout the timeout value, in milliseconds
      */
     public void setJavaScriptTimeout(final long timeout) {
-        scriptEngine_.getContextFactory().setTimeout(timeout);
+        scriptEngine_.setJavaScriptTimeout(timeout);
     }
 
     /**
@@ -1556,7 +1557,7 @@
      * @return the timeout value, in milliseconds
      */
     public long getJavaScriptTimeout() {
-        return scriptEngine_.getContextFactory().getTimeout();
+        return scriptEngine_.getJavaScriptTimeout();
     }
 
     /**
@@ -1942,7 +1943,7 @@
         in.defaultReadObject();
 
         webConnection_ = createWebConnection();
-        scriptEngine_ = new JavaScriptEngine(this);
+        scriptEngine_ = new RhinoJavaScriptEngine(this);
         jobManagers_ = Collections.synchronizedList(new \
ArrayList<WeakReference<JavaScriptJobManager>>());  
         if (getBrowserVersion().hasFeature(JS_XML_SUPPORT_VIA_ACTIVEXOBJECT)) {

Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/activex/javascript/msxml/XMLHTTPRequest.java
 ===================================================================
--- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/activex/javascript/msxml/XMLHTTPRequest.java	2015-09-28 \
                11:35:30 UTC (rev 11314)
+++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/activex/javascript/msxml/XMLHTTPRequest.java	2015-09-28 \
12:26:03 UTC (rev 11315) @@ -41,7 +41,7 @@
 import com.gargoylesoftware.htmlunit.WebRequest;
 import com.gargoylesoftware.htmlunit.WebResponse;
 import com.gargoylesoftware.htmlunit.html.HtmlPage;
-import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
+import com.gargoylesoftware.htmlunit.javascript.RhinoJavaScriptEngine;
 import com.gargoylesoftware.htmlunit.javascript.background.BackgroundJavaScriptFactory;
  import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptJob;
 import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass;
@@ -162,7 +162,8 @@
 
         if (stateChangeHandler_ != null && !openedMultipleTimes_) {
             final Scriptable scope = stateChangeHandler_.getParentScope();
-            final JavaScriptEngine jsEngine = \
containingPage_.getWebClient().getJavaScriptEngine(); +            final \
RhinoJavaScriptEngine jsEngine = (RhinoJavaScriptEngine) +                    \
containingPage_.getWebClient().getJavaScriptEngine();  
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Calling onreadystatechange handler for state " + state);
@@ -459,17 +460,17 @@
         else {
             // Create and start a thread in which to execute the request.
             final Scriptable startingScope = getWindow();
-            final ContextFactory cf = \
client.getJavaScriptEngine().getContextFactory(); +            final ContextFactory \
cf = ((RhinoJavaScriptEngine) client.getJavaScriptEngine()).getContextFactory();  \
final ContextAction action = new ContextAction() {  @Override
                 public Object run(final Context cx) {
                     // KEY_STARTING_SCOPE maintains a stack of scopes
                     @SuppressWarnings("unchecked")
                     Stack<Scriptable> stack =
-                            (Stack<Scriptable>) \
cx.getThreadLocal(JavaScriptEngine.KEY_STARTING_SCOPE); +                            \
(Stack<Scriptable>) cx.getThreadLocal(RhinoJavaScriptEngine.KEY_STARTING_SCOPE);  if \
(null == stack) {  stack = new Stack<>();
-                        cx.putThreadLocal(JavaScriptEngine.KEY_STARTING_SCOPE, \
stack); +                        \
cx.putThreadLocal(RhinoJavaScriptEngine.KEY_STARTING_SCOPE, stack);  }
                     stack.push(startingScope);
 

Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/BaseFrameElement.java
 ===================================================================
--- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/BaseFrameElement.java	2015-09-28 \
                11:35:30 UTC (rev 11314)
+++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/BaseFrameElement.java	2015-09-28 \
12:26:03 UTC (rev 11315) @@ -29,8 +29,8 @@
 import com.gargoylesoftware.htmlunit.WebClient;
 import com.gargoylesoftware.htmlunit.WebRequest;
 import com.gargoylesoftware.htmlunit.WebWindow;
-import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
 import com.gargoylesoftware.htmlunit.javascript.PostponedAction;
+import com.gargoylesoftware.htmlunit.javascript.RhinoJavaScriptEngine;
 import com.gargoylesoftware.htmlunit.protocol.javascript.JavaScriptURLConnection;
 
 /**
@@ -123,7 +123,8 @@
         final Page enclosedPage = getEnclosedPage();
         if (enclosedPage != null && enclosedPage.isHtmlPage()) {
             final HtmlPage htmlPage = (HtmlPage) enclosedPage;
-            final JavaScriptEngine jsEngine = \
getPage().getWebClient().getJavaScriptEngine(); +            final \
RhinoJavaScriptEngine jsEngine = (RhinoJavaScriptEngine) +                    \
getPage().getWebClient().getJavaScriptEngine();  if (jsEngine.isScriptRunning()) {
                 final PostponedAction action = new PostponedAction(getPage()) {
                     @Override
@@ -394,7 +395,8 @@
         loadSrcWhenAddedToPage_ = false;
         final String src = getSrcAttribute();
 
-        final JavaScriptEngine jsEngine = \
getPage().getWebClient().getJavaScriptEngine(); +        final RhinoJavaScriptEngine \
jsEngine = (RhinoJavaScriptEngine) +                \
                getPage().getWebClient().getJavaScriptEngine();
         // When src is set from a script, loading is postponed until script finishes
         // in fact this implementation is probably wrong: JavaScript URL should be
         // first evaluated and only loading, when any, should be postponed.

Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/DomElement.java
 ===================================================================
--- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/DomElement.java	2015-09-28 \
                11:35:30 UTC (rev 11314)
+++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/DomElement.java	2015-09-28 \
12:26:03 UTC (rev 11315) @@ -47,7 +47,7 @@
 import com.gargoylesoftware.htmlunit.ScriptResult;
 import com.gargoylesoftware.htmlunit.SgmlPage;
 import com.gargoylesoftware.htmlunit.WebClient;
-import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
+import com.gargoylesoftware.htmlunit.javascript.RhinoJavaScriptEngine;
 import com.gargoylesoftware.htmlunit.javascript.host.event.Event;
 import com.gargoylesoftware.htmlunit.javascript.host.event.EventTarget;
 import com.gargoylesoftware.htmlunit.javascript.host.event.MouseEvent;
@@ -774,7 +774,7 @@
             stateUpdated = true;
         }
 
-        final JavaScriptEngine jsEngine = page.getWebClient().getJavaScriptEngine();
+        final RhinoJavaScriptEngine jsEngine = (RhinoJavaScriptEngine) \
page.getWebClient().getJavaScriptEngine();  jsEngine.holdPosponedActions();
         try {
             final ScriptResult scriptResult = doClickFireClickEvent(event);
@@ -1161,7 +1161,7 @@
             }
         };
 
-        final ContextFactory cf = client.getJavaScriptEngine().getContextFactory();
+        final ContextFactory cf = ((RhinoJavaScriptEngine) \
client.getJavaScriptEngine()).getContextFactory();  final ScriptResult result = \
(ScriptResult) cf.call(action);  if (event.isAborted(result)) {
             preventDefault();

Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlInput.java
 ===================================================================
--- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlInput.java	2015-09-28 \
                11:35:30 UTC (rev 11314)
+++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlInput.java	2015-09-28 \
12:26:03 UTC (rev 11315) @@ -29,7 +29,7 @@
 import com.gargoylesoftware.htmlunit.ScriptResult;
 import com.gargoylesoftware.htmlunit.SgmlPage;
 import com.gargoylesoftware.htmlunit.WebAssert;
-import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
+import com.gargoylesoftware.htmlunit.javascript.RhinoJavaScriptEngine;
 import com.gargoylesoftware.htmlunit.javascript.configuration.JsxGetter;
 import com.gargoylesoftware.htmlunit.javascript.configuration.JsxSetter;
 import com.gargoylesoftware.htmlunit.javascript.host.event.Event;
@@ -507,7 +507,8 @@
     static Page executeOnChangeHandlerIfAppropriate(final HtmlElement htmlElement) {
         final SgmlPage page = htmlElement.getPage();
 
-        final JavaScriptEngine engine = \
htmlElement.getPage().getWebClient().getJavaScriptEngine(); +        final \
RhinoJavaScriptEngine engine = (RhinoJavaScriptEngine) +                \
htmlElement.getPage().getWebClient().getJavaScriptEngine();  if \
(engine.isScriptRunning()) {  return page;
         }

Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java
 ===================================================================
--- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java	2015-09-28 \
                11:35:30 UTC (rev 11314)
+++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java	2015-09-28 \
12:26:03 UTC (rev 11315) @@ -41,11 +41,6 @@
 import java.util.SortedSet;
 import java.util.TreeSet;
 
-import net.sourceforge.htmlunit.corejs.javascript.Context;
-import net.sourceforge.htmlunit.corejs.javascript.Script;
-import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
-import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
-
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -77,9 +72,9 @@
 import com.gargoylesoftware.htmlunit.WebResponse;
 import com.gargoylesoftware.htmlunit.WebWindow;
 import com.gargoylesoftware.htmlunit.html.HTMLParser.HtmlUnitDOMBuilder;
-import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
 import com.gargoylesoftware.htmlunit.javascript.JavaScriptErrorListener;
 import com.gargoylesoftware.htmlunit.javascript.PostponedAction;
+import com.gargoylesoftware.htmlunit.javascript.RhinoJavaScriptEngine;
 import com.gargoylesoftware.htmlunit.javascript.host.Window;
 import com.gargoylesoftware.htmlunit.javascript.host.dom.Node;
 import com.gargoylesoftware.htmlunit.javascript.host.event.BeforeUnloadEvent;
@@ -87,6 +82,11 @@
 import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLDocument;
 import com.gargoylesoftware.htmlunit.protocol.javascript.JavaScriptURLConnection;
 
+import net.sourceforge.htmlunit.corejs.javascript.Context;
+import net.sourceforge.htmlunit.corejs.javascript.Script;
+import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
+import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
+
 /**
  * A representation of an HTML page returned from a server.
  * <p>
@@ -983,7 +983,7 @@
             return JavaScriptLoadResult.COMPILATION_ERROR;
         }
 
-        client.getJavaScriptEngine().execute(this, script);
+        ((RhinoJavaScriptEngine) client.getJavaScriptEngine()).execute(this, \
script);  return JavaScriptLoadResult.SUCCESS;
     }
 
@@ -1071,7 +1071,7 @@
         final String scriptCode = response.getContentAsString(scriptEncoding);
         response.cleanUp();
         if (null != scriptCode) {
-            final JavaScriptEngine javaScriptEngine = client.getJavaScriptEngine();
+            final RhinoJavaScriptEngine javaScriptEngine = (RhinoJavaScriptEngine) \
                client.getJavaScriptEngine();
             final Script script = javaScriptEngine.compile(this, scriptCode, \
url.toExternalForm(), 1);  if (script != null) {
                 // cache the script
@@ -2206,7 +2206,7 @@
         super.setDocumentType(type);
 
         if (hasFeature(JS_WINDOW_IN_STANDARDS_MODE) && !isQuirksMode()) {
-            final JavaScriptEngine jsEngine = getWebClient().getJavaScriptEngine();
+            final RhinoJavaScriptEngine jsEngine = (RhinoJavaScriptEngine) \
getWebClient().getJavaScriptEngine();  \
jsEngine.definePropertiesInStandardsMode(this);  }
     }

Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/HtmlUnitContextFactory.java
 ===================================================================
--- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/HtmlUnitContextFactory.java	2015-09-28 \
                11:35:30 UTC (rev 11314)
+++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/HtmlUnitContextFactory.java	2015-09-28 \
12:26:03 UTC (rev 11315) @@ -184,7 +184,7 @@
 
             // Pre process the source code
             final HtmlPage page = (HtmlPage) Context.getCurrentContext()
-                .getThreadLocal(JavaScriptEngine.KEY_STARTING_PAGE);
+                .getThreadLocal(RhinoJavaScriptEngine.KEY_STARTING_PAGE);
             source = preProcess(page, source, sourceName, lineno, null);
 
             //source = new StringScriptPreProcessor(HtmlUnitContextFactory.this)
@@ -337,7 +337,7 @@
                 return browserVersion_.hasFeature(JS_ERROR_STACK);
             case Context.FEATURE_HTMLUNIT_CONSTRUCTOR:
                 final HtmlPage htmlPage = (HtmlPage) Context.getCurrentContext()
-                    .getThreadLocal(JavaScriptEngine.KEY_STARTING_PAGE);
+                    .getThreadLocal(RhinoJavaScriptEngine.KEY_STARTING_PAGE);
                 return \
browserVersion_.hasFeature(BrowserVersionFeatures.JS_CONSTRUCTOR)  || htmlPage == \
null || !htmlPage.isQuirksMode();  case \
Context.FEATURE_HTMLUNIT_FUNCTION_OBJECT_METHOD:

Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java
 ===================================================================
--- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java	2015-09-28 \
                11:35:30 UTC (rev 11314)
+++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java	2015-09-28 \
12:26:03 UTC (rev 11315) @@ -14,78 +14,12 @@
  */
 package com.gargoylesoftware.htmlunit.javascript;
 
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_ALLOW_CONST_ASSIGNMENT;
                
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_CONSTRUCTOR;
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_DATE_USE_UTC;
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_DEFINE_GETTER;
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_DONT_ENUM_FUNCTIONS;
                
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_ECMA5_FUNCTIONS;
                
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_FUNCTION_BIND;
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_FUNCTION_TOSOURCE;
                
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_IMAGE_PROTOTYPE_SAME_AS_HTML_IMAGE;
                
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INTL;
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_Iterator;
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OBJECT_WITH_PROTOTYPE_PROPERTY_IN_WINDOW_SCOPE;
                
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OPTION_PROTOTYPE_SAME_AS_HTML_OPTION;
                
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WINDOW_ACTIVEXOBJECT_HIDDEN;
                
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_XML;
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.STRING_CONTAINS;
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.STRING_TRIM;
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.STRING_TRIM_LEFT_RIGHT;
                
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Stack;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import com.gargoylesoftware.htmlunit.BrowserVersion;
 import com.gargoylesoftware.htmlunit.InteractivePage;
-import com.gargoylesoftware.htmlunit.Page;
-import com.gargoylesoftware.htmlunit.ScriptException;
-import com.gargoylesoftware.htmlunit.WebAssert;
-import com.gargoylesoftware.htmlunit.WebClient;
 import com.gargoylesoftware.htmlunit.WebWindow;
-import com.gargoylesoftware.htmlunit.html.DomNode;
-import com.gargoylesoftware.htmlunit.html.HtmlDivision;
-import com.gargoylesoftware.htmlunit.html.HtmlPage;
-import com.gargoylesoftware.htmlunit.javascript.background.BackgroundJavaScriptFactory;
                
-import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptExecutor;
-import com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration;
 import com.gargoylesoftware.htmlunit.javascript.configuration.JavaScriptConfiguration;
                
-import com.gargoylesoftware.htmlunit.javascript.host.ActiveXObject;
-import com.gargoylesoftware.htmlunit.javascript.host.DateCustom;
-import com.gargoylesoftware.htmlunit.javascript.host.Element;
-import com.gargoylesoftware.htmlunit.javascript.host.StringCustom;
-import com.gargoylesoftware.htmlunit.javascript.host.Window;
-import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLDocument;
-import com.gargoylesoftware.htmlunit.javascript.host.intl.Intl;
 
-import net.sourceforge.htmlunit.corejs.javascript.BaseFunction;
-import net.sourceforge.htmlunit.corejs.javascript.Context;
-import net.sourceforge.htmlunit.corejs.javascript.ContextAction;
-import net.sourceforge.htmlunit.corejs.javascript.Function;
-import net.sourceforge.htmlunit.corejs.javascript.FunctionObject;
-import net.sourceforge.htmlunit.corejs.javascript.Script;
-import net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime;
-import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
-import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
-import net.sourceforge.htmlunit.corejs.javascript.UniqueTag;
-
 /**
- * A wrapper for the <a href="http://www.mozilla.org/rhino">Rhino JavaScript \
                engine</a>
- * that provides browser specific features.<br/>
- * Like all classes in this package, this class is not intended for direct use
- * and may change without notice.
+ * An interface for {@code JavaScriptEngine}.
  *
  * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
  * @author <a href="mailto:chen_jun@users.sourceforge.net">Chen Jun</a>
@@ -99,724 +33,28 @@
  * @author Amit Manjhi
  * @author Ronald Brill
  * @author Frank Danek
- * @see <a href="http://groups-beta.google.com/group/netscape.public.mozilla.jseng/browse_thread/thread/b4edac57329cf49f/069e9307ec89111f">
                
- * Rhino and Java Browser</a>
  */
-public class JavaScriptEngine {
+public interface JavaScriptEngine {
 
-    private static final Log LOG = LogFactory.getLog(JavaScriptEngine.class);
-
-    private final WebClient webClient_;
-    private final HtmlUnitContextFactory contextFactory_;
-    private final JavaScriptConfiguration jsConfig_;
-
-    private transient ThreadLocal<Boolean> javaScriptRunning_;
-    private transient ThreadLocal<List<PostponedAction>> postponedActions_;
-    private transient boolean holdPostponedActions_;
-
-    /** The JavaScriptExecutor corresponding to all windows of this Web client */
-    private transient JavaScriptExecutor javaScriptExecutor_;
-
     /**
-     * Key used to place the scope in which the execution of some JavaScript code
-     * started as thread local attribute in current context.<br/>
-     * This is needed to resolve some relative locations relatively to the page
-     * in which the script is executed and not to the page which location is \
changed. +     * Gets the associated configuration.
+     * @return the configuration
      */
-    public static final String KEY_STARTING_SCOPE = "startingScope";
+    JavaScriptConfiguration getJavaScriptConfiguration();
 
     /**
-     * Key used to place the {@link InteractivePage} for which the JavaScript code \
                is executed
-     * as thread local attribute in current context.
+     * Adds an action that should be executed first when the script currently being \
executed has finished. +     * @param action the action
      */
-    public static final String KEY_STARTING_PAGE = "startingPage";
+    void addPostponedAction(final PostponedAction action);
 
     /**
-     * Creates an instance for the specified {@link WebClient}.
-     *
-     * @param webClient the client that will own this engine
+     * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT \
YOUR OWN RISK.</span><br> +     * Process postponed actions, if any.
      */
-    public JavaScriptEngine(final WebClient webClient) {
-        webClient_ = webClient;
-        contextFactory_ = new HtmlUnitContextFactory(webClient);
-        initTransientFields();
-        jsConfig_ = \
                JavaScriptConfiguration.getInstance(webClient.getBrowserVersion());
-    }
+    void processPostponedActions();
 
     /**
-     * Returns the web client that this engine is associated with.
-     * @return the web client
-     */
-    public final WebClient getWebClient() {
-        return webClient_;
-    }
-
-    /**
-     * Returns this JavaScript engine's Rhino {@link \
                net.sourceforge.htmlunit.corejs.javascript.ContextFactory}.
-     * @return this JavaScript engine's Rhino {@link \
                net.sourceforge.htmlunit.corejs.javascript.ContextFactory}
-     */
-    public HtmlUnitContextFactory getContextFactory() {
-        return contextFactory_;
-    }
-
-    /**
-     * Performs initialization for the given webWindow.
-     * @param webWindow the web window to initialize for
-     */
-    public void initialize(final WebWindow webWindow) {
-        WebAssert.notNull("webWindow", webWindow);
-
-        final ContextAction action = new ContextAction() {
-            @Override
-            public Object run(final Context cx) {
-                try {
-                    init(webWindow, cx);
-                }
-                catch (final Exception e) {
-                    LOG.error("Exception while initializing JavaScript for the \
                page", e);
-                    throw new ScriptException(null, e); // BUG: null is not useful.
-                }
-
-                return null;
-            }
-        };
-
-        getContextFactory().call(action);
-    }
-
-    /**
-     * Returns the JavaScriptExecutor.
-     * @return the JavaScriptExecutor.
-     */
-    public JavaScriptExecutor getJavaScriptExecutor() {
-        return javaScriptExecutor_;
-    }
-
-    /**
-     * 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 Context context) throws \
                Exception {
-        final WebClient webClient = webWindow.getWebClient();
-        final BrowserVersion browserVersion = webClient.getBrowserVersion();
-        final Map<Class<? extends HtmlUnitScriptable>, HtmlUnitScriptable> \
                prototypes = new HashMap<>();
-        final Map<String, HtmlUnitScriptable> prototypesPerJSName = new HashMap<>();
-
-        final Window window = new Window();
-        ((SimpleScriptable) window).setClassName("Window");
-        context.initStandardObjects(window);
-
-        if (browserVersion.hasFeature(JS_CONSTRUCTOR)) {
-            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(browserVersion, window, window, new Window());
-            }
-        }
-        else {
-            deleteProperties(window, "constructor");
-        }
-
-        // remove some objects, that Rhino defines in top scope but that we don't \
                want
-        deleteProperties(window, "java", "javax", "org", "com", "edu", "net",
-                "JavaAdapter", "JavaImporter", "Continuation", "Packages", \
                "getClass");
-        if (!browserVersion.hasFeature(JS_XML)) {
-            deleteProperties(window, "XML", "XMLList", "Namespace", "QName");
-        }
-
-        if (!browserVersion.hasFeature(JS_Iterator)) {
-            deleteProperties(window, "Iterator", "StopIteration");
-        }
-
-        if (browserVersion.hasFeature(JS_INTL)) {
-            final Intl intl = new Intl();
-            intl.setParentScope(window);
-            window.defineProperty(intl.getClassName(), intl, \
                ScriptableObject.DONTENUM);
-            intl.defineProperties(browserVersion);
-        }
-
-        // put custom object to be called as very last prototype to call the \
                fallback getter (if any)
-        final Scriptable fallbackCaller = new FallbackCaller();
-        ScriptableObject.getObjectPrototype(window).setPrototype(fallbackCaller);
-
-        final boolean putPrototypeInWindowScope =
-                browserVersion.hasFeature(JS_OBJECT_WITH_PROTOTYPE_PROPERTY_IN_WINDOW_SCOPE);
                
-        for (final ClassConfiguration config : jsConfig_.getAll()) {
-            final boolean isWindow = \
                Window.class.getName().equals(config.getHostClass().getName());
-            if (isWindow) {
-                configureConstantsPropertiesAndFunctions(config, window, \
                browserVersion);
-
-                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
-                    if (putPrototypeInWindowScope) {
-                        final HtmlUnitScriptable obj = \
                config.getHostClass().newInstance();
-                        prototype.defineProperty("__proto__", prototype, \
                ScriptableObject.DONTENUM);
-                        obj.defineProperty("prototype", prototype, \
                ScriptableObject.DONTENUM); // but not setPrototype!
-                        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);
-
-                        if (obj.getClass() == Element.class) {
-                            final Page page = webWindow.getEnclosedPage();
-                            if (page != null && page.isHtmlPage()) {
-                                final DomNode domNode = new HtmlDivision("", \
                (HtmlPage) page, null);
-                                ((SimpleScriptable) obj).setDomNode(domNode);
-                            }
-                        }
-                    }
-                }
-                prototypes.put(config.getHostClass(), prototype);
-                prototypesPerJSName.put(config.getClassName(), prototype);
-            }
-        }
-
-        for (final ClassConfiguration config : jsConfig_.getAll()) {
-            final Member jsConstructor = config.getJsConstructor();
-            final String jsClassName = config.getClassName();
-            Scriptable prototype = prototypesPerJSName.get(jsClassName);
-            final String hostClassSimpleName = \
                config.getHostClass().getSimpleName();
-            if ("Image".equals(hostClassSimpleName)
-                    && \
                browserVersion.hasFeature(JS_IMAGE_PROTOTYPE_SAME_AS_HTML_IMAGE)) {
-                prototype = prototypesPerJSName.get("HTMLImageElement");
-            }
-            if ("Option".equals(hostClassSimpleName)
-                    && \
                browserVersion.hasFeature(JS_OPTION_PROTOTYPE_SAME_AS_HTML_OPTION)) {
-                prototype = prototypesPerJSName.get("HTMLOptionElement");
-            }
-
-            switch (hostClassSimpleName) {
-                case "WebKitAnimationEvent":
-                    prototype = prototypesPerJSName.get("AnimationEvent");
-                    break;
-
-                case "WebKitMutationObserver":
-                    prototype = prototypesPerJSName.get("MutationObserver");
-                    break;
-
-                case "WebKitTransitionEvent":
-                    prototype = prototypesPerJSName.get("TransitionEvent");
-                    break;
-
-                case "webkitAudioContext":
-                    prototype = prototypesPerJSName.get("AudioContext");
-                    break;
-
-                case "webkitIDBCursor":
-                    prototype = prototypesPerJSName.get("IDBCursor");
-                    break;
-
-                case "webkitIDBDatabase":
-                    prototype = prototypesPerJSName.get("IDBDatabase");
-                    break;
-
-                case "webkitIDBFactory":
-                    prototype = prototypesPerJSName.get("IDBFactory");
-                    break;
-
-                case "webkitIDBIndex":
-                    prototype = prototypesPerJSName.get("IDBIndex");
-                    break;
-
-                case "webkitIDBKeyRange":
-                    prototype = prototypesPerJSName.get("IDBKeyRange");
-                    break;
-
-                case "webkitIDBObjectStore":
-                    prototype = prototypesPerJSName.get("IDBObjectStore");
-                    break;
-
-                case "webkitIDBRequest":
-                    prototype = prototypesPerJSName.get("IDBRequest");
-                    break;
-
-                case "webkitIDBTransaction":
-                    prototype = prototypesPerJSName.get("IDBTransaction");
-                    break;
-
-                case "webkitOfflineAudioContext":
-                    prototype = prototypesPerJSName.get("OfflineAudioContext");
-                    break;
-
-                case "webkitURL":
-                    prototype = prototypesPerJSName.get("URL");
-                    break;
-
-                default:
-            }
-            if (prototype != null && config.isJsObject()) {
-                if (jsConstructor != null) {
-                    final BaseFunction function;
-                    if ("Window".equals(jsClassName)) {
-                        function = (BaseFunction) \
                ScriptableObject.getProperty(window, "constructor");
-                    }
-                    else {
-                        function = new RecursiveFunctionObject(jsClassName, \
                jsConstructor, window);
-                    }
-
-                    if ("WebKitAnimationEvent".equals(hostClassSimpleName)
-                            || "WebKitMutationObserver".equals(hostClassSimpleName)
-                            || "WebKitTransitionEvent".equals(hostClassSimpleName)
-                            || "webkitAudioContext".equals(hostClassSimpleName)
-                            || "webkitIDBCursor".equals(hostClassSimpleName)
-                            || "webkitIDBDatabase".equals(hostClassSimpleName)
-                            || "webkitIDBFactory".equals(hostClassSimpleName)
-                            || "webkitIDBIndex".equals(hostClassSimpleName)
-                            || "webkitIDBKeyRange".equals(hostClassSimpleName)
-                            || "webkitIDBObjectStore".equals(hostClassSimpleName)
-                            || "webkitIDBRequest".equals(hostClassSimpleName)
-                            || "webkitIDBTransaction".equals(hostClassSimpleName)
-                            || \
                "webkitOfflineAudioContext".equals(hostClassSimpleName)
-                            || \
                "webkitOfflineAudioContext".equals(hostClassSimpleName)
-                            || "webkitURL".equals(hostClassSimpleName)
-                            || "Image".equals(hostClassSimpleName)
-                            || "Option".equals(hostClassSimpleName)) {
-                        final Object prototypeProperty = \
                ScriptableObject.getProperty(window, prototype.getClassName());
-
-                        if (function instanceof FunctionObject) {
-                            ((FunctionObject) function).addAsConstructor(window, \
                prototype);
-                        }
-
-                        ScriptableObject.defineProperty(window, hostClassSimpleName, \
                function,
-                                ScriptableObject.DONTENUM);
-
-                        // the prototype class name is set as a side effect of \
                functionObject.addAsConstructor
-                        // 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) {
-                            ((FunctionObject) function).addAsConstructor(window, \
                prototype);
-                        }
-                    }
-
-                    configureConstants(config, function);
-                    configureStaticFunctions(config, function);
-                    configureStaticProperties(config, browserVersion, function);
-                }
-                else {
-                    if (browserVersion.hasFeature(JS_CONSTRUCTOR)) {
-                        final ScriptableObject constructor;
-                        if ("Window".equals(jsClassName)) {
-                            constructor = (ScriptableObject) \
                ScriptableObject.getProperty(window, "constructor");
-                        }
-                        else {
-                            constructor = config.getHostClass().newInstance();
-                            ((SimpleScriptable) \
                constructor).setClassName(config.getClassName());
-                        }
-                        defineConstructor(browserVersion, window, prototype, \
                constructor);
-                        configureConstants(config, constructor);
-                    }
-                    else {
-                        if (!"Window".equals(jsClassName)) {
-                            final ScriptableObject constructor = \
                config.getHostClass().newInstance();
-                            constructor.setParentScope(window);
-                            window.defineProperty(constructor.getClassName(), \
                constructor, ScriptableObject.DONTENUM);
-                        }
-
-                        deleteProperties(prototype, "constructor");
-                    }
-                }
-            }
-        }
-        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, HtmlUnitScriptable> entry : \
                prototypesPerJSName.entrySet()) {
-            final String name = entry.getKey();
-            final ClassConfiguration config = jsConfig_.getClassConfiguration(name);
-            Scriptable prototype = entry.getValue();
-            if (prototype.getPrototype() != null) {
-                prototype = prototype.getPrototype(); // "double prototype" hack for \
                FF
-            }
-            if (!StringUtils.isEmpty(config.getExtendedClassName())) {
-                final Scriptable parentPrototype = \
                prototypesPerJSName.get(config.getExtendedClassName());
-                prototype.setPrototype(parentPrototype);
-            }
-            else {
-                prototype.setPrototype(objectPrototype);
-            }
-        }
-
-        // IE11 ActiveXObject simulation
-        // see http://msdn.microsoft.com/en-us/library/ie/dn423948%28v=vs.85%29.aspx
-        // DEV Note: this is at the moment the only usage of HiddenFunctionObject
-        //           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);
-                functionObject.addAsConstructor(window, prototype);
-            }
-        }
-
-        // Rhino defines too much methods for us, particularly since implementation \
                of ECMAScript5
-        removePrototypeProperties(window, "String", "equals", "equalsIgnoreCase");
-        if (!browserVersion.hasFeature(STRING_TRIM)) {
-            removePrototypeProperties(window, "String", "trim");
-        }
-        if (!browserVersion.hasFeature(STRING_TRIM_LEFT_RIGHT)) {
-            removePrototypeProperties(window, "String", "trimLeft");
-            removePrototypeProperties(window, "String", "trimRight");
-        }
-        if (browserVersion.hasFeature(STRING_CONTAINS)) {
-            final ScriptableObject stringPrototype =
-                (ScriptableObject) ScriptableObject.getClassPrototype(window, \
                "String");
-            stringPrototype.defineFunctionProperties(new String[] {"contains"},
-                StringCustom.class, ScriptableObject.EMPTY);
-        }
-
-        if (!browserVersion.hasFeature(JS_FUNCTION_BIND)) {
-            removePrototypeProperties(window, "Function", "bind");
-        }
-        if (!browserVersion.hasFeature(JS_ECMA5_FUNCTIONS)) {
-            removePrototypeProperties(window, "Date", "toISOString", "toJSON");
-        }
-
-        if (!browserVersion.hasFeature(JS_DEFINE_GETTER)) {
-            removePrototypeProperties(window, "Object", "__defineGetter__", \
                "__defineSetter__", "__lookupGetter__",
-                    "__lookupSetter__");
-        }
-
-        // only FF has toSource
-        if (!browserVersion.hasFeature(JS_FUNCTION_TOSOURCE)) {
-            deleteProperties(window, "uneval");
-            removePrototypeProperties(window, "Object", "toSource");
-            removePrototypeProperties(window, "Array", "toSource");
-            removePrototypeProperties(window, "Date", "toSource");
-            removePrototypeProperties(window, "Function", "toSource");
-            removePrototypeProperties(window, "Number", "toSource");
-            removePrototypeProperties(window, "String", "toSource");
-        }
-        deleteProperties(window, "isXMLName");
-
-        NativeFunctionToStringFunction.installFix(window, \
                webClient.getBrowserVersion());
-
-        if (browserVersion.hasFeature(JS_ALLOW_CONST_ASSIGNMENT)) {
-            makeConstWritable(window, "undefined", "NaN", "Infinity");
-        }
-
-        final ScriptableObject datePrototype = (ScriptableObject) \
                ScriptableObject.getClassPrototype(window, "Date");
-        datePrototype.defineFunctionProperties(new String[] {"toLocaleDateString", \
                "toLocaleTimeString"},
-                DateCustom.class, ScriptableObject.DONTENUM);
-
-        if (browserVersion.hasFeature(JS_DATE_USE_UTC)) {
-            datePrototype.defineFunctionProperties(new String[] {"toUTCString"},
-                    DateCustom.class, ScriptableObject.DONTENUM);
-        }
-
-        window.setPrototypes(prototypes, prototypesPerJSName);
-        window.initialize(webWindow);
-    }
-
-    private void defineConstructor(final BrowserVersion browserVersion, final Window \
                window,
-            final Scriptable prototype, final ScriptableObject constructor) {
-        constructor.setParentScope(window);
-        final Object constructorValue = browserVersion.hasFeature(JS_CONSTRUCTOR) ? \
                constructor : null;
-        ScriptableObject.defineProperty(prototype, "constructor", constructorValue,
-                ScriptableObject.DONTENUM  | ScriptableObject.PERMANENT | \
                ScriptableObject.READONLY);
-        ScriptableObject.defineProperty(constructor, "prototype", prototype,
-                ScriptableObject.DONTENUM  | ScriptableObject.PERMANENT | \
                ScriptableObject.READONLY);
-        window.defineProperty(constructor.getClassName(), constructor, \
                ScriptableObject.DONTENUM);
-    }
-
-    private void makeConstWritable(final ScriptableObject scope, final String... \
                constNames) {
-        for (final String name : constNames) {
-            final Object value = ScriptableObject.getProperty(scope, name);
-            ScriptableObject.defineProperty(scope, name, value,
-                    ScriptableObject.DONTENUM | ScriptableObject.PERMANENT);
-        }
-    }
-
-    /**
-     * Deletes the properties with the provided names.
-     * @param scope the scope from which properties have to be removed
-     * @param propertiesToDelete the list of property names
-     */
-    private void deleteProperties(final Scriptable scope, final String... \
                propertiesToDelete) {
-        for (final String property : propertiesToDelete) {
-            scope.delete(property);
-        }
-    }
-
-    /**
-     * Define properties in Standards Mode.
-     *
-     * @param page the page
-     */
-    public void definePropertiesInStandardsMode(final HtmlPage page) {
-        final Window window = ((HTMLDocument) page.getScriptObject()).getWindow();
-        final BrowserVersion browserVersion = window.getBrowserVersion();
-        for (final ClassConfiguration config : jsConfig_.getAll()) {
-            final String jsClassName = config.getClassName();
-            if (config.isDefinedInStandardsMode()) {
-                final Scriptable prototype = window.getPrototype(jsClassName);
-                if ("Window".equals(jsClassName)) {
-                    defineConstructor(browserVersion, window, window, new Window());
-                }
-                else if (!config.isJsObject()) {
-                    try {
-                        final ScriptableObject constructor = \
                config.getHostClass().newInstance();
-                        defineConstructor(browserVersion, window, prototype, \
                constructor);
-                    }
-                    catch (final Exception e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Removes prototype properties.
-     * @param scope the scope
-     * @param className the class for which properties should be removed
-     * @param properties the properties to remove
-     */
-    private void removePrototypeProperties(final Scriptable scope, final String \
                className,
-            final String... properties) {
-        final ScriptableObject prototype = (ScriptableObject) \
                ScriptableObject.getClassPrototype(scope, className);
-        for (final String property : properties) {
-            prototype.delete(property);
-        }
-    }
-
-    /**
-     * Configures the specified class for access via JavaScript.
-     * @param config the configuration settings for the class to be configured
-     * @param window the scope within which to configure the class
-     * @param browserVersion the browser version
-     * @throws InstantiationException if the new class cannot be instantiated
-     * @throws IllegalAccessException if we don't have access to create the new \
                instance
-     * @return the created prototype
-     */
-    public static HtmlUnitScriptable configureClass(final ClassConfiguration config, \
                final Scriptable window,
-            final BrowserVersion browserVersion)
-        throws InstantiationException, IllegalAccessException {
-
-        final HtmlUnitScriptable prototype = config.getHostClass().newInstance();
-        prototype.setParentScope(window);
-        prototype.setClassName(config.getClassName());
-
-        configureConstantsPropertiesAndFunctions(config, prototype, browserVersion);
-
-        return prototype;
-    }
-
-    /**
-     * Configures constants, properties and functions on the object.
-     * @param config the configuration for the object
-     * @param scriptable the object to configure
-     */
-    private static void configureConstantsPropertiesAndFunctions(final \
                ClassConfiguration config,
-            final ScriptableObject scriptable, final BrowserVersion browserVersion) \
                {
-
-        // the constants
-        configureConstants(config, scriptable);
-
-        // the properties
-        configureProperties(config, browserVersion, scriptable);
-
-        configureFunctions(config, browserVersion, scriptable);
-    }
-
-    private static void configureFunctions(final ClassConfiguration config,
-            final BrowserVersion browserVersion,
-            final ScriptableObject scriptable) {
-        final int attributes;
-        if (browserVersion.hasFeature(JS_DONT_ENUM_FUNCTIONS)) {
-            attributes = ScriptableObject.DONTENUM;
-        }
-        else {
-            attributes = ScriptableObject.EMPTY;
-        }
-        // the functions
-        for (final Entry<String, Method> functionInfo : config.getFunctionEntries()) \
                {
-            final String functionName = functionInfo.getKey();
-            final Method method = functionInfo.getValue();
-            final FunctionObject functionObject = new FunctionObject(functionName, \
                method, scriptable);
-            scriptable.defineProperty(functionName, functionObject, attributes);
-        }
-    }
-
-    private static void configureConstants(final ClassConfiguration config,
-            final ScriptableObject scriptable) {
-        final Class<?> linkedClass = config.getHostClass();
-        for (final String constant : config.getConstants()) {
-            try {
-                final Object value = linkedClass.getField(constant).get(null);
-                int flag = ScriptableObject.READONLY | ScriptableObject.PERMANENT;
-                // https://code.google.com/p/chromium/issues/detail?id=500633
-                if (config.getClassName().endsWith("Array")) {
-                    flag |= ScriptableObject.DONTENUM;
-                }
-                scriptable.defineProperty(constant, value, flag);
-            }
-            catch (final Exception e) {
-                throw Context.reportRuntimeError("Cannot get field '" + constant + \
                "' for type: "
-                    + config.getHostClass().getName());
-            }
-        }
-    }
-
-    private static void configureProperties(final ClassConfiguration config, final \
                BrowserVersion browserVersion,
-            final ScriptableObject scriptable) {
-
-        for (final Entry<String, ClassConfiguration.PropertyInfo> propertyEntry : \
                config.getPropertyEntries()) {
-            final String propertyName = propertyEntry.getKey();
-            final Method readMethod = propertyEntry.getValue().getReadMethod();
-            final Method writeMethod = propertyEntry.getValue().getWriteMethod();
-            int flag = ScriptableObject.EMPTY;
-
-            // https://code.google.com/p/chromium/issues/detail?id=492999
-            if (browserVersion.isChrome() && "cssFloat".equals(propertyName)) {
-                flag = ScriptableObject.DONTENUM;
-            }
-            scriptable.defineProperty(propertyName, null, readMethod, writeMethod, \
                flag);
-        }
-    }
-
-    private static void configureStaticProperties(final ClassConfiguration config,
-            final BrowserVersion browserVersion,
-            final ScriptableObject scriptable) {
-        for (final Entry<String, ClassConfiguration.PropertyInfo> propertyEntry
-                : config.getStaticPropertyEntries()) {
-            final String propertyName = propertyEntry.getKey();
-            final Method readMethod = propertyEntry.getValue().getReadMethod();
-            final Method writeMethod = propertyEntry.getValue().getWriteMethod();
-            final int flag = ScriptableObject.EMPTY;
-
-            scriptable.defineProperty(propertyName, null, readMethod, writeMethod, \
                flag);
-        }
-    }
-
-    private static void configureStaticFunctions(final ClassConfiguration config,
-            final ScriptableObject scriptable) {
-        for (final Entry<String, Method> staticfunctionInfo : \
                config.getStaticFunctionEntries()) {
-            final String functionName = staticfunctionInfo.getKey();
-            final Method method = staticfunctionInfo.getValue();
-            final FunctionObject staticFunctionObject = new \
                FunctionObject(functionName, method,
-                    scriptable);
-            scriptable.defineProperty(functionName, staticFunctionObject, \
                ScriptableObject.EMPTY);
-        }
-    }
-
-    /**
-     * Register WebWindow with the JavaScriptExecutor.
-     * @param webWindow the WebWindow to be registered.
-     */
-    public synchronized void registerWindowAndMaybeStartEventLoop(final WebWindow \
                webWindow) {
-        if (javaScriptExecutor_ == null) {
-            javaScriptExecutor_ = \
                BackgroundJavaScriptFactory.theFactory().createJavaScriptExecutor(webClient_);
                
-        }
-        javaScriptExecutor_.addWindow(webWindow);
-    }
-
-    /**
-     * Executes the jobs in the eventLoop till timeoutMillis expires or the \
                eventLoop becomes empty.
-     * No use in non-GAE mode (see {@link \
                com.gargoylesoftware.htmlunit.gae.GAEUtils#isGaeMode}.
-     * @param timeoutMillis the timeout in milliseconds
-     * @return the number of jobs executed
-     */
-    public int pumpEventLoop(final long timeoutMillis) {
-        if (javaScriptExecutor_ == null) {
-            return 0;
-        }
-        return javaScriptExecutor_.pumpEventLoop(timeoutMillis);
-    }
-
-    /**
-     * Shutdown the JavaScriptEngine.
-     */
-    public void shutdown() {
-        if (javaScriptExecutor_ != null) {
-            javaScriptExecutor_.shutdown();
-            javaScriptExecutor_ = null;
-        }
-        if (postponedActions_ != null) {
-            postponedActions_.remove();
-        }
-        if (javaScriptRunning_ != null) {
-            javaScriptRunning_.remove();
-        }
-        holdPostponedActions_ = false;
-    }
-
-    /**
-     * Compiles the specified JavaScript code in the context of a given HTML page.
-     *
-     * @param page the page that the code will execute within
-     * @param sourceCode the JavaScript code to execute
-     * @param sourceName the name that will be displayed on error conditions
-     * @param startLine the line at which the script source starts
-     * @return the result of executing the specified code
-     */
-    public Script compile(final InteractivePage page, final String sourceCode,
-                           final String sourceName, final int startLine) {
-        final Scriptable scope = getScope(page, null);
-        return compile(page, scope, sourceCode, sourceName, startLine);
-    }
-
-    /**
-     * Compiles the specified JavaScript code in the context of a given scope.
-     *
-     * @param owningPage the page from which the code started
-     * @param scope the scope in which to execute the javascript code
-     * @param sourceCode the JavaScript code to execute
-     * @param sourceName the name that will be displayed on error conditions
-     * @param startLine the line at which the script source starts
-     * @return the result of executing the specified code
-     */
-    public Script compile(final InteractivePage owningPage, final Scriptable scope, \
                final String sourceCode,
-            final String sourceName, final int startLine) {
-        WebAssert.notNull("sourceCode", sourceCode);
-
-        if (LOG.isTraceEnabled()) {
-            final String newline = System.getProperty("line.separator");
-            LOG.trace("Javascript compile " + sourceName + newline + sourceCode + \
                newline);
-        }
-
-        final String source = sourceCode;
-        final ContextAction action = new HtmlUnitContextAction(scope, owningPage) {
-            @Override
-            public Object doRun(final Context cx) {
-                return cx.compileString(source, sourceName, startLine, null);
-            }
-
-            @Override
-            protected String getSourceCode(final Context cx) {
-                return source;
-            }
-        };
-
-        return (Script) getContextFactory().call(action);
-    }
-
-    /**
      * Executes the specified JavaScript code in the context of a given page.
      *
      * @param page the page that the code will execute within
@@ -825,334 +63,41 @@
      * @param startLine the line at which the script source starts
      * @return the result of executing the specified code
      */
-    public Object execute(final InteractivePage page,
+    Object execute(final InteractivePage page,
                            final String sourceCode,
                            final String sourceName,
-                           final int startLine) {
+                           final int startLine);
 
-        final Script script = compile(page, sourceCode, sourceName, startLine);
-        if (script == null) { // happens with syntax error + \
                throwExceptionOnScriptError = false
-            return null;
-        }
-        return execute(page, script);
-    }
-
     /**
-     * Executes the specified JavaScript code in the context of a given page.
-     *
-     * @param page the page that the code will execute within
-     * @param script the script to execute
-     * @return the result of executing the specified code
+     * Register WebWindow with the JavaScriptExecutor.
+     * @param webWindow the WebWindow to be registered.
      */
-    public Object execute(final InteractivePage page, final Script script) {
-        final Scriptable scope = getScope(page, null);
-        return execute(page, scope, script);
-    }
+    void registerWindowAndMaybeStartEventLoop(final WebWindow webWindow);
 
     /**
-     * Executes the specified JavaScript code in the given scope.
-     *
-     * @param page the page that started the execution
-     * @param scope the scope in which to execute
-     * @param script the script to execute
-     * @return the result of executing the specified code
+     * Performs initialization for the given webWindow.
+     * @param webWindow the web window to initialize for
      */
-    public Object execute(final InteractivePage page, final Scriptable scope, final \
                Script script) {
-        final ContextAction action = new HtmlUnitContextAction(scope, page) {
-            @Override
-            public Object doRun(final Context cx) {
-                return script.exec(cx, scope);
-            }
+    void initialize(final WebWindow webWindow);
 
-            @Override
-            protected String getSourceCode(final Context cx) {
-                return null;
-            }
-        };
-
-        return getContextFactory().call(action);
-    }
-
     /**
-     * Calls a JavaScript function and return the result.
-     * @param page the page
-     * @param javaScriptFunction the function to call
-     * @param thisObject the this object for class method calls
-     * @param args the list of arguments to pass to the function
-     * @param node the HTML element that will act as the context
-     * @return the result of the function call
+     * Sets the number of milliseconds that a script is allowed to execute before \
being terminated. +     * A value of 0 or less means no timeout.
+     *
+     * @param timeout the timeout value, in milliseconds
      */
-    public Object callFunction(
-            final InteractivePage page,
-            final Function javaScriptFunction,
-            final Scriptable thisObject,
-            final Object[] args,
-            final DomNode node) {
+    void setJavaScriptTimeout(final long timeout);
 
-        final Scriptable scope = getScope(page, node);
-
-        return callFunction(page, javaScriptFunction, scope, thisObject, args);
-    }
-
     /**
-     * Calls the given function taking care of synchronization issues.
-     * @param page the interactive page that caused this script to executed
-     * @param function the JavaScript function to execute
-     * @param scope the execution scope
-     * @param thisObject the 'this' object
-     * @param args the function's arguments
-     * @return the function result
+     * Returns the number of milliseconds that a script is allowed to execute before \
being terminated. +     * A value of 0 or less means no timeout.
+     *
+     * @return the timeout value, in milliseconds
      */
-    public Object callFunction(final InteractivePage page, final Function function,
-            final Scriptable scope, final Scriptable thisObject, final Object[] \
args) { +    long getJavaScriptTimeout();
 
-        final ContextAction action = new HtmlUnitContextAction(scope, page) {
-            @Override
-            public Object doRun(final Context cx) {
-                if (ScriptRuntime.hasTopCall(cx)) {
-                    return function.call(cx, scope, thisObject, args);
-                }
-                return ScriptRuntime.doTopCall(function, cx, scope, thisObject, \
                args);
-            }
-            @Override
-            protected String getSourceCode(final Context cx) {
-                return cx.decompileFunction(function, 2);
-            }
-        };
-        return getContextFactory().call(action);
-    }
-
-    private Scriptable getScope(final InteractivePage page, final DomNode node) {
-        if (node != null) {
-            return node.getScriptObject();
-        }
-        return (Window) page.getEnclosingWindow().getScriptObject();
-    }
-
     /**
-     * Indicates if JavaScript is running in current thread.<br/>
-     * This allows code to know if there own evaluation is has been triggered by \
                some JS code.
-     * @return {@code true} if JavaScript is running
+     * Shutdown the JavaScriptEngine.
      */
-    public boolean isScriptRunning() {
-        return Boolean.TRUE.equals(javaScriptRunning_.get());
-    }
-
-    /**
-     * Facility for ContextAction usage.
-     * ContextAction should be preferred because according to Rhino doc it
-     * "guarantees proper association of Context instances with the current thread \
                and is faster".
-     */
-    private abstract class HtmlUnitContextAction implements ContextAction {
-        private final Scriptable scope_;
-        private final InteractivePage page_;
-        HtmlUnitContextAction(final Scriptable scope, final InteractivePage page) {
-            scope_ = scope;
-            page_ = page;
-        }
-
-        @Override
-        public final Object run(final Context cx) {
-            final Boolean javaScriptAlreadyRunning = javaScriptRunning_.get();
-            javaScriptRunning_.set(Boolean.TRUE);
-
-            try {
-                // KEY_STARTING_SCOPE maintains a stack of scopes
-                @SuppressWarnings("unchecked")
-                Stack<Scriptable> stack = (Stack<Scriptable>) \
                cx.getThreadLocal(JavaScriptEngine.KEY_STARTING_SCOPE);
-                if (null == stack) {
-                    stack = new Stack<>();
-                    cx.putThreadLocal(KEY_STARTING_SCOPE, stack);
-                }
-
-                final Object response;
-                stack.push(scope_);
-                try {
-                    cx.putThreadLocal(KEY_STARTING_PAGE, page_);
-                    synchronized (page_) { // 2 scripts can't be executed in \
                parallel for one page
-                        if (page_ != page_.getEnclosingWindow().getEnclosedPage()) {
-                            return null; // page has been unloaded
-                        }
-                        response = doRun(cx);
-                    }
-                }
-                finally {
-                    stack.pop();
-                }
-
-                // doProcessPostponedActions is synchronized
-                // moved out of the sync block to avoid deadlocks
-                if (!holdPostponedActions_) {
-                    doProcessPostponedActions();
-                }
-                return response;
-            }
-            catch (final Exception e) {
-                handleJavaScriptException(new ScriptException(page_, e, \
                getSourceCode(cx)), true);
-                return null;
-            }
-            catch (final TimeoutError e) {
-                final JavaScriptErrorListener javaScriptErrorListener = \
                getWebClient().getJavaScriptErrorListener();
-                if (javaScriptErrorListener != null) {
-                    javaScriptErrorListener.timeoutError(page_, e.getAllowedTime(), \
                e.getExecutionTime());
-                }
-                if (getWebClient().getOptions().isThrowExceptionOnScriptError()) {
-                    throw new RuntimeException(e);
-                }
-                LOG.info("Caught script timeout error", e);
-                return null;
-            }
-            finally {
-                javaScriptRunning_.set(javaScriptAlreadyRunning);
-            }
-        }
-
-        protected abstract Object doRun(final Context cx);
-
-        protected abstract String getSourceCode(final Context cx);
-    }
-
-    private void doProcessPostponedActions() {
-        holdPostponedActions_ = false;
-
-        try {
-            getWebClient().loadDownloadedResponses();
-        }
-        catch (final RuntimeException e) {
-            throw e;
-        }
-        catch (final Exception e) {
-            throw new RuntimeException(e);
-        }
-
-        final List<PostponedAction> actions = postponedActions_.get();
-        if (actions != null) {
-            postponedActions_.set(null);
-            try {
-                for (final PostponedAction action : actions) {
-                    if (LOG.isDebugEnabled()) {
-                        LOG.debug("Processing PostponedAction " + action);
-                    }
-
-                    // verify that the page that registered this PostponedAction is \
                still alive
-                    if (action.isStillAlive()) {
-                        action.execute();
-                    }
-                }
-            }
-            catch (final Exception e) {
-                Context.throwAsScriptRuntimeEx(e);
-            }
-        }
-    }
-
-    /**
-     * Adds an action that should be executed first when the script currently being \
                executed has finished.
-     * @param action the action
-     */
-    public void addPostponedAction(final PostponedAction action) {
-        List<PostponedAction> actions = postponedActions_.get();
-        if (actions == null) {
-            actions = new ArrayList<>();
-            postponedActions_.set(actions);
-        }
-        actions.add(action);
-    }
-
-    /**
-     * Handles an exception that occurred during execution of JavaScript code.
-     * @param scriptException the exception
-     * @param triggerOnError if true, this triggers the onerror handler
-     */
-    protected void handleJavaScriptException(final ScriptException scriptException, \
                final boolean triggerOnError) {
-        // Trigger window.onerror, if it has been set.
-        final InteractivePage page = scriptException.getPage();
-        if (triggerOnError && page != null) {
-            final WebWindow window = page.getEnclosingWindow();
-            if (window != null) {
-                final Window w = (Window) window.getScriptObject();
-                if (w != null) {
-                    try {
-                        w.triggerOnError(scriptException);
-                    }
-                    catch (final Exception e) {
-                        handleJavaScriptException(new ScriptException(page, e, \
                null), false);
-                    }
-                }
-            }
-        }
-        final JavaScriptErrorListener javaScriptErrorListener = \
                getWebClient().getJavaScriptErrorListener();
-        if (javaScriptErrorListener != null) {
-            javaScriptErrorListener.scriptException(page, scriptException);
-        }
-        // Throw a Java exception if the user wants us to.
-        if (getWebClient().getOptions().isThrowExceptionOnScriptError()) {
-            throw scriptException;
-        }
-        // Log the error; ScriptException instances provide good debug info.
-        LOG.info("Caught script exception", scriptException);
-    }
-
-    /**
-     * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT \
                YOUR OWN RISK.</span><br>
-     * Indicates that no postponed action should be executed.
-     */
-    public void holdPosponedActions() {
-        holdPostponedActions_ = true;
-    }
-
-    /**
-     * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT \
                YOUR OWN RISK.</span><br>
-     * Process postponed actions, if any.
-     */
-    public void processPostponedActions() {
-        doProcessPostponedActions();
-    }
-
-    /**
-     * Re-initializes transient fields when an object of this type is deserialized.
-     */
-    private void readObject(final ObjectInputStream in) throws IOException, \
                ClassNotFoundException {
-        in.defaultReadObject();
-        initTransientFields();
-    }
-
-    private void initTransientFields() {
-        javaScriptRunning_ = new ThreadLocal<>();
-        postponedActions_ = new ThreadLocal<>();
-        holdPostponedActions_ = false;
-    }
-
-    private static class FallbackCaller extends ScriptableObject {
-
-        @Override
-        public Object get(final String name, final Scriptable start) {
-            if (start instanceof ScriptableWithFallbackGetter) {
-                return ((ScriptableWithFallbackGetter) start).getWithFallback(name);
-            }
-            return NOT_FOUND;
-        }
-
-        @Override
-        public String getClassName() {
-            return "htmlUnitHelper-fallbackCaller";
-        }
-    }
-
-    /**
-     * Gets the class of the JavaScript object for the node class.
-     * @param c the node class {@link DomNode} or some subclass.
-     * @return {@code null} if none found
-     */
-    public Class<? extends HtmlUnitScriptable> getJavaScriptClass(final Class<?> c) \
                {
-        return jsConfig_.getDomJavaScriptMapping().get(c);
-    }
-
-    /**
-     * Gets the associated configuration.
-     * @return the configuration
-     */
-    public JavaScriptConfiguration getJavaScriptConfiguration() {
-        return jsConfig_;
-    }
+    void shutdown();
 }

Added: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/RhinoJavaScriptEngine.java
 ===================================================================
--- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/RhinoJavaScriptEngine.java	 \
                (rev 0)
+++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/RhinoJavaScriptEngine.java	2015-09-28 \
12:26:03 UTC (rev 11315) @@ -0,0 +1,1178 @@
+/*
+ * Copyright (c) 2002-2015 Gargoyle Software Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gargoylesoftware.htmlunit.javascript;
+
+import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_ALLOW_CONST_ASSIGNMENT;
 +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_CONSTRUCTOR;
+import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_DATE_USE_UTC;
+import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_DEFINE_GETTER;
+import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_DONT_ENUM_FUNCTIONS;
 +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_ECMA5_FUNCTIONS;
 +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_FUNCTION_BIND;
 +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_FUNCTION_TOSOURCE;
 +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_IMAGE_PROTOTYPE_SAME_AS_HTML_IMAGE;
 +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INTL;
+import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_Iterator;
+import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OBJECT_WITH_PROTOTYPE_PROPERTY_IN_WINDOW_SCOPE;
 +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OPTION_PROTOTYPE_SAME_AS_HTML_OPTION;
 +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WINDOW_ACTIVEXOBJECT_HIDDEN;
 +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_XML;
+import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.STRING_CONTAINS;
+import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.STRING_TRIM;
+import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.STRING_TRIM_LEFT_RIGHT;
 +
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Stack;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.gargoylesoftware.htmlunit.BrowserVersion;
+import com.gargoylesoftware.htmlunit.InteractivePage;
+import com.gargoylesoftware.htmlunit.Page;
+import com.gargoylesoftware.htmlunit.ScriptException;
+import com.gargoylesoftware.htmlunit.WebAssert;
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.WebWindow;
+import com.gargoylesoftware.htmlunit.html.DomNode;
+import com.gargoylesoftware.htmlunit.html.HtmlDivision;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.javascript.background.BackgroundJavaScriptFactory;
 +import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptExecutor;
+import com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration;
+import com.gargoylesoftware.htmlunit.javascript.configuration.JavaScriptConfiguration;
 +import com.gargoylesoftware.htmlunit.javascript.host.ActiveXObject;
+import com.gargoylesoftware.htmlunit.javascript.host.DateCustom;
+import com.gargoylesoftware.htmlunit.javascript.host.Element;
+import com.gargoylesoftware.htmlunit.javascript.host.StringCustom;
+import com.gargoylesoftware.htmlunit.javascript.host.Window;
+import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLDocument;
+import com.gargoylesoftware.htmlunit.javascript.host.intl.Intl;
+
+import net.sourceforge.htmlunit.corejs.javascript.BaseFunction;
+import net.sourceforge.htmlunit.corejs.javascript.Context;
+import net.sourceforge.htmlunit.corejs.javascript.ContextAction;
+import net.sourceforge.htmlunit.corejs.javascript.Function;
+import net.sourceforge.htmlunit.corejs.javascript.FunctionObject;
+import net.sourceforge.htmlunit.corejs.javascript.Script;
+import net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime;
+import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
+import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
+import net.sourceforge.htmlunit.corejs.javascript.UniqueTag;
+
+/**
+ * A wrapper for the <a href="http://www.mozilla.org/rhino">Rhino JavaScript \
engine</a> + * that provides browser specific features.<br/>
+ * Like all classes in this package, this class is not intended for direct use and \
may change without notice. + *
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:chen_jun@users.sourceforge.net">Chen Jun</a>
+ * @author David K. Taylor
+ * @author Chris Erskine
+ * @author <a href="mailto:bcurren@esomnie.com">Ben Curren</a>
+ * @author David D. Kilzer
+ * @author Marc Guillemot
+ * @author Daniel Gredler
+ * @author Ahmed Ashour
+ * @author Amit Manjhi
+ * @author Ronald Brill
+ * @author Frank Danek
+ * @see <a href="http://groups-beta.google.com/group/netscape.public.mozilla.jseng/browse_thread/thread/b4edac57329cf49f/069e9307ec89111f">
 + * Rhino and Java Browser</a>
+ */
+public class RhinoJavaScriptEngine implements JavaScriptEngine {
+
+    private static final Log LOG = LogFactory.getLog(RhinoJavaScriptEngine.class);
+
+    private final WebClient webClient_;
+    private final HtmlUnitContextFactory contextFactory_;
+    private final JavaScriptConfiguration jsConfig_;
+
+    private transient ThreadLocal<Boolean> javaScriptRunning_;
+    private transient ThreadLocal<List<PostponedAction>> postponedActions_;
+    private transient boolean holdPostponedActions_;
+
+    /** The JavaScriptExecutor corresponding to all windows of this Web client */
+    private transient JavaScriptExecutor javaScriptExecutor_;
+
+    /**
+     * Key used to place the scope in which the execution of some JavaScript code
+     * started as thread local attribute in current context.<br/>
+     * This is needed to resolve some relative locations relatively to the page
+     * in which the script is executed and not to the page which location is \
changed. +     */
+    public static final String KEY_STARTING_SCOPE = "startingScope";
+
+    /**
+     * Key used to place the {@link InteractivePage} for which the JavaScript code \
is executed +     * as thread local attribute in current context.
+     */
+    public static final String KEY_STARTING_PAGE = "startingPage";
+
+    /**
+     * Creates an instance for the specified {@link WebClient}.
+     *
+     * @param webClient the client that will own this engine
+     */
+    public RhinoJavaScriptEngine(final WebClient webClient) {
+        webClient_ = webClient;
+        contextFactory_ = new HtmlUnitContextFactory(webClient);
+        initTransientFields();
+        jsConfig_ = \
JavaScriptConfiguration.getInstance(webClient.getBrowserVersion()); +    }
+
+    /**
+     * Returns the web client that this engine is associated with.
+     * @return the web client
+     */
+    public final WebClient getWebClient() {
+        return webClient_;
+    }
+
+    /**
+     * Returns this JavaScript engine's Rhino {@link \
net.sourceforge.htmlunit.corejs.javascript.ContextFactory}. +     * @return this \
JavaScript engine's Rhino {@link \
net.sourceforge.htmlunit.corejs.javascript.ContextFactory} +     */
+    public HtmlUnitContextFactory getContextFactory() {
+        return contextFactory_;
+    }
+
+    /**
+     * Performs initialization for the given webWindow.
+     * @param webWindow the web window to initialize for
+     */
+    public void initialize(final WebWindow webWindow) {
+        WebAssert.notNull("webWindow", webWindow);
+
+        final ContextAction action = new ContextAction() {
+            @Override
+            public Object run(final Context cx) {
+                try {
+                    init(webWindow, cx);
+                }
+                catch (final Exception e) {
+                    LOG.error("Exception while initializing JavaScript for the \
page", e); +                    throw new ScriptException(null, e); // BUG: null is \
not useful. +                }
+
+                return null;
+            }
+        };
+
+        getContextFactory().call(action);
+    }
+
+    /**
+     * Returns the JavaScriptExecutor.
+     * @return the JavaScriptExecutor.
+     */
+    public JavaScriptExecutor getJavaScriptExecutor() {
+        return javaScriptExecutor_;
+    }
+
+    /**
+     * 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 Context context) throws \
Exception { +        final WebClient webClient = webWindow.getWebClient();
+        final BrowserVersion browserVersion = webClient.getBrowserVersion();
+        final Map<Class<? extends HtmlUnitScriptable>, HtmlUnitScriptable> \
prototypes = new HashMap<>(); +        final Map<String, HtmlUnitScriptable> \
prototypesPerJSName = new HashMap<>(); +
+        final Window window = new Window();
+        ((SimpleScriptable) window).setClassName("Window");
+        context.initStandardObjects(window);
+
+        if (browserVersion.hasFeature(JS_CONSTRUCTOR)) {
+            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(browserVersion, window, window, new Window());
+            }
+        }
+        else {
+            deleteProperties(window, "constructor");
+        }
+
+        // remove some objects, that Rhino defines in top scope but that we don't \
want +        deleteProperties(window, "java", "javax", "org", "com", "edu", "net",
+                "JavaAdapter", "JavaImporter", "Continuation", "Packages", \
"getClass"); +        if (!browserVersion.hasFeature(JS_XML)) {
+            deleteProperties(window, "XML", "XMLList", "Namespace", "QName");
+        }
+
+        if (!browserVersion.hasFeature(JS_Iterator)) {
+            deleteProperties(window, "Iterator", "StopIteration");
+        }
+
+        if (browserVersion.hasFeature(JS_INTL)) {
+            final Intl intl = new Intl();
+            intl.setParentScope(window);
+            window.defineProperty(intl.getClassName(), intl, \
ScriptableObject.DONTENUM); +            intl.defineProperties(browserVersion);
+        }
+
+        // put custom object to be called as very last prototype to call the \
fallback getter (if any) +        final Scriptable fallbackCaller = new \
FallbackCaller(); +        \
ScriptableObject.getObjectPrototype(window).setPrototype(fallbackCaller); +
+        final boolean putPrototypeInWindowScope =
+                browserVersion.hasFeature(JS_OBJECT_WITH_PROTOTYPE_PROPERTY_IN_WINDOW_SCOPE);
 +        for (final ClassConfiguration config : jsConfig_.getAll()) {
+            final boolean isWindow = \
Window.class.getName().equals(config.getHostClass().getName()); +            if \
(isWindow) { +                configureConstantsPropertiesAndFunctions(config, \
window, browserVersion); +
+                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
+                    if (putPrototypeInWindowScope) {
+                        final HtmlUnitScriptable obj = \
config.getHostClass().newInstance(); +                        \
prototype.defineProperty("__proto__", prototype, ScriptableObject.DONTENUM); +        \
obj.defineProperty("prototype", prototype, ScriptableObject.DONTENUM); // but not \
setPrototype! +                        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); +
+                        if (obj.getClass() == Element.class) {
+                            final Page page = webWindow.getEnclosedPage();
+                            if (page != null && page.isHtmlPage()) {
+                                final DomNode domNode = new HtmlDivision("", \
(HtmlPage) page, null); +                                ((SimpleScriptable) \
obj).setDomNode(domNode); +                            }
+                        }
+                    }
+                }
+                prototypes.put(config.getHostClass(), prototype);
+                prototypesPerJSName.put(config.getClassName(), prototype);
+            }
+        }
+
+        for (final ClassConfiguration config : jsConfig_.getAll()) {
+            final Member jsConstructor = config.getJsConstructor();
+            final String jsClassName = config.getClassName();
+            Scriptable prototype = prototypesPerJSName.get(jsClassName);
+            final String hostClassSimpleName = \
config.getHostClass().getSimpleName(); +            if \
("Image".equals(hostClassSimpleName) +                    && \
browserVersion.hasFeature(JS_IMAGE_PROTOTYPE_SAME_AS_HTML_IMAGE)) { +                \
prototype = prototypesPerJSName.get("HTMLImageElement"); +            }
+            if ("Option".equals(hostClassSimpleName)
+                    && \
browserVersion.hasFeature(JS_OPTION_PROTOTYPE_SAME_AS_HTML_OPTION)) { +               \
prototype = prototypesPerJSName.get("HTMLOptionElement"); +            }
+
+            switch (hostClassSimpleName) {
+                case "WebKitAnimationEvent":
+                    prototype = prototypesPerJSName.get("AnimationEvent");
+                    break;
+
+                case "WebKitMutationObserver":
+                    prototype = prototypesPerJSName.get("MutationObserver");
+                    break;
+
+                case "WebKitTransitionEvent":
+                    prototype = prototypesPerJSName.get("TransitionEvent");
+                    break;
+
+                case "webkitAudioContext":
+                    prototype = prototypesPerJSName.get("AudioContext");
+                    break;
+
+                case "webkitIDBCursor":
+                    prototype = prototypesPerJSName.get("IDBCursor");
+                    break;
+
+                case "webkitIDBDatabase":
+                    prototype = prototypesPerJSName.get("IDBDatabase");
+                    break;
+
+                case "webkitIDBFactory":
+                    prototype = prototypesPerJSName.get("IDBFactory");
+                    break;
+
+                case "webkitIDBIndex":
+                    prototype = prototypesPerJSName.get("IDBIndex");
+                    break;
+
+                case "webkitIDBKeyRange":
+                    prototype = prototypesPerJSName.get("IDBKeyRange");
+                    break;
+
+                case "webkitIDBObjectStore":
+                    prototype = prototypesPerJSName.get("IDBObjectStore");
+                    break;
+
+                case "webkitIDBRequest":
+                    prototype = prototypesPerJSName.get("IDBRequest");
+                    break;
+
+                case "webkitIDBTransaction":
+                    prototype = prototypesPerJSName.get("IDBTransaction");
+                    break;
+
+                case "webkitOfflineAudioContext":
+                    prototype = prototypesPerJSName.get("OfflineAudioContext");
+                    break;
+
+                case "webkitURL":
+                    prototype = prototypesPerJSName.get("URL");
+                    break;
+
+                default:
+            }
+            if (prototype != null && config.isJsObject()) {
+                if (jsConstructor != null) {
+                    final BaseFunction function;
+                    if ("Window".equals(jsClassName)) {
+                        function = (BaseFunction) \
ScriptableObject.getProperty(window, "constructor"); +                    }
+                    else {
+                        function = new RecursiveFunctionObject(jsClassName, \
jsConstructor, window); +                    }
+
+                    if ("WebKitAnimationEvent".equals(hostClassSimpleName)
+                            || "WebKitMutationObserver".equals(hostClassSimpleName)
+                            || "WebKitTransitionEvent".equals(hostClassSimpleName)
+                            || "webkitAudioContext".equals(hostClassSimpleName)
+                            || "webkitIDBCursor".equals(hostClassSimpleName)
+                            || "webkitIDBDatabase".equals(hostClassSimpleName)
+                            || "webkitIDBFactory".equals(hostClassSimpleName)
+                            || "webkitIDBIndex".equals(hostClassSimpleName)
+                            || "webkitIDBKeyRange".equals(hostClassSimpleName)
+                            || "webkitIDBObjectStore".equals(hostClassSimpleName)
+                            || "webkitIDBRequest".equals(hostClassSimpleName)
+                            || "webkitIDBTransaction".equals(hostClassSimpleName)
+                            || \
"webkitOfflineAudioContext".equals(hostClassSimpleName) +                            \
|| "webkitOfflineAudioContext".equals(hostClassSimpleName) +                          \
|| "webkitURL".equals(hostClassSimpleName) +                            || \
"Image".equals(hostClassSimpleName) +                            || \
"Option".equals(hostClassSimpleName)) { +                        final Object \
prototypeProperty = ScriptableObject.getProperty(window, prototype.getClassName()); +
+                        if (function instanceof FunctionObject) {
+                            ((FunctionObject) function).addAsConstructor(window, \
prototype); +                        }
+
+                        ScriptableObject.defineProperty(window, hostClassSimpleName, \
function, +                                ScriptableObject.DONTENUM);
+
+                        // the prototype class name is set as a side effect of \
functionObject.addAsConstructor +                        // 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) {
+                            ((FunctionObject) function).addAsConstructor(window, \
prototype); +                        }
+                    }
+
+                    configureConstants(config, function);
+                    configureStaticFunctions(config, function);
+                    configureStaticProperties(config, browserVersion, function);
+                }
+                else {
+                    if (browserVersion.hasFeature(JS_CONSTRUCTOR)) {
+                        final ScriptableObject constructor;
+                        if ("Window".equals(jsClassName)) {
+                            constructor = (ScriptableObject) \
ScriptableObject.getProperty(window, "constructor"); +                        }
+                        else {
+                            constructor = config.getHostClass().newInstance();
+                            ((SimpleScriptable) \
constructor).setClassName(config.getClassName()); +                        }
+                        defineConstructor(browserVersion, window, prototype, \
constructor); +                        configureConstants(config, constructor);
+                    }
+                    else {
+                        if (!"Window".equals(jsClassName)) {
+                            final ScriptableObject constructor = \
config.getHostClass().newInstance(); +                            \
constructor.setParentScope(window); +                            \
window.defineProperty(constructor.getClassName(), constructor, \
ScriptableObject.DONTENUM); +                        }
+
+                        deleteProperties(prototype, "constructor");
+                    }
+                }
+            }
+        }
+        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, \
HtmlUnitScriptable> entry : prototypesPerJSName.entrySet()) { +            final \
String name = entry.getKey(); +            final ClassConfiguration config = \
jsConfig_.getClassConfiguration(name); +            Scriptable prototype = \
entry.getValue(); +            if (prototype.getPrototype() != null) {
+                prototype = prototype.getPrototype(); // "double prototype" hack for \
FF +            }
+            if (!StringUtils.isEmpty(config.getExtendedClassName())) {
+                final Scriptable parentPrototype = \
prototypesPerJSName.get(config.getExtendedClassName()); +                \
prototype.setPrototype(parentPrototype); +            }
+            else {
+                prototype.setPrototype(objectPrototype);
+            }
+        }
+
+        // IE11 ActiveXObject simulation
+        // see http://msdn.microsoft.com/en-us/library/ie/dn423948%28v=vs.85%29.aspx
+        // DEV Note: this is at the moment the only usage of HiddenFunctionObject
+        //           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); +                functionObject.addAsConstructor(window, \
prototype); +            }
+        }
+
+        // Rhino defines too much methods for us, particularly since implementation \
of ECMAScript5 +        removePrototypeProperties(window, "String", "equals", \
"equalsIgnoreCase"); +        if (!browserVersion.hasFeature(STRING_TRIM)) {
+            removePrototypeProperties(window, "String", "trim");
+        }
+        if (!browserVersion.hasFeature(STRING_TRIM_LEFT_RIGHT)) {
+            removePrototypeProperties(window, "String", "trimLeft");
+            removePrototypeProperties(window, "String", "trimRight");
+        }
+        if (browserVersion.hasFeature(STRING_CONTAINS)) {
+            final ScriptableObject stringPrototype =
+                (ScriptableObject) ScriptableObject.getClassPrototype(window, \
"String"); +            stringPrototype.defineFunctionProperties(new String[] \
{"contains"}, +                StringCustom.class, ScriptableObject.EMPTY);
+        }
+
+        if (!browserVersion.hasFeature(JS_FUNCTION_BIND)) {
+            removePrototypeProperties(window, "Function", "bind");
+        }
+        if (!browserVersion.hasFeature(JS_ECMA5_FUNCTIONS)) {
+            removePrototypeProperties(window, "Date", "toISOString", "toJSON");
+        }
+
+        if (!browserVersion.hasFeature(JS_DEFINE_GETTER)) {
+            removePrototypeProperties(window, "Object", "__defineGetter__", \
"__defineSetter__", "__lookupGetter__", +                    "__lookupSetter__");
+        }
+
+        // only FF has toSource
+        if (!browserVersion.hasFeature(JS_FUNCTION_TOSOURCE)) {
+            deleteProperties(window, "uneval");
+            removePrototypeProperties(window, "Object", "toSource");
+            removePrototypeProperties(window, "Array", "toSource");
+            removePrototypeProperties(window, "Date", "toSource");
+            removePrototypeProperties(window, "Function", "toSource");
+            removePrototypeProperties(window, "Number", "toSource");
+            removePrototypeProperties(window, "String", "toSource");
+        }
+        deleteProperties(window, "isXMLName");
+
+        NativeFunctionToStringFunction.installFix(window, \
webClient.getBrowserVersion()); +
+        if (browserVersion.hasFeature(JS_ALLOW_CONST_ASSIGNMENT)) {
+            makeConstWritable(window, "undefined", "NaN", "Infinity");
+        }
+
+        final ScriptableObject datePrototype = (ScriptableObject) \
ScriptableObject.getClassPrototype(window, "Date"); +        \
datePrototype.defineFunctionProperties(new String[] {"toLocaleDateString", \
"toLocaleTimeString"}, +                DateCustom.class, ScriptableObject.DONTENUM);
+
+        if (browserVersion.hasFeature(JS_DATE_USE_UTC)) {
+            datePrototype.defineFunctionProperties(new String[] {"toUTCString"},
+                    DateCustom.class, ScriptableObject.DONTENUM);
+        }
+
+        window.setPrototypes(prototypes, prototypesPerJSName);
+        window.initialize(webWindow);
+    }
+
+    private void defineConstructor(final BrowserVersion browserVersion, final Window \
window, +            final Scriptable prototype, final ScriptableObject constructor) \
{ +        constructor.setParentScope(window);
+        final Object constructorValue = browserVersion.hasFeature(JS_CONSTRUCTOR) ? \
constructor : null; +        ScriptableObject.defineProperty(prototype, \
"constructor", constructorValue, +                ScriptableObject.DONTENUM  | \
ScriptableObject.PERMANENT | ScriptableObject.READONLY); +        \
ScriptableObject.defineProperty(constructor, "prototype", prototype, +                \
ScriptableObject.DONTENUM  | ScriptableObject.PERMANENT | ScriptableObject.READONLY); \
+        window.defineProperty(constructor.getClassName(), constructor, \
ScriptableObject.DONTENUM); +    }
+
+    private void makeConstWritable(final ScriptableObject scope, final String... \
constNames) { +        for (final String name : constNames) {
+            final Object value = ScriptableObject.getProperty(scope, name);
+            ScriptableObject.defineProperty(scope, name, value,
+                    ScriptableObject.DONTENUM | ScriptableObject.PERMANENT);
+        }
+    }
+
+    /**
+     * Deletes the properties with the provided names.
+     * @param scope the scope from which properties have to be removed
+     * @param propertiesToDelete the list of property names
+     */
+    private void deleteProperties(final Scriptable scope, final String... \
propertiesToDelete) { +        for (final String property : propertiesToDelete) {
+            scope.delete(property);
+        }
+    }
+
+    /**
+     * Define properties in Standards Mode.
+     *
+     * @param page the page
+     */
+    public void definePropertiesInStandardsMode(final HtmlPage page) {
+        final Window window = ((HTMLDocument) page.getScriptObject()).getWindow();
+        final BrowserVersion browserVersion = window.getBrowserVersion();
+        for (final ClassConfiguration config : jsConfig_.getAll()) {
+            final String jsClassName = config.getClassName();
+            if (config.isDefinedInStandardsMode()) {
+                final Scriptable prototype = window.getPrototype(jsClassName);
+                if ("Window".equals(jsClassName)) {
+                    defineConstructor(browserVersion, window, window, new Window());
+                }
+                else if (!config.isJsObject()) {
+                    try {
+                        final ScriptableObject constructor = \
config.getHostClass().newInstance(); +                        \
defineConstructor(browserVersion, window, prototype, constructor); +                  \
} +                    catch (final Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes prototype properties.
+     * @param scope the scope
+     * @param className the class for which properties should be removed
+     * @param properties the properties to remove
+     */
+    private void removePrototypeProperties(final Scriptable scope, final String \
className, +            final String... properties) {
+        final ScriptableObject prototype = (ScriptableObject) \
ScriptableObject.getClassPrototype(scope, className); +        for (final String \
property : properties) { +            prototype.delete(property);
+        }
+    }
+
+    /**
+     * Configures the specified class for access via JavaScript.
+     * @param config the configuration settings for the class to be configured
+     * @param window the scope within which to configure the class
+     * @param browserVersion the browser version
+     * @throws InstantiationException if the new class cannot be instantiated
+     * @throws IllegalAccessException if we don't have access to create the new \
instance +     * @return the created prototype
+     */
+    public static HtmlUnitScriptable configureClass(final ClassConfiguration config, \
final Scriptable window, +            final BrowserVersion browserVersion)
+        throws InstantiationException, IllegalAccessException {
+
+        final HtmlUnitScriptable prototype = config.getHostClass().newInstance();

@@ Diff output truncated at 100000 characters. @@

------------------------------------------------------------------------------
_______________________________________________
HtmlUnit-develop mailing list
HtmlUnit-develop@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/htmlunit-develop


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic