com.sun.javafx.webkit.drt.DumpRenderTree Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openjfx-78-backport Show documentation
Show all versions of openjfx-78-backport Show documentation
This is a backport of OpenJFX 8 to run on Java 7.
The newest version!
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
*/
package com.sun.javafx.webkit.drt;
import com.sun.javafx.application.PlatformImpl;
import com.sun.webkit.BackForwardList;
import com.sun.webkit.Invoker;
import com.sun.webkit.LoadListenerClient;
import com.sun.webkit.PageCache;
import com.sun.webkit.WebPage;
import com.sun.webkit.WebPageClient;
import com.sun.webkit.graphics.WCPageBackBuffer;
import com.sun.webkit.graphics.WCPoint;
import com.sun.webkit.graphics.WCRectangle;
import static com.sun.webkit.network.URLs.newURL;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javafx.scene.web.WebEngine;
public final class DumpRenderTree {
private final static Logger log = Logger.getLogger("DumpRenderTree");
private final static long PID = (new Date()).getTime() & 0xFFFF;
private final static String fileSep = System.getProperty("file.separator");
private static boolean forceDumpAsText = false;
final static PrintWriter out;
static {
try {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
System.out, "UTF-8")), true);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
}
static volatile DumpRenderTree drt;
private final WebPage webPage;
private final UIClientImpl uiClient;
private final EventSender eventSender;
private final CountDownLatch latch;
private final String testPath;
private String pixelsHash = "";
private boolean loaded;
private boolean waiting;
private boolean complete;
// called on FX thread
private DumpRenderTree(String testString, CountDownLatch latch) {
int t = testString.indexOf("'");
if ((t > 0) && (t < testString.length() - 1)) {
pixelsHash = testString.substring(t + 1);
testString = testString.substring(0, t);
}
this.testPath = testString;
this.latch = latch;
drt = this;
uiClient = new UIClientImpl();
webPage = new WebPage(new WebPageClientImpl(), uiClient, null, null,
null, false);
uiClient.setWebPage(webPage);
eventSender = new EventSender(webPage);
webPage.setBounds(0, 0, 800, 600);
webPage.setUsePageCache(true);
webPage.setDeveloperExtrasEnabled(true);
webPage.addLoadListenerClient(new DRTLoadListener());
init(testPath, pixelsHash);
}
// called on FX thread
private void run() {
String file = testPath;
mlog("{runTest: " + file);
long mainFrame = webPage.getMainFrame();
try {
new URL(file);
} catch (MalformedURLException ex) {
file = "file:///" + file;
}
webPage.open(mainFrame, file);
mlog("}runTest");
}
private static boolean isDebug()
{
return log.isLoggable(Level.FINE);
}
private static void mlog(String msg)
{
if (isDebug()) {
log.fine("PID:" + Long.toHexString(PID)
+ " TID:" + Thread.currentThread().getId()
+ "(" + Thread.currentThread().getName() + ") "
+ msg);
}
}
private static void initPlatform() throws Exception {
// initialize default toolkit
final CountDownLatch latch = new CountDownLatch(1);
PlatformImpl.startup(new Runnable() {
public void run() {
new WebEngine(); // initialize Webkit classes
System.loadLibrary("DumpRenderTreeJava");
PageCache.setCapacity(1);
latch.countDown();
}
});
// wait for libraries to load
latch.await();
}
private static void runTest(final String testString) throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
Invoker.getInvoker().invokeOnEventThread(new Runnable() {
public void run() {
new DumpRenderTree(testString, latch).run();
}});
// wait until test is finished
latch.await();
Invoker.getInvoker().invokeOnEventThread(new Runnable() {
public void run() {
mlog("dispose");
drt.uiClient.closePage();
dispose();
}});
}
// called from native
private static void waitUntilDone() {
mlog("waitUntilDone");
drt.setWaiting(true); // TODO: handle timeout
}
// called from native
private static void notifyDone() {
mlog("notifyDone");
drt.setWaiting(false);
}
private synchronized void setLoaded(boolean loaded) {
this.loaded = loaded;
done();
}
private synchronized void setWaiting(boolean waiting) {
this.waiting = waiting;
done();
}
private synchronized void dump(long frame) {
boolean dumpAsText = dumpAsText() || forceDumpAsText;
mlog("dumpAsText = " + dumpAsText);
if (dumpAsText) {
String innerText = webPage.getInnerText(frame);
if (frame == webPage.getMainFrame()) {
if (innerText != null) {
// don't use println() here as it varies from platform
// to platform, but DRT expects it always to be 0x0A
out.print(innerText + '\n');
}
} else {
out.printf("\n--------\nFrame: '%s'\n--------\n%s\n",
webPage.getName(frame), innerText);
}
if (dumpChildFramesAsText()) {
List children = webPage.getChildFrames(frame);
if (children != null) {
for (long child : children) {
dump(child);
}
}
}
if (dumpBackForwardList() && frame == webPage.getMainFrame()) {
drt.dumpBfl();
}
} else {
String renderTree = webPage.getRenderTree(frame);
out.print(renderTree);
}
}
private synchronized void done() {
if (waiting || !loaded || complete) {
return;
}
mlog("dump");
dump(webPage.getMainFrame());
mlog("done");
out.print("#EOF" + '\n');
// TODO: dump pixels here
out.print("#EOF" + '\n');
out.flush();
System.err.print("#EOF" + '\n');
System.err.flush();
complete = true;
// notify main thread that test is finished
this.latch.countDown();
}
private static native void init(String testPath, String pixelsHash);
private static native void didClearWindowObject(long pContext,
long pWindowObject, EventSender eventSender);
private static native void dispose();
private static native boolean dumpAsText();
private static native boolean dumpChildFramesAsText();
private static native boolean dumpBackForwardList();
private final class DRTLoadListener implements LoadListenerClient {
@Override
public void dispatchLoadEvent(long frame, int state,
String url, String contentType,
double progress, int errorCode)
{
mlog("dispatchLoadEvent: ENTER");
if (frame == webPage.getMainFrame()) {
mlog("dispatchLoadEvent: STATE = " + state);
switch (state) {
case PAGE_STARTED:
mlog("PAGE_STARTED");
setLoaded(false);
break;
case PAGE_FINISHED:
mlog("PAGE_FINISHED");
if (didFinishLoad()) {
setLoaded(true);
}
break;
case DOCUMENT_AVAILABLE:
dumpUnloadListeners(webPage, frame);
break;
case LOAD_FAILED:
mlog("LOAD_FAILED");
// safety net: if load fails, e.g. command line
// parameters were bad, let's not hang forever
setLoaded(true);
break;
}
}
mlog("dispatchLoadEvent: EXIT");
}
@Override
public void dispatchResourceLoadEvent(long frame, int state,
String url, String contentType,
double progress, int errorCode)
{
}
}
public static void main(final String[] args) throws Exception {
if ( isDebug() ) {
log.setLevel(Level.FINEST);
FileHandler handler = new FileHandler("drt.log", true);
handler.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return formatMessage(record) + "\n";
}
});
log.addHandler(handler);
}
mlog("{main");
initPlatform();
for (String arg: args) {
if ("--dump-as-text".equals(arg)) {
forceDumpAsText = true;
} else if ("-".equals(arg)) {
// read from stdin
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
String testPath;
while ((testPath = in.readLine()) != null) {
runTest(testPath);
}
in.close();
} else {
runTest(arg);
}
}
PlatformImpl.exit();
mlog("}main");
System.exit(0); // workaround to kill media threads
}
// called from native
private static int getWorkerThreadCount() {
return drt.webPage.getWorkerThreadCount();
}
// called from native
private static String resolveURL(String relativeURL) {
String testDir = new File(drt.testPath).getParentFile().getPath();
File f = new File(testDir, relativeURL);
String url = "file:///" + f.toString().replace(fileSep, "/");
mlog("resolveURL: " + url);
return url;
}
// called from native
private static void loadURL(String url) {
drt.webPage.open(drt.webPage.getMainFrame(), url);
}
// called from native
private static void goBackForward(int dist) {
// TODO: honor the dist
if (dist > 0) {
drt.webPage.goForward();
} else {
drt.webPage.goBack();
}
}
// called from native
private static int getBackForwardItemCount() {
return drt.getBackForwardList().size();
}
private static final String TEST_DIR_NAME = "LayoutTests";
private static final int TEST_DIR_LEN = TEST_DIR_NAME.length();
private static final String CUR_ITEM_STR = "curr->";
private static final int CUR_ITEM_STR_LEN = CUR_ITEM_STR.length();
private static final String INDENT = " ";
private BackForwardList bfl;
private BackForwardList getBackForwardList() {
if (bfl == null) {
bfl = webPage.createBackForwardList();
}
return bfl;
}
private void dumpBfl() {
out.print("\n============== Back Forward List ==============\n");
getBackForwardList();
BackForwardList.Entry curItem = bfl.getCurrentEntry();
for (BackForwardList.Entry e: bfl.toArray()) {
dumpBflItem(e, 2, e == curItem);
}
out.print("===============================================\n");
}
private void dumpBflItem(BackForwardList.Entry item, int indent, boolean isCurrent) {
StringBuilder str = new StringBuilder();
for (int i = indent; i > 0; i--) str.append(INDENT);
if (isCurrent) str.replace(0, CUR_ITEM_STR_LEN, CUR_ITEM_STR);
String url = item.getURL().toString();
if (url.contains("file:/")) {
String subUrl = url.substring(url.indexOf(TEST_DIR_NAME) + TEST_DIR_LEN + 1);
str.append("(file test):" + subUrl);
} else {
str.append(url);
}
if (item.getTarget() != null) {
str.append(" (in frame \"" + item.getTarget() + "\")");
}
if (item.isTargetItem()) {
str.append(" **nav target**\n");
} else {
str.append("\n");
}
out.print(str);
if (item.getChildren() != null)
for (BackForwardList.Entry child: item.getChildren())
dumpBflItem(child, indent + 1, false);
}
void dumpUnloadListeners(WebPage page, long frame) {
if (waiting == true && dumpAsText()) {
String dump = getUnloadListenersDescription(page, frame);
if (dump != null) {
out.print(dump + '\n');
}
}
}
private static String getUnloadListenersDescription(WebPage page, long frame) {
int count = page.getUnloadEventListenersCount(frame);
if (count > 0) {
return getFrameDescription(page, frame) +
" - has " + count + " onunload handler(s)";
}
return null;
}
private static String getFrameDescription(WebPage page, long frame) {
String name = page.getName(frame);
if (frame == page.getMainFrame()) {
return name == null ? "main frame" : "main frame " + name;
}
return name == null ? "frame (anonymous)" : "frame " + name;
}
private native static boolean didFinishLoad();
private final class WebPageClientImpl implements WebPageClient {
@Override
public void setCursor(long cursorID) {
}
@Override
public void setFocus(boolean focus) {
}
@Override
public void transferFocus(boolean forward) {
}
@Override
public void setTooltip(String tooltip) {
}
@Override
public WCRectangle getScreenBounds(boolean available) {
return null;
}
@Override
public int getScreenDepth() {
return 24;
}
@Override
public Void getContainer() {
return null;
}
@Override
public WCPoint screenToWindow(WCPoint ptScreen) {
return ptScreen;
}
@Override
public WCPoint windowToScreen(WCPoint ptWindow) {
return ptWindow;
}
@Override
public WCPageBackBuffer createBackBuffer() {
throw new UnsupportedOperationException();
}
@Override
public boolean isBackBufferSupported() {
return false;
}
@Override
public void addMessageToConsole(String message, int lineNumber,
String sourceId)
{
if (!message.isEmpty()) {
int pos = message.indexOf("file://");
if (pos != -1) {
String s1 = message.substring(0, pos);
String s2 = message.substring(pos);
try {
// Extract the last path component aka file name
s2 = new File(newURL(s2).getPath()).getName();
} catch (MalformedURLException ignore) {}
message = s1 + s2;
}
}
if (lineNumber == 0) {
out.printf("CONSOLE MESSAGE: %s\n", message);
} else {
out.printf("CONSOLE MESSAGE: line %d: %s\n",
lineNumber, message);
}
}
@Override
public void didClearWindowObject(long context, long windowObject) {
mlog("didClearWindowObject");
DumpRenderTree.didClearWindowObject(context, windowObject,
eventSender);
}
}
}