Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
GNU LESSER GENERAL PUBLIC LICENSE
Copyright (C) 2006 The Lobo Project
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Contact info: [email protected]
*/
/*
* Created on Nov 12, 2005
*/
package org.cobraparser.html.js;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Timer;
import org.cobraparser.html.HtmlRendererContext;
import org.cobraparser.html.domimpl.CanvasPath2D;
import org.cobraparser.html.domimpl.CommentImpl;
import org.cobraparser.html.domimpl.HTMLDivElementImpl;
import org.cobraparser.html.domimpl.HTMLDocumentImpl;
import org.cobraparser.html.domimpl.HTMLElementImpl;
import org.cobraparser.html.domimpl.HTMLIFrameElementImpl;
import org.cobraparser.html.domimpl.HTMLImageElementImpl;
import org.cobraparser.html.domimpl.HTMLOptionElementImpl;
import org.cobraparser.html.domimpl.HTMLScriptElementImpl;
import org.cobraparser.html.domimpl.HTMLSelectElementImpl;
import org.cobraparser.html.domimpl.NodeImpl;
import org.cobraparser.html.domimpl.TextImpl;
import org.cobraparser.js.AbstractScriptableDelegate;
import org.cobraparser.js.HideFromJS;
import org.cobraparser.js.JavaClassWrapper;
import org.cobraparser.js.JavaClassWrapperFactory;
import org.cobraparser.js.JavaInstantiator;
import org.cobraparser.js.JavaObjectWrapper;
import org.cobraparser.js.JavaScript;
import org.cobraparser.ua.UserAgentContext;
import org.cobraparser.ua.UserAgentContext.Request;
import org.cobraparser.ua.UserAgentContext.RequestKind;
import org.cobraparser.util.ID;
import org.mozilla.javascript.ClassShutter;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.css.CSS2Properties;
import org.w3c.dom.events.EventException;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import org.w3c.dom.html.HTMLCollection;
import org.w3c.dom.html.HTMLElement;
import org.w3c.dom.views.AbstractView;
import org.w3c.dom.views.DocumentView;
public class Window extends AbstractScriptableDelegate implements AbstractView, EventTarget {
private static final Storage STORAGE = new Storage();
private static final Logger logger = Logger.getLogger(Window.class.getName());
private static final Map> CONTEXT_WINDOWS = new WeakHashMap<>();
// private static final JavaClassWrapper IMAGE_WRAPPER =
// JavaClassWrapperFactory.getInstance().getClassWrapper(Image.class);
private static final JavaClassWrapper XMLHTTPREQUEST_WRAPPER = JavaClassWrapperFactory.getInstance()
.getClassWrapper(XMLHttpRequest.class);
private static final JavaClassWrapper PATH2D_WRAPPER = JavaClassWrapperFactory.getInstance()
.getClassWrapper(CanvasPath2D.class);
private static final JavaClassWrapper EVENT_WRAPPER = JavaClassWrapperFactory.getInstance()
.getClassWrapper(Event.class);
// Timer ids should begin counting from 1 or more.
// jQuery's ajax polling handler relies on a non-zero value (uses it as a boolean condition)
// Chromium 37 starts counting from 1 while Firefox 32 starts counting from 2 (from developer consoles and plugins installed)
private static int timerIdCounter = 1;
private final HtmlRendererContext rcontext;
private final UserAgentContext uaContext;
private Navigator navigator;
private Screen screen;
private Location location;
private Map taskMap;
private volatile Document document;
// private volatile HTMLDocumentImpl document;
public Window(final HtmlRendererContext rcontext, final UserAgentContext uaContext) {
// TODO: Probably need to create a new Window instance
// for every document. Sharing of Window state between
// different documents is not correct.
this.rcontext = rcontext;
this.uaContext = uaContext;
}
private static int generateTimerID() {
synchronized (logger) {
return timerIdCounter++;
}
}
public HtmlRendererContext getHtmlRendererContext() {
return this.rcontext;
}
public UserAgentContext getUserAgentContext() {
return this.uaContext;
}
private void clearState() {
synchronized (this) {
// windowClosing = true;
if (document instanceof HTMLDocumentImpl) {
((HTMLDocumentImpl) document).stopEverything();
}
jsScheduler.stopAndWindUp(true);
jsScheduler = new JSScheduler(this);
eventTargetManager.reset();
this.onWindowLoadHandler = null;
this.forgetAllTasks();
// Commenting out call to getWindowScope() since that creates a new scope which is wasteful
// if we are going to destroy it anyway.
// final Scriptable s = this.getWindowScope();
final Scriptable s = this.windowScope;
if (s != null) {
final Object[] ids = s.getIds();
for (final Object id : ids) {
if (id instanceof String) {
s.delete((String) id);
} else if (id instanceof Integer) {
s.delete(((Integer) id).intValue());
}
}
}
// This will ensure that a fresh scope will be created by getWindowScope() on the next call
this.windowScope = null;
}
}
@HideFromJS
public void setDocument(final Document document) {
synchronized (this) {
final Document prevDocument = this.document;
if (prevDocument != document) {
final Function onunload = this.onunload;
if (onunload != null) {
final HTMLDocumentImpl oldDoc = (HTMLDocumentImpl) prevDocument;
Executor.executeFunction(this.getWindowScope(), onunload, oldDoc.getDocumentURL(), this.uaContext, windowContextFactory);
this.onunload = null;
}
// TODO: Should clearing of the state be done when window "unloads"?
if (prevDocument != null) {
// Only clearing when the previous document was not null
// because state might have been set on the window before
// the very first document is added.
this.clearState();
}
// this.forgetAllTasks();
this.initWindowScope(document);
jobsOver.set(false);
jsScheduler.start();
this.document = document;
// eventTargetManager.setNode(document);
}
}
}
public DocumentView getDocument() {
return (DocumentView) this.document;
}
public Document getDocumentNode() {
return this.document;
}
private abstract static class JSTask implements Comparable {
protected final int priority;
protected final long creationTime;
protected final String description;
private final AccessControlContext context;
// TODO: Add a context parameter that will be combined with current context, to help with creation of timer tasks
// public JSTask(final int priority, final Runnable runnable) {
public JSTask(final int priority, final String description) {
this.priority = priority;
this.description = description;
this.context = AccessController.getContext();
this.creationTime = System.nanoTime();
}
// TODO: Add a way to stop a task. It should return false if the task can't be stopped in which case a thread kill will be performed by the task scheduler.
// TODO: Sorting by priority
public int compareTo(final JSTask o) {
final long diffCreation = (o.creationTime - creationTime);
if (diffCreation < 0) {
return 1;
} else if (diffCreation == 0) {
return 0;
} else {
return -1;
}
}
public abstract void run();
}
public final static class JSRunnableTask extends JSTask {
private final Runnable runnable;
public JSRunnableTask(final int priority, final Runnable runnable) {
this(priority, "", runnable);
}
public JSRunnableTask(final int priority, final String description, final Runnable runnable) {
super(priority, description);
this.runnable = runnable;
}
@Override
public String toString() {
// return "JSRunnableTask [priority=" + priority + ", runnable=" + runnable + ", creationTime=" + creationTime + "]";
return "JSRunnableTask [priority=" + priority + ", description=" + description + ", creationTime=" + creationTime + "]";
}
@Override
public void run() {
runnable.run();
}
}
public final static class JSSupplierTask extends JSTask {
private final Supplier supplier;
private final Consumer consumer;
public JSSupplierTask(final int priority, final Supplier supplier, final Consumer consumer) {
super(priority, "supplier description TODO");
this.supplier = supplier;
this.consumer = consumer;
}
@Override
public void run() {
final T result = supplier.get();
consumer.accept(result);
}
}
private static final int JS_SCHED_POLL_INTERVAL_MILLIS = 100;
private static final int JS_SCHED_JOIN_INTERVAL_MILLIS = JS_SCHED_POLL_INTERVAL_MILLIS * 2;
private static final class JSScheduler extends Thread {
private static final class ScheduledTask implements Comparable {
final int id;
final JSTask task;
public ScheduledTask(final int id, final JSTask task) {
this.id = id;
this.task = task;
}
public int compareTo(final ScheduledTask other) {
return task.compareTo(other.task);
}
@Override
public boolean equals(final Object o) {
if (o instanceof Integer) {
final Integer oId = (Integer) o;
return oId == id;
}
return false;
}
@Override
public String toString() {
return "Scheduled Task (" + id + ", " + task + ")";
}
}
private final PriorityBlockingQueue jsQueue = new PriorityBlockingQueue<>();
private final AtomicBoolean running = new AtomicBoolean(false);
private volatile boolean windowClosing = false;
// TODO: This is not water tight for one reason, Windows are reused for different documents.
// If they are always freshly created, the taskIdCounter will be more reliable.
private volatile AtomicInteger taskIdCounter = new AtomicInteger(0);
private String name;
public JSScheduler(final Window window) {
super("JS Scheduler");
this.name = "JS Sched " + (window.document == null ? "" : "" + window.document.getBaseURI());
}
@Override
public void run() {
setName(name);
while (!windowClosing) {
try {
ScheduledTask scheduledTask;
// TODO: uncomment if synchronization is necessary with the add methods
// synchronized (this) {
scheduledTask = jsQueue.poll(JS_SCHED_POLL_INTERVAL_MILLIS, TimeUnit.MILLISECONDS);
if (scheduledTask != null) {
final PrivilegedAction