Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3622d79
Merge pull request #113 from java2script/master
BobHanson Sep 23, 2019
e3c90f8
Integer.TYPE does not include isArray$() or isPrimitive$()
Sep 24, 2019
9f7ae09
root may be null
Sep 24, 2019
ed91e5f
JTabbedPane tab look and feel not so tall
Sep 24, 2019
47e0caa
JAXB code cleanup; JSSAXParser fix for top-level-only "parsing"
Sep 25, 2019
0671858
fixes missing org.w3c.Node.getTextContent() implementation in
Sep 30, 2019
aae9e15
JTabbedPane addNotify for tab components should check for null
Oct 1, 2019
e76fa51
Merge pull request #114 from BobHanson/hanson1
BobHanson Oct 1, 2019
cf4c362
a2s TextListener not returning correct event; probably needs to be fixed
Oct 4, 2019
5e4e930
BufferedImage needs flush() if using graphics after getting a pixel and
Oct 4, 2019
4210f9d
j2sComboBox must set class swingjs-ui for button; close delay is a bit
Oct 4, 2019
52de9f0
JSGraphics2D should not unset alpha composite if color alpha is 0xFF
Oct 4, 2019
32829e3
too early check of domnode
Oct 4, 2019
83db70d
key release in Java comes after the update
Oct 4, 2019
c3e7d99
SwingJS-site.zip update
Oct 4, 2019
6f05001
fix for JApplet.setLocationRelativeTo
Oct 6, 2019
1438e7c
fix for JSFrameUI.getEmbedded
Oct 6, 2019
3cef167
missing JSGraphics2D method for drawing image with transparent pixel
Oct 6, 2019
5b36511
fix for jquery object could be null in JSPopupMenu
Oct 6, 2019
93b5ccb
fixing exact height sizing for AWT peer Label, TextArea, and TextField
Oct 6, 2019
ebf89b5
new SwingJS-site.zip (Wuppertal and Dundee)
Oct 6, 2019
2ffe0ed
debug comments out
Oct 13, 2019
32b64ca
More detail about how java2script/SwingJS works for developers of
Oct 13, 2019
677f72a
SwingJS-site update
Oct 13, 2019
0f48c0c
Merge pull request #115 from BobHanson/hanson1
BobHanson Oct 13, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
Binary file modified sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion sources/net.sf.j2s.core/dist/swingjs/timestamp
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20190923090813
20191008173421
Binary file modified sources/net.sf.j2s.core/dist/swingjs/ver/3.2.4/SwingJS-site.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion sources/net.sf.j2s.core/dist/swingjs/ver/3.2.4/timestamp
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20190923090813
20191008173421
65 changes: 62 additions & 3 deletions sources/net.sf.j2s.core/doc/howItWorks.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
Java2Script: How It Works
***Java2Script: How It Works***

**java2script/SwingJS**

The full java2script/SwingJS operation involves two parts: Creating the JavaScript from the abstract syntax tree (java2script), and running that within the browser (SwingJS). Both are discussed below.

The code for these two parts are well-separated:

net.sf.j2s.core java2script transpiler
net.sf.j2s.java.core SwingJS runtime

[Note: You may notice that the java2script project includes several other net.sf.... projects. Frankly, I have no idea what they are for. My guess is that they don't work. I think perhaps they were early attempts to get all this working within Eclipse at runtime, with "hot" connections to code. But that never ever worked for me, and what we have now -- direct creation of a site directory that can be debugged in a standard external browser is way better, anyway. I have left them there just because I haven't taken the time to get rid of them.]

**java2script transpiler**

[Note: Changes in java2script should be necessary only when core Java syntax changes or is supplemented in the core Java. For example, Java 8 allows switch cases that are String constants, while Java 6 does not. When we went to Java 8, we had to modify Java2ScriptVisitor.java to account for that. If ever there is a need to fix something that the java2script compiler is doing wrong or to adapt to new Java syntax, as for Java 11, look in net.sf.j2s.core.Java2ScriptVisitor.]

A compiler converts code in one computer language to another. Typically this is from a higher-level language to a lower-level "machine code" language. In the case of the Java compiler, this is from written Java code (*.java) to "Java byte code" (*.class). In the case of of java2script, this is from Java to JavaScript. There are two basic requirements of a compiler: reading and writing. The reading process involves converting the written Java code to an <i>abstract syntax tree</i> [https://en.wikipedia.org/wiki/Abstract_syntax_tree]. The writing process involves scanning that tree, creating one or more output files from the original input file.

Expand All @@ -25,9 +39,54 @@ So this is pretty straightforward. All the output that is ultimately saved in *.

etc.

If ever there is a need to fix something that the java2script compiler is doing wrong or to adapt to new Java syntax, as for Java 11, look in net.sf.j2s.core.Java2ScriptVisitor. There is great documentation on all of these org.eclipse.jdt.core.dom.ASTNode subclasses.
[Note that a big difference between Java and JavaScript is that JavaScript functions cannot be "overloaded", meaning the two calls in JavaScript:

write(b)
write(b, 2, 3)

will both point to the same function. A major task of the java2script transpiler is to sort this out before it becomes an issue at runtime. It does this by creating signature-specific function names in JavaScript, such as write$B and write$B$I$I.]


**Creating a New Transpiler**

The transpiler is created in Eclipse by checking out the net.sf.j2s.core project from GitHub as a standard Java project and adjusting the code as necessary. When it is desired to create the transpiler (net.sf.j2s.core.jar):

1) Use File...Export...Deployable plug-ins and fragments
(if you do not see this option, check that you are using Eclipse
Enterprise)
2) Choose net.sf.j2s.core (Version 3.2.4), check the directory,
and press finish.
3) Copy this file to the drop-ins directory, restart Eclipse,
and test.
4) Copy this file to the project dist/swingjs folder and also
to the swingjs/ver/3.2.4 folder (or appropriate).

I do this with a DOS batch file, which also adds a timestamp.

That's it. I advise to NOT change the version number. I know, this
sounds stupid, but if you change that number, installation in Eclipse requires starting Eclipse with a -clean as the first option. https://www.eclipsezone.com//eclipse/forums/t61566.html
This is pain. If you do not do this clean build, Eclipse just
ignores your drop-in.

The dist directory also includes SwingJS-site.zip, created from the net.sf.j2s.core.java project.


**SwingJS runtime maintenance**

[Note: As of 10/2019, SwingJS is still a collection of Java code from a variety of sources. There is some original Apache Java code from before 2016, and there is code that is a mix of Java6 and Java8. Some of the core java.lang classes are created in j2sClazz.js directly, disregarding the class files in src. I realize this makes maintenance challenging, but that is the way it is. It's a volunteer operation....]

As Java evolves, new packages, classes, and methods are added. Some classes are deprecated and perhaps even removed. For example, the java.util.stream package was added in Java 8, and along with that, several core java.lang classes and interfaces (such as java.lang.String) were augmented to include stream-based methods. There have also been a number of cases where generic classes have been converted to typed classes. For example, staring in Java 7, javax.swing.JComboBox became javax.swing.JComboBox<E>. To date, this has not been an issue. (Particularly in the area of generics, java2script uses an aliasing scheme to refer to the same method by different names so that code from different Java versions still runs appropriately. -- For example, java.util.Calendar.compareTo is aliased as

compareTo$java\_util\_Calendar, compareTo$, and compareTo$TT

Java 11 makes a huge leap in the handling of String and char. SwingJS will have to be maintained to keep up with these changes.

The important thing here is to maintain backward compatibility at all times. It is critical that any changes to SwingJS do not break the running of code from older versions of Java. We do not have the luxury in SwingJS of packaging code with its own JRE (other than the obvious fact that you can put whatever you want into site/swingjs/j2s on your own web site).

So, basically, you can add to or modify any of the several thousand classes in j2s.net.sf.java.core/src. Just be careful to allow for what is already there to still run. Adding a new class can be a challenge. Note that we have not implemented serialization or accessibility. This was a design decision based on need. We needed applet code to run, and these two features added far too much complexity to the task. So we ignored them. (Serialization, in particular, is probably not ever going to work in JavaScript, because the java2script transpiler does not preserve enough information about variable types to make that work properly.)


Bob Hanson 2019.06.07.
Bob Hanson 2019.10.13



Binary file modified sources/net.sf.j2s.java.core/dist/SwingJS-site.zip
Binary file not shown.
30 changes: 15 additions & 15 deletions sources/net.sf.j2s.java.core/src/java/awt/CardLayout.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,21 +109,21 @@ public Card(String cardName, Component cardComponent) {
*/
int vgap;

/**
* @serialField tab Hashtable
* deprectated, for forward compatibility only
* @serialField hgap int
* @serialField vgap int
* @serialField vector Vector
* @serialField currentCard int
*/
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("tab", Hashtable.class),
new ObjectStreamField("hgap", Integer.TYPE),
new ObjectStreamField("vgap", Integer.TYPE),
new ObjectStreamField("vector", Vector.class),
new ObjectStreamField("currentCard", Integer.TYPE)
};
// /**
// * @serialField tab Hashtable
// * deprectated, for forward compatibility only
// * @serialField hgap int
// * @serialField vgap int
// * @serialField vector Vector
// * @serialField currentCard int
// */
// private static final ObjectStreamField[] serialPersistentFields = {
// new ObjectStreamField("tab", Hashtable.class),
// new ObjectStreamField("hgap", Integer.TYPE),
// new ObjectStreamField("vgap", Integer.TYPE),
// new ObjectStreamField("vector", Vector.class),
// new ObjectStreamField("currentCard", Integer.TYPE)
// };

/**
* Creates a new card layout with gaps of size zero.
Expand Down
139 changes: 67 additions & 72 deletions sources/net.sf.j2s.java.core/src/java/awt/Window.java
Original file line number Diff line number Diff line change
Expand Up @@ -3045,81 +3045,76 @@ void resetGC() {
// }
}

/**
* Sets the location of the window relative to the specified
* component.
* <p>
* If the component is not currently showing, or <code>c</code>
* is <code>null</code>, the window is placed at the center of
* the screen. The center point can be determined with {@link
* GraphicsEnvironment#getCenterPoint GraphicsEnvironment.getCenterPoint}
* <p>
* If the bottom of the component is offscreen, the window is
* placed to the side of the <code>Component</code> that is
* closest to the center of the screen. So if the <code>Component</code>
* is on the right part of the screen, the <code>Window</code>
* is placed to its left, and vice versa.
*
* @param c the component in relation to which the window's location
* is determined
* @see java.awt.GraphicsEnvironment#getCenterPoint
* @since 1.4
*/
public void setLocationRelativeTo(Component c) {
Container root=null;

if (c != null) {
if (c.isWindowOrJSApplet()) {
root = (Container)c;
} else {
Container parent;
for(parent = c.getParent() ; parent != null ; parent = parent.getParent()) {
if (parent.isWindowOrJSApplet()) {
root = parent;
break;
}
}
}
}

if((c != null && !c.isShowing()) || root == null ||
!root.isShowing()) {
Dimension paneSize = getSize();
/**
* Sets the location of the window relative to the specified component.
* <p>
* If the component is not currently showing, or <code>c</code> is
* <code>null</code>, the window is placed at the center of the screen. The
* center point can be determined with {@link GraphicsEnvironment#getCenterPoint
* GraphicsEnvironment.getCenterPoint}
* <p>
* If the bottom of the component is offscreen, the window is placed to the side
* of the <code>Component</code> that is closest to the center of the screen. So
* if the <code>Component</code> is on the right part of the screen, the
* <code>Window</code> is placed to its left, and vice versa.
*
* @param c the component in relation to which the window's location is
* determined
* @see java.awt.GraphicsEnvironment#getCenterPoint
* @since 1.4
*/
public void setLocationRelativeTo(Component c) {
Container root = null;

if (c != null) {
if (c.isWindowOrJSApplet()) {
root = (Container) c;
} else {
Container parent;
for (parent = c.getParent(); parent != null; parent = parent.getParent()) {
if (parent.isWindowOrJSApplet()) {
root = parent;
break;
}
}
}
}

Point centerPoint = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
setLocation(centerPoint.x - paneSize.width / 2,
centerPoint.y - paneSize.height / 2);
} else {
Dimension invokerSize = c.getSize();
Point invokerScreenLocation = c.getLocationOnScreen();

Rectangle windowBounds = getBounds();
int dx = invokerScreenLocation.x+((invokerSize.width-windowBounds.width)>>1);
int dy = invokerScreenLocation.y+((invokerSize.height - windowBounds.height)>>1);
Rectangle ss = root.getGraphicsConfiguration().getBounds();

// Adjust for bottom edge being offscreen
if (dy+windowBounds.height>ss.y+ss.height) {
dy = ss.y + ss.height-windowBounds.height;
if (invokerScreenLocation.x - ss.x + invokerSize.width / 2 <
ss.width / 2) {
dx = invokerScreenLocation.x+invokerSize.width;
}
else {
dx = invokerScreenLocation.x-windowBounds.width;
}
}
if ((c != null && !c.isShowing()) || root == null || !root.isShowing()) {
Dimension paneSize = getSize();
Point centerPoint = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
setLocation(centerPoint.x - paneSize.width / 2, centerPoint.y - paneSize.height / 2);
} else {
Dimension invokerSize = c.getSize();
Point invokerScreenLocation = c.getLocationOnScreen();

Rectangle windowBounds = getBounds();
int dx = invokerScreenLocation.x + ((invokerSize.width - windowBounds.width) >> 1);
int dy = invokerScreenLocation.y + ((invokerSize.height - windowBounds.height) >> 1);
Rectangle ss = root.getGraphicsConfiguration().getBounds();

// Adjust for bottom edge being offscreen
if (dy + windowBounds.height > ss.y + ss.height) {
dy = ss.y + ss.height - windowBounds.height;
if (invokerScreenLocation.x - ss.x + invokerSize.width / 2 < ss.width / 2) {
dx = invokerScreenLocation.x + invokerSize.width;
} else {
dx = invokerScreenLocation.x - windowBounds.width;
}
}

// Avoid being placed off the edge of the screen
if (dx+windowBounds.width > ss.x + ss.width) {
dx = ss.x + ss.width - windowBounds.width;
}
if (dx < ss.x) dx = ss.x;
if (dy < ss.y) dy = ss.y;
// Avoid being placed off the edge of the screen
if (dx + windowBounds.width > ss.x + ss.width) {
dx = ss.x + ss.width - windowBounds.width;
}
if (dx < ss.x)
dx = ss.x;
if (dy < ss.y)
dy = ss.y;

setLocation(dx, dy);
}
}
setLocation(dx, dy);
}
}

/**
* Overridden from Component. Top-level Windows should not propagate a
Expand Down
20 changes: 17 additions & 3 deletions sources/net.sf.j2s.java.core/src/java/awt/image/BufferedImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -1420,6 +1420,7 @@ public int getTileGridYOffset() {
* @exception <code>ArrayIndexOutOfBoundsException</code> if both
* <code>tileX</code> and <code>tileY</code> are not equal to 0
*/
@Override
public Raster getTile(int tileX, int tileY) {
// SwingJS not implemented
// if (tileX == 0 && tileY == 0) {
Expand All @@ -1436,6 +1437,7 @@ public Raster getTile(int tileX, int tileY) {
* @return a <code>Raster</code> that is a copy of the image data.
* @see #setData(Raster)
*/
@Override
public Raster getData() {

// REMIND : this allocates a whole new tile if raster is a
Expand Down Expand Up @@ -1470,6 +1472,7 @@ public Raster getData() {
* specified region of the <code>BufferedImage</code>
* @see #setData(Raster)
*/
@Override
public Raster getData(Rectangle rect) {
SampleModel sm = raster.getSampleModel();
SampleModel nsm = sm.createCompatibleSampleModel(rect.width, rect.height);
Expand Down Expand Up @@ -1502,6 +1505,7 @@ public Raster getData(Rectangle rect) {
* image, or <code>null</code>
* @return a reference to the supplied or created <code>WritableRaster</code>.
*/
@Override
public WritableRaster copyData(WritableRaster outRaster) {
if (outRaster == null) {
return (WritableRaster) getData();
Expand Down Expand Up @@ -1717,6 +1721,15 @@ public void setPixels() {
秘havePix = true;
}


@Override
public void flush() {
// call this method after drawing to ensure that
// pixels are recreated from the HTML5 canvas
秘pix = null;
秘havePix = false;
// was for surfaceManager only super.flush();
}
/**
* convert [r g b a r g b a ...] into [argb argb argb ...]
*
Expand Down Expand Up @@ -1778,9 +1791,10 @@ public Graphics2D getImageGraphic() {
* pix.img = this;
*
*/
{
}
秘pix = null;

// 秘pix = null;
flush(); // also setting 秘havePix false

}
Graphics2D g2d = (Graphics2D) (Object)秘g;
if (秘component != null) {
Expand Down
Loading