IdCanvas holdRepaint()
[jalview.git] / swingjs / differences.txt
1 Notes
2 =====
3
4 ---IMPORTANT CHARACTER SET NOTE---
5
6 It is critical that all development work in Java2Script 
7 be done in UTF-8. This means:
8
9 - making sure your Eclipse project is set up for UTF-8 (not the Eclipse default?)
10 - making sure your server can serve up UTF-8 by default for any browser-loaded files
11 - making sure you don't edit a Java2Script class file or one of the site .js files
12     using a non-UTF-8 editor. It may replace non-Latin characters with "?" or garbage.
13 - making sure that your web pages are delivered with proper headings indicating HTML5 and UTF-8
14
15 <!DOCTYPE html>
16 <html>
17 <head>
18 <meta charset="utf-8">
19
20 Note that the DOCTYPE tag is critical for some browsers to switch into HTML5 mode. (MSIE?)
21
22
23
24   
25 In particular, the Mandarin character ç§˜ (mi; "secret") is used extensively throughout
26 the SwingJS class files to distinguish j2s-specific fields and methods that must not 
27 ever be shadowed or overridden by subclasses. For example, we see in java.lang.Thread.java:
28
29                 public static JSThread ç§˜thisThread;
30
31 ----------------------------------
32
33
34 updated 3/21/2020 -- adds note about HashMap, Hashtable, and HashSet iterator ordering
35 updated 3/20/2020 -- adds note about interning, new String("xxx"), and "xxx"
36 updated 2/26/2020 -- adds Graphics.setClip issue
37 updated 12/22/19 -- additional issues
38 updated 11/03/19 -- adds information about File.exists() and points to src/javajs/async
39 updated 10/26/19 -- adds information about File.createTempFile()
40 updated 8/16/19 -- minor typos and added summary paragraph
41 updated 7/19/19 -- clarification that AWT and Swing classes are supported directly
42 updated 5/13/19 -- Mandarin U+79D8 reserved character; Missing Math methods; int and long
43 updated 5/10/19 -- adds a section on static issues in multi-(duplicate)-applet pages
44 updated 1/4/19 -- nio
45 updated 9/15/18 -- adds integer 1/0 == Infinity
46 updated 7/24/18 -- most classes replaced with https://github.com/frohoff/jdk8u-jdk
47 updated 6/5/17 -- reserved package name "window"
48 updated 3/11/17 -- myClass.getField
49 updated 3/7/17 -- overloading of JSplitPane.setDividerLocation
50 updated 3/2/17 -- more indication of classes not implemented (KeyListener)
51
52 =============================================================================
53 SwingJS and OpenJDK 8+
54 =============================================================================
55
56 SwingJS implements a wide range of the Java language in JavaScript. The base
57 version for this implementation is OpenJDK8. some classes are implemented using 
58 older source code, and there are some missing methods. For the most part, this is 
59 no real problem. You can add or modify any java class just be adding it as source
60 in your project. Or (preferably) you can contact me, and I can get it into the 
61 distribution. Or (even more preferably) you can do that via a patch submission. 
62
63 =================
64 DESIGN PHILOSOPHY
65 =================
66
67 The java2script/SwingJS design goal is to recreate a recognizable, easily debuggable
68 equivalent in JavaScript for as much of Java as practical. This means, for example, 
69 that one can call in JavaScript 
70
71   new java.util.Hashtable()
72   
73 and for all practical purposes it will appear that Java is running.
74
75
76 Method and Field Disambiguation
77 -------------------------------
78
79 SwingJS has no problem with the overloading of methods, for example:
80
81   public void print(int b);
82   public void print(float b);
83
84 JavaScript does not allow overloading of methods, and the common practice in
85 Java of naming a field the same as a method -- isAllowed and isAllowed() -- is
86 not possible in JavaScript. As a result, SwingJS implements "fully-qualified" 
87 method names using "$" parameter type separation. Thus, these methods in SwingJS
88 will be referred to as print$I and print$F. The rules for this encoding are
89 relatively simple: 
90
91 1. The seven primitive types in Java are encoded $I (int), $L (long), $F (float), 
92 $D (double), $B (byte) $Z (boolean), and $H (short). 
93
94 2. String and Object are encoded as $S and $O, respectively.
95
96 3. "java_lang_" is dropped for all other classes in the java.lang package (as in Java).
97    For example:  $StringBuffer, not $java_lang_StringBuffer
98
99 4. All other classes are encoded as 
100
101  "$" + Class.getName().replace(".","_")
102
103 For example, in Java we see:
104
105   public void equals(Object o) {...}
106
107 Whereas in SwingJS we have:
108
109   Clazz.newMeth(C$, 'equals$O', function (o) {...}
110
111 And 
112
113  this.getContentPane().add(bar, "North");
114
115 becomes
116
117  this.getContentPane$().add$java_awt_Component$O(bar, "North");
118
119 5. Arrays are indicated with appended "A" for each level. So
120
121   setDataVector(Object[][] dataVector, Object[] columnIdentifiers)
122   
123 becomes
124
125   setDataVector$OAA$OA(dataVector, columnIdentifiers)
126
127 (It is recognized that this design does introduce a bit of ambiguity, in that
128  in principal there could be user class named XA and X in the same package,
129  and methods a(X[]) and a(XA) in the same class that cannot be distinguished.
130  The benefit of this simple system, however, triumphed over the unlikelyhood
131  of that scenario.) The transpiler could be set to flag this possibility.
132
133 6. Constructors are prepended with "c$". So 
134
135   public JLabel(String text) {...}
136   
137 becomes:
138
139   Clazz.newMeth(C$, 'c$$S', function (text) {...});
140
141 Field disambiguation involves prepending. In Java, a class and its subclass 
142 can both have the same field name, such as 
143
144  boolean visible;
145  
146 When this happens, it is called "shadowing", and though not recommended, Java allows
147 it. The Java2Script transpiler will prepend such shadowing fields with "$" so that the
148 subclass instance has both "visible" (for use in its methods inherited from its
149 superclass) and "$visible" (for its own methods). Thus, we might see in Java:
150
151   this.visible = super.visible;
152   
153 while in SwingJS we will see:
154
155   this.$visible=this.visible;
156
157 since JavaScript does not have the "super" keyword.
158
159
160
161 Parameterless methods such as toString() are appended with "$" to become toString$().
162 The one exception to this rule is private methods, which are saved in (truly) private 
163 array in the class (and are not accessible by reflection). Private parameterless 
164 methods retain their simple Java name, since they cannot conflict with field names.
165
166 This renaming of methods has a few consequences, which are discussed more fully below.
167 See particularly the section on "qualified field and method names", where it is described
168 how you can use packages or classes or interfaces with ".api.js" in them to represent JavaScript
169 objects for which all method names are to be left unqualified. Note that it is not 
170 possible to cherry-pick methods to be unqualified; only full packages, classes or 
171 interfaces can hold this status.
172
173 The swingjs.api.js package in particular contains a number of useful interfaces that
174 you can import into your project for JavaScript-specific capabilities.
175
176
177 Applet vs. Application
178 ----------------------
179
180 One of the very cool aspects of SwingJS is that it doesn't particularly matter if a browser-based
181 Java app is an "applet" or an "application". We don't need JNLP (Java Network Launch Protocol) 
182 because now we can just start up any Java application in a browser just as easily as any applet.
183 The associative array that passes information to the SwingJS applet (information that formerly
184 might have been part of the APPLET tag, such as width, height, and codebase, always referred to 
185 in our writing as "the Info array") allows the option to specify the JApplet/Applet "code" 
186 class or the application "main" class. Either one will run just fine.
187
188
189 Performance
190 -----------
191
192 Obviously, there are limitations. One is performance, but we have seen reproducible 
193 performance at 1/6 - 1/3 the speed of Java. Achieving this performance may require
194 some refactoring of the Java to make it more efficient in both Java and JavaScript. 
195 "for" loops need to be more carefully crafted; use of "new" and "instanceof" need to be
196 minimized in critical areas. Note that method overloading -- that is, the same method name
197 with different parameters, such as read(int) and read(byte) -- is no longer any problem. 
198   
199
200 Threads
201 -------
202
203 Although there is only a single thread in JavaScript, meaning Thread.wait(), Thread.sleep(int) and 
204 Thread.notify() cannot be reproduced, we have found that this is not a serious limitation. 
205 For example, javax.swing.Timer() works perfectly in JavaScript. All it means is that threads 
206 that use sleep(int) or notify() must be refactored to allow Timer-like callbacks. That is, 
207 they must allow full exit and re-entry of Thread.run(), not the typical while/sleep motif. 
208
209 The key is to create a state-based run() that can be exited and re-entered in JavaScript.
210
211
212 Static fields
213 -------------
214
215 Final static primitive "constant" fields (String, boolean, int, etc.) such as 
216
217 static final int TEST = 3;
218 static final String MY_STRING = "my " + "string";
219
220 are converted to their primitive form automatically by the Eclipse Java compiler 
221 and do not appear in the JavaScript by their names. 
222
223 Other static fields are properties of their class and can be used as expected.
224
225 Note, however, that SwingJS runs all "Java" code on a page in a common "jvm" 
226 (like older versions of Java). So, like the older Java schema, the JavaScript 
227 equivalents of both applets and applications will share all of their static 
228 fields and methods. This includes java.lang.System. 
229
230 Basically, SwingJS implementations of Java run in a browser page-based sandbox 
231 instead of an applet-specific one.
232
233 In general, this is no problem. But if we are to implement pages with 
234 multiple applets present, we must be sure to only have static references 
235 that are "final" or specifically meant to be shared in a JavaScript 
236 environment only (since they will not be shared in Java).
237
238 A simple solution, if static non-constant references are needed, is to attach the 
239 field to Thread.currentThread.threadGroup(), which is an applet-specific reference.
240 Be sure, if you do this, that you use explicit setters and getters:
241
242 For example, 
243
244 private static String myvar;
245
246 ...
247
248 public void setMyVar(String x) {
249   ThreadGroup g = Thread.currentThread().threadGroup();
250   /**
251    * @j2sNative g._myvar = x;
252    * 
253    */
254    {
255      myvar = x;
256    }
257 }
258
259 public String getMyVar() {
260   ThreadGroup g = Thread.currentThread().threadGroup();
261   /**
262    * @j2sNative return g._myvar || null;
263    * 
264    */
265    {
266      return myvar;
267    }
268 }
269  
270  in Java will get and set x the same in JavaScript and in Java. 
271  
272  
273 A convenient way to do this in general is to supply a singleton class with
274 explicitly private-only constructors and then refer to it in Java and in JavaScript
275 instead of using static field, referring to myclass.getIntance().xxx instead of 
276 myclass.xxx in Java (and JavaScript). 
277
278 This was done extensively in the Jalview project. See jalview.bin.Instance.
279
280
281 Helper Packages -- swingjs/ and javajs/
282 ---------------------------------------
283
284 The SwingJS library is the swingjs/ package. There are interfaces that may be of assistance
285 in swingjs/api, but other than that, it is not recommended that developers access classes in 
286 this package. The "public" nature of their methods is really an internal necessity.
287
288 In addition to swingjs/, though, there are several useful classes in the javajs/ package
289 that could be very useful. This package is a stand-alone package that can be 
290 cloned in any Java project that also would be great to have in any JavaScript project
291 -- SwingJS-related or not. Functionality ranges from reading and writing various file 
292 formats, including PDF, BMP, PNG, GIF, JPG, JSON, ZIP, and CompoundDocument formats.
293
294 A variety of highly efficient three- and four-dimensional point, vector, matrix, and 
295 quaternion classes are included, as they were developed for JSmol and inherited from that
296 project. 
297
298 Of particular interest should be javajs/async/, which includes
299
300 javajs.async.Async
301 javajs.async.AsyncColorChooser
302 javajs.async.AsyncDialog
303 javajs.async.AsyncFileChooser
304
305 See javajs.async.Async JavaDoc comments for a full description of 
306 these useful classes.
307
308
309 Modal Dialogs
310 -------------
311
312 Although true modal dialogs are not possible with only one thread, a functional equivalent -- 
313 asynchronous modal dialogs -- is relatively easy to set up. All the JOptionPane dialogs will
314 return PropertyChangeEvents to signal that they have been disposed of and containing the results. 
315 See below and classes in the javajs.async package.
316
317
318 Native calls
319 ------------
320
321 Native calls in Java are calls to operating system methods that are not in Java. JavaScript
322 has no access to these, of course, and they must all be replaced by JavaScript equivalents.
323 Fortunately, they are not common, and those that are present in Java (for example, in calculating
324 checksums in ZIP file creation) are at a low enough level that most developers do not utilize them
325 or do not even have access to them. All native calls in Java classes have been replaced by 
326 Java equivalents.
327
328
329 Swing GUI Peers and UIClasses
330 -----------------------------
331
332 One of the biggest adaptations introduced in SwingJS is in the area of the graphical 
333 user interface. The issue here is complex but workable. In Java there are two background 
334 concepts -- the Component "peer" (one per "heavy-weight" component, such as a Frame) and the 
335 component "uiClass" (one per component, such as JButton or JTextField).
336
337 Peers are native objects of the operating system. These are the virtual buttons and text areas
338 that the user is interacting with at a very base level. Their events are being passed on to 
339 Java or the browser by the operating system. UI classes provide a consistent "look and feel" 
340 for these native objects, rendering them onto the native window canvas and handling all 
341 user-generated events. They paint the borders, the backgrounds, the highlights, of every 
342 control you see in Java. There is one-to-one correspondence of Swing classes and UI classes. 
343 Setting the Look and Feel for a project amounts to selecting the directory from which to draw 
344 these UI classes. The UI classes can be found in the javax.swing.plaf ("platform look and feel") 
345 package.
346
347 Early on in the development of SwingJS, we decided not to fully reproduce the painfully detailed 
348 bit-by-bit painting of controls as is done in Java. Instead, we felt it was wiser to utilize the standard
349 HTML5 UI capabilities as much as possible, using DIV, and INPUT especially, with extensive use
350 of CSS and sometimes jQuery (menus, and sliders, for example). Thus, we have created a new 
351 set of UIs -- the "HTML5 Look and Feel". These classes can be found in swingjs.plaf. Besides being
352 more adaptable, this approach allows far more versatility to SwingJS developers, allowing them
353 to modify the GUI to suit their needs if desired.
354
355 In SwingJS, since we have no access to native peers except through the browser DOM,
356 it seemed logical to merge the peer and UI idea. So instead of having one peer per heavy-weight control and
357 one UI class instance for each control type, we just have one UI class instance per control, and
358 that UI class instance is what is being referred to when a "peer" is notified. 
359
360 In some ways this is a throw back to when all of Swing's components were subclasses of
361 specific AWT components such as Button and List. These "heavy-weight components" all had their 
362 own individual native peers and thus automatically took on the look and feel provided by the OS. 
363 Later Swing versions implemented full look and feel for all peers, leaving only JDialog, JFrame,
364 and a few other classes to have native peers. But in SwingJS we have again a 1:1 map of component
365 and UI class/peer instance.
366
367 The origin of most issues (read "bugs") in relation to the GUI will probably be found in the
368 swingjs.plaf JSxxxxUI.java code.
369
370   
371 Swing-only Components -- no longer an issue
372 -------------------------------------------
373
374 Swing was introduced into Java well after the Java Abstract Window Toolkit (AWT) was well
375 established. As such, its designers chose to allow AWT controls such as Button and List to be used 
376 alongside their Swing counterparts JButton and JList. Reading the code, it is clear that this 
377 design choice posed a huge headache for Swing class developers. 
378
379 For SwingJS, we decided from the beginning NOT to allow this mixed-mode programming and 
380 instead to require that all components be Swing components. 
381
382 However, this is no longer an issue. All AWT components in SwingJS are now subclasses of 
383 javax.swing.JComponent. So far, we have found no problem with this.
384
385  
386 The a2s Adapter Package
387 -----------------------
388
389 Originally, we thought that we would restrict ourselves to JApplets only. That is, only
390 Swing-based applets. But as we worked, we discovered that there are a lot of great 
391 applets out there that are pre-Swing pure-AWT java.applet.Applet applets. Our problem was 
392 that we also wanted it to be possible to quickly adapt these applets to JavaScript as well.
393  
394 The solution turned out to be simple: Write a package (a2s) that recreates the interface for 
395 non-Swing components as subclasses of Swing components. Thus, a2s.Button subclasses javax.swing.JButton
396 but also accepts all of the methods of java.awt.Button. This works amazingly well, with a few
397 special adaptations to the core javax.swing to be "AWT-aware." All AWT components now subclass 
398 a2s components, which in turn subclass JComponents. So no changes in code are necessary. We have
399 successfully transpiled over 500 applets using this strategy. (Kind of surprising, actually, that
400 the original Java developers did not see that option. But we have a hindsight advantage here.)
401
402
403 Working with Files
404 ==================
405
406 Simple String file names are not optimal for passing information about
407 read files within SwingJS applications. 
408  
409 All work with files should either use Path or File objects exclusively. 
410 These objects, after a file is read or checked for existence, will already 
411 contain the file byte[] data. Doing something like this:
412
413 File f = File("./test.dat");
414 boolean isOK = f.exists();
415
416 will load f with its byte[] data, if the file exists. 
417
418 But if after that, we use:
419
420 File f2 = new File(f.getAbsolutePath());
421
422 f2 will not contain that data. Such copying should be done as:
423
424 File f2 = new File(f);
425
426 in which case, the byte[] data will be transferred.
427
428
429 SwingJS uses the following criteria to determine if File.exists() returns true:
430
431 (1) if this File object has been used directly to read data, or 
432 (2) if reading data using this File object is successful.
433
434 Note that you cannot check to see if a file exists before input or if it 
435 was actually written or if it already exists prior to writing in SwingJS.  
436
437 Thus, you should check each use of file.exists() carefully, and if necessary, provide a J2sNative 
438 block that gives an appropriate "OK" message, for example:
439
440 (/** @j2sNative 1 ? false : */ outputfile.exits())
441
442 or 
443
444 (/** @j2sNative 1 ? true : */ inputfile.exits())
445
446 Temporary files can be created in SwingJS. SwingJS will maintain a pseudo-filesystem for files 
447 created with File.createTempFile(). This is useful in that closure of writing to a temporary file 
448 does not generate a pseudo-download to the user's machine.
449
450
451 UNIMPLEMENTED CLASSES BY DESIGN
452 ===============================
453
454 The SwingJS implementation of the following classes are present 
455 in a way that gracefully bypasses their functionality:
456
457 accessibility
458 security
459 serialization
460
461
462
463 TODO LIST FOR UNIMPLEMENTED CLASSES
464 ===================================
465
466 JEditorPane (minimal implementation) - DONE 12/2018; some issues still
467 JSplitPane - DONE 8/2018
468 JTabbedPane - DONE 10/2018
469 JTree - done 12/2019
470
471
472 MINOR ISSUES--required some rewriting/refactoring by Bob and Udo  
473 ================================================================
474
475 Thread.currentThread() == dispatchThread
476
477
478 MINOR ISSUES--requiring some rewriting/refactoring outside of SwingJS  
479 =====================================================================
480
481 See below for a full discussion.
482
483 HashMap, Hashtable, and HashSet iterator ordering
484 interning, new String("xxx") vs "xxx"
485 Names with "$" and "_"
486 positive integers do not add to give negative numbers
487 ArrayIndexOutOfBounds
488 java.awt.Color
489 native methods
490 javax.swing.JFileDialog
491 key focus
492 LookAndFeel and UI Classes
493 System.exit(0) does not stop all processes
494 list cell renderers must be JComponents
495 myClass.getField not implemented
496 "window" and other reserved JavaScript names
497 reserved field and method names
498 qualified field and method names
499 missing Math methods
500 Component.getGraphics(), Graphics.dispose()
501 Graphics.setClip()
502
503 MAJOR ISSUES--for Bob and Udo within SwingJS
504 ============================================
505
506 fonts
507 OS-dependent classes
508 AWT component peers
509 some aspects of reflection
510
511 MAJOR ISSUES--to be resolved by implementers
512 ============================================
513
514 fonts
515 threads
516 modal dialogs
517 image loading
518 BigDecimal not fully implemented 
519 no format internationalization
520 no winding rules
521 text-related field implementation
522 Formatter/Regex limitations
523 integer 1/0 == Infinity
524
525 ======================================================================== 
526
527 DISCUSS
528 =======
529
530 Table row/col sorter needs checking after removal of java.text.Collator references
531
532 I had to move all of SunHints class to RenderingHints, or the 
533 two classes could not be loaded. Shouldn't be a problem, I think. The sun classes are
534 not accessible to developers in Java anyway, since they are generally package private.
535
536 ========================================================================== 
537
538 //////////////////////////////////////////////////////////////////////////////
539
540 UNIMPLEMENTED CLASSES
541 =====================
542
543 accessibility
544 -------------
545
546 All Accessibility handling has been commented out to save the download footprint.
547 This removes the need for sun.misc.SharedSecrets as well. 
548 Nothing says we could not implement accessibility. We just didn't.
549
550
551 security
552 --------
553
554 All JavaScript security is handled by the browser natively. 
555 Thus, Java security checking is no longer necessary, and 
556 java.security.AccessController has been simplified to work without
557 native security checking.
558
559 Note that private methods in a class are REALLY private. 
560
561
562 serialization
563 -------------
564
565 All serialization has been removed. It was never very useful for Swing anyway, 
566 because one needs exactly the same Java version to save and restore serialized objects.
567
568
569 keyboard accelerators and mnemonics
570 -----------------------------------
571
572 This work was completed in the spring of 2019. Note that in a browser, some 
573 key strokes, particularly CTRL-keys, are not available. Bummer.
574
575
576 MINOR ISSUES--required some rewriting/refactoring by Bob and Udo  
577 ================================================================
578
579
580 Thread.currentThread() == dispatchThread
581 ----------------------------------------
582
583 changed to JSToolkit.isDispatchThread()
584
585
586 MINOR ISSUES--requiring some rewriting/refactoring outside of SwingJS  
587 =====================================================================
588
589 HashMap, Hashtable, and HashSet iterator ordering
590 -------------------------------------------------
591
592 In Java, iterators for HashMap, Hashtable, and HashSet do not guarantee any particular order. 
593 From the HashMap documentation for Java 8:
594
595         This class makes no guarantees as to the order of the map; in particular, it does not 
596         guarantee that the order will remain constant over time.
597  
598 Likewise, for HashSet (because it is simply a convenience method for HashMap<Object,PRESENT>:
599
600         [HashSet] makes no guarantees as to the iteration order of the set.
601
602 JavaScript's Map object is different. It is basically a LinkedHashMap, so it guarantees iteration
603 in order of object addition.
604
605 Starting with java2script 3.2.9.v1, these classes use the JavaScript Map object rather than hash codes
606 whenever all keys are strictly of JavaScript typeof "string". If any key is introduced that is not a string, the
607 implementation falls back to using hash codes, the same as Java. 
608
609 Note strings created using new String("xxxx") are NOT typeof "string"; they are typeof "object".
610
611 The result is significantly faster performance (3-12 x faster) than originally, and up to 3 x faster
612 performance in JavaScript than in Java itself. Right. Faster than Java. 
613
614 The JavaScript Map implementation is implemented UNLESS the constructor used is the one that
615 specifies both initial capacity and load factor in their constructor. Thus, 
616
617 new Hashtable()
618 new HashMap()
619 new HashMap(16)
620 new HashSet()
621
622 all use the JavaScript Map. But
623
624 new Hashtable(11, 0.75f)
625 new HashMap(16, 0.75f)
626 new HashSet(16, 0.75f)
627
628 do not. 
629
630 This design allows for opting out of the JavaScript Map use in order to retain the exact behavior of 
631 iterators in JavaScript as in Java.
632
633
634 interning, new String("xxx") vs "xxx"
635 -------------------------------------
636
637 Note that the following are true in JavaScript:
638
639 typeof new String("xxxx") == "object"
640 typeof "xxxx" == "string"
641 var s = "x";typeof ("xxx" + s) == "string"
642
643 There is no equivalence to this behavior in Java, where a String is a String is a String.
644
645 Be aware that SwingJS does not always create a JavaScript String object using JavaScript's 
646 new String(...) constructor. It only does this for Java new String("xxxx") or new String(new String()). 
647
648 In all other cases, new String(...) (in Java) results in a simple "xxxx" string in JavaScript. 
649 That is, it will be JavaScript typeof "string", not typeof "object". 
650
651 The reason for this design is that several classes in the Java core use toString() 
652 methods that return new String(), and those classes that do that would cause a JavaScript error
653 if implicitly stringified if new String() returned a JavaScript String object. 
654
655 This is fine in JavaScript
656
657 test1 = function() { return { toString:function(){ return "OK" } } }
658 "testing" + new test1()
659 >> "testingOK"
660
661 But for whatever reason in JavaScript:
662
663 test2 = function() { return { toString:function(){ return new String("OK") } } }
664 "testing" + new test2()
665 >> Uncaught TypeError: Cannot convert object to primitive value
666
667 The lesson here is never to use 
668
669   return new String("...");
670
671 in a Java toString() method. In Java it will be fine; in JavaScript it will also be fine as long as
672 that method is never called in JavaScript implicitly in the context of string concatenation.
673
674 A note about interning. Consider the following six Java constructions, where we have a == "x";
675
676 "xxx"
677 "xx" + "x"
678 new String("xxx").intern()
679
680 new String("xxx")
681 "xx" + a.toString()
682 "xx" + a
683
684 All six of these will return java.lang.String for .getClass().getName().
685 However, the first three are String literals, while the last three are String objects. 
686 Thus:
687         "xxx" == "xxx"
688         "xxx" == "xx" + "x"
689         "xxx" == new String("xxx").intern()
690
691 but none of the other three are equivalent to "xxx" or each other:
692
693               "xxx" != new String("xxx")
694               "xxx" != "xx" + a.toString()
695               "xxx" != "xx" + a
696   new String("xxx") != new String("xxx") 
697            "xx" + a != new String("xxx") 
698
699 etc.
700
701 As in Java, in SwingJS, all of the following Java assertions pass as true:
702
703                 assert("xxx" == "xx" + "x"); 
704                 assert("xxx" == ("xx" + a).intern()); 
705                 assert("xxx" === new String("xxx").intern()); 
706                 
707 and both of these do as well:
708
709                 assert(new String("xxx") != "xxx"); 
710                 assert(new String("xxx") != new String("xxx")); 
711
712 But the following two fail to assert true:
713
714         assert("xxx" != "xx" + a);
715         assert("xxx" != "xx" + a.toString());
716
717 because in JavaScript, both of these right-side expressions evaluate to a simple "interned" string.
718
719 In Java, however, these assertions are true because Java implicitly "boxes" String 
720 concatentaion as a String object, not a literal. 
721
722 Most of us know not to generally use == with Strings unless they are explicitly interned. 
723 Where this problem may arise, though, is in IdentityHashMap, which compares objects using 
724 System.identityHashCode(), which is not the same for different objects or their string literal equivalents.
725
726 My recommendation, if you need to use IdentityHashMap with strings is to always use an explicit String.intern()
727 for any keys -- unless you really want to keep every string as separate keys even if they are the same sequence, 
728 in which case, use new String(). This will work in Java and in  JavaScript.
729
730 Be aware when working with strings that come from SwingJS and are being used by other JavaScript modules
731 that those that are String objects will return "object" for the JavaScript typeof operator, not "string".
732
733 The easy way to ensure this is no problem is to concatenate strings with "" to force immediate interning:
734
735   var x = aJavaObject.getString() + "";
736
737 unless you are certain that the string is being returned is a raw JavaScript string.   
738
739 Names with "$" and "_"
740 ----------------------
741
742 For the most part, this should be no problem. 
743
744 Note that the use of $ and _ in Java field names has always been discouraged:
745 [https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html]
746
747         You may find some situations where auto-generated names will contain the dollar sign, 
748         but your variable names should always avoid using it. A similar convention 
749         exists for the underscore character; while it's technically legal to begin your 
750         variable's name with "_", this practice is discouraged.
751
752 Some impacts of transpiling method names with full qualification:
753
754 1) SwingJS will introduce fields that start with $ or _. These will not conflict
755    if the above convention is followed.
756    
757 2) Fields that have the same Java name as a method are not an issue. 
758
759 3) Fields that have a Java name with $ that matches a transpiled method name, 
760    such as toString$, will need to be refactored in Java to not have that name collision.
761    
762 4) Fields in a subclass that have the same name as private fields in a superclass
763    represent a name collision, because the superclass method needs to call its private
764    field even if invoked from a subclass. The solution was to modify the subclass field
765    name using one or more prepended $.
766    
767 5) Use of Class.getDeclaredMethods() reflection will return Method objects having the transpiled 
768    name, not the Java name. This could require some j2sNative adjustment 
769    to strip the $... parameters from the name if that is needed. 
770
771 6) Use of Method.getParameterTypes() should work fine, provided class names
772    do not contain "_". This is because the transpiler converts "." to "_" when
773    creating the fully qualified JavaScript name.
774
775
776 positive integers do not add to give negative numbers
777 -----------------------------------------------------
778
779 In Java, the following is true:
780
781   2000000000 + 2000000000 == -294967296
782
783 But in SwingJS, that will be 4000000000. So, for example, the following
784 strategy will fail in SwingJS:
785
786                 int newLength = lineBuf.length * 2;
787                 if (newLength < 0) {
788                         newLength = Integer.MAX_VALUE;
789                 }
790
791 "-1" in JavaScript is not 0xFFFFFFFF.
792
793 And one must take care to not compare a negative number with a 32-bit mask. So
794
795 (b & 0xFF000000) == 0xFF000000
796
797 is true in Java for (int) b = -1, but is false in JavaScript, because 0xFF000000 is 4278190080, 
798 while (-1 & 0xFF000000) is, strangely enough, -16777216, and, in fact, 
799
800 (0xFF000000 & 0xFF000000) != 0xFF000000
801
802 because -16777216 is not 4278190080.
803
804 The fix is that one must compare similar operations:
805
806 if ((b & 0xFF000000) == (0xFF000000 & 0xFF000000)) .....
807
808 Importantly, the JavaScript Int32Array does behave properly. From 
809 the Firefox developer console:
810
811 >> x = new Int32Array(1)
812 <- Int32Array(1) [ 0 ]
813 >> x[0] = 4000000000
814 <- 4000000000
815 >> x[0]
816 <- -294967296
817
818 Notice that, perhaps unexpectedly, the following two constructs produce 
819 different results in JavaScript:
820
821 x = new Int32Array(1);
822 b = x[0] = 4000000000;
823
824 (b will be 4000000000)
825
826 and
827
828 x = new Int32Array(1);
829 x[0] = 4000000000;
830 b = x[0];
831
832 (b will be -294967296)
833
834
835 SwingJS leverages array typing to handle all byte and short arithmetic so as
836 to ensure that any byte or short operation in JavaScript does give the same 
837 result in Java. The design decision to not also do this with integer math was
838 a trade-off between performance and handling edge cases.
839
840
841 ArrayIndexOutOfBounds
842 ---------------------
843
844 You cannot implicitly throw an ArrayIndexOutOfBoundsException in JavaScript.
845 JavaScript will simply return "undefined", not throw an Exception. So:
846
847 boolean notAGoodIdeaIsOutOfBounds(String[] sa, int i) {
848   try {
849      return (sa[i] == sa[i]);
850   } catch (ArrayIndexOutOfBoundsException e) {
851         return false;
852   }
853 }
854
855 will work in Java but not in JavaScript. Code should not depend upon this sort 
856 of trap anyway, if you ask me. 
857
858 Throwable vs Error vs Exception
859 -------------------------------
860
861 True JavaScript errors are trapped as Throwable, whereas you can still trap
862 Error and Exception as well. So if you want to be sure to catch any JavaScript
863 error, use try{}catch (Throwable t){}, not try{}catch (Exception e){}. 
864
865 j
866 ava.awt.Color
867 --------------
868
869 ColorSpace: only "support" CS_sRGB.
870
871  TODO -- any volunteers??
872  
873
874 javax.swing.JFileDialog
875 -----------------------
876
877 HTML5 cannot expose a file reading directory structure. But you certainly 
878 can still do file reading and writing. It just works a little differently.
879 It's a simple modification:
880
881                 b = new JButton("FileOpenDialog");
882                 b.addActionListener(new ActionListener() {
883
884                         @Override
885                         public void actionPerformed(ActionEvent e) {
886                                 JFileChooser fc = new JFileChooser();
887                                 Test_Dialog.this.onDialogReturn(fc.showOpenDialog(Test_Dialog.this));
888                                 // Java will wait until the dialog is closed, then enter the onDialogReturn method.
889                                 // JavaScript will exit with NaN immediately, and then call back with its actual value
890                                 // asynchronously.
891                         }
892
893                 });
894         
895                 public void onDialogReturn(int value) {
896                         if (value != Math.floor(value))
897                                 return; // in JavaScript, this will be NaN, indicating the dialog has been opened
898                         // If we are here, the dialog has closed, in both Java and JavaScript.
899                         System.out.println("int value is " + value);
900                 }
901
902
903         @Override
904         public void propertyChange(PropertyChangeEvent event) {
905                 Object val = event.getNewValue();
906                 String name = event.getPropertyName();
907                 System.out.println(name);
908                 switch (event.getSource().getClass().getName()) {
909                 case "javax.swing.JOptionPane":
910                         switch (name) {
911                         case "inputValue":
912                                 onDialogReturn(val);
913                                 return;
914                         case "value":
915                                 if (val instanceof Integer)
916                                         onDialogReturn(((Integer) val).intValue());
917                                 else
918                                         onDialogReturn(val);
919                                 return;
920                         }
921                         break;
922                 case "javax.swing.ColorChooserDialog":
923                         switch (name) {
924                         case "SelectedColor":
925                                 onDialogReturn(val);
926                                 return;
927                         }
928                         break;
929                 case "javax.swing.JFileChooser":
930                         switch (name) {
931                         case "SelectedFile":
932                                 File file = (File) val;
933                                 byte[] array = (val == null ? null : /** @j2sNative file.秘bytes || */
934                                                 null);
935                                 onDialogReturn("fileName is '" + file.getName() + "'\n\n" + new String(array));
936                                 return;
937                         }
938                         break;
939                 }
940                 System.out.println(
941                                 event.getSource().getClass().getName() + " " + event.getPropertyName() + ": " + event.getNewValue());
942         }
943
944
945 Developers are encouraged to create a separate class that handles general calls to JFileDialog. 
946 An example class can be found in the SwingJS distribution as 
947
948 /sources/net.sf.j2s.java.core/src/javajs/async/AsyncFileChooser.java.
949
950
951 javax.swing.JOptionPane dialogs
952 -------------------------------
953
954 For this action to work, the parentComponent must implement
955 propertyChangeListener, and any call to JOptionPanel should allow for
956 an asynchronous response, meaning that there is no actionable code following the
957 call to the dialog opening. 
958
959 In addition, for compatibility with the Java version, implementation should
960 wrap the call to getConfirmDialog or getOptionDialog in a method call to
961 handle the Java:
962
963 onDialogReturn(JOptionPane.showConfirmDialog(parentFrame,
964 messageOrMessagePanel, "title", JOptionPane.OK_CANCEL_OPTION));
965
966 Then parentFrame.propertyChange(event) should also call onDialogReturn.
967
968 This will then work in both Java and JavaScript.
969
970 Note that there is an int and an Object version of onDialogReturn().
971
972
973 In JavaScript:
974
975 The initial return from JOptionPane.showConfirmDialog and showMessageDialog
976 will be (SwingJS) JDialog.ASYNCHRONOUS_INTEGER (NaN), testable as an impossible 
977 Java int value using ret != -(-ret) if the parent implements PropertyChangeListener, or -1
978 (CLOSE_OPTION) if not.
979
980 For showOptionDialog (which returns Object) or showInputDialog (which returns
981 String), the initial return will be (SwingJS) JDialog.ASYNCHRONOUS_OBJECT, testable as
982 ((Object) ret) instanceof javax.swing.plaf.UIResource if the parent implements
983 PropertyChangeListeneer, or null if not.
984
985 The second return will be the desired return.
986
987 In Java:
988
989 The initial return will be the one and only modal final return.
990
991
992
993 For full compatibility, The calling method must not continue beyond this
994 call.
995
996 All of the standard Java events associated with Components are also
997 available.
998
999 Certain fall back mechanisms are possible, where onReturn does not exist, but
1000 only for the following cases:
1001
1002
1003 For showMessageDialog, for WARNING_MESSAGE and ERROR_MESSAGE, a simple
1004 JavaScript alert() is used, returning 0 (OK_OPTION) or -1 (CLOSED_OPTION).
1005
1006 For showInputDialog, if the message is a string, a simple JavaScript prompt()
1007 with input box is used, returning the entered string or null.
1008
1009 For showConfirmDialog, a simple JavaScript confirm() is used, in which case:
1010
1011 for YES_NO_OPTION: YES_OPTION or NO_OPTION
1012
1013 for YES_NO_CANCEL_OPTION: YES_OPTION or CANCEL_OPTION
1014
1015 for OK_CANCEL_OPTION or any other: OK_OPTION or CANCEL_OPTION
1016
1017 Note that you should implement a response for CLOSED_OPTION for
1018 showConfirmDialog. For other dialogs, a null return indicates the dialog was
1019 closed, just as for Java.
1020
1021 Developers are encouraged to create a separate class that handles general calls. 
1022 An example class can be found in the SwingJS distribution as src/javajs/async/AsyncDialog.java.
1023 Very simple modifications to the Java allows asynchronous operation using AsyncDialog. Here
1024 is a simple "do you want to close this frame" example, where you can see that what we have
1025 done is to set the reply into an ActionListener that is defined in the constructor of 
1026 the AsyncDisplay object:
1027
1028 // Original:
1029 //
1030 //      private void promptQuit() {
1031 //              int sel = JOptionPane.showConfirmDialog(null, PROMPT_EXIT, NAME, JOptionPane.YES_NO_OPTION);
1032 //              switch (sel) {
1033 //              case JOptionPane.YES_OPTION:
1034 //                      resultsTab.clean();
1035 //                      seqs.dispose();
1036 //                      if (fromMain) {
1037 //                              System.exit(0);
1038 //                      }
1039 //                      break;
1040 //              }
1041 //      }
1042
1043         private void promptQuitAsync() {
1044                 new AsyncDialog(new ActionListener() {
1045
1046                         @Override
1047                         public void actionPerformed(ActionEvent e) {
1048                             int sel = ((AsyncDialog)e.getSource()).getOption();
1049                                 switch (sel) {
1050                                 case JOptionPane.YES_OPTION:
1051                                         resultsTab.clean();
1052                                         seqs.dispose();
1053                                         if (fromMain) {
1054                                                 System.exit(0);
1055                                         }
1056                                         break;
1057                                 }
1058                         }}).showConfirmDialog(null, PROMPT_EXIT, NAME, JOptionPane.YES_NO_OPTION);
1059         }
1060
1061 Very simple! 
1062
1063
1064 native methods
1065 --------------
1066
1067 The J2S compiler ignores all static native method declarations.
1068 Anything of this nature needs to be implemented in JavaScript if it is needed,
1069 using j2sNative blocks:
1070
1071 /**
1072  * @j2sNative
1073  *
1074  *    var putYourJavaScriptCodeHere
1075  *
1076  */
1077  
1078  Note that if you follow that directly with a {...} block, then 
1079  the javadoc code will run in JavaScript, and the {...} code will run in Java.
1080  
1081  
1082 key Focus
1083 ---------
1084
1085 As of June, 2019, the keyboard focus manager is fully implemented. 
1086 The one catch is that JTextPane and JTextArea, which already consume
1087 VK_TAB in Java, cannot use CTRL-TAB to continue a tabbing cycle around
1088 the components in a window. Instead, CTRL-TAB is absorbed by the browser. 
1089
1090
1091 LookAndFeel and UI Classes
1092 --------------------------
1093
1094 SwingJS implements the native browser look and feel as swingjs.plaf.HTML5LookAndFeel. 
1095 There are small differences between all look and feels -- MacOS, Windows, SwingJS.
1096
1097 Expert developers know how to coerce changes in the UI by subclassing the UI for a 
1098 component. This probably will not work in SwingJS. 
1099
1100 Note that LookAndFeel in Java usually determines canvas size in a Frame because 
1101 different operating systems (Mac OS vs Windows vs HTML5) will have 
1102 different edge sizes on their frames. If you want to ensure a component size, 
1103 use getContentPane().setPreferredSize().
1104
1105
1106 System.exit(0) does not stop all processes
1107 ------------------------------------------
1108
1109 Although System.ext(int) has been implemented in JavaScript, it just closes the 
1110 frames, stops all pending javax.swing.Timer objects in the queue, and runs any 
1111 threads added using Runtime.getRuntime().addShutdownHook(Thread).
1112 It may not stop all "threads." So don't rely on that.
1113 Applications are responsible for shutting down prior to executing System.exit(0). 
1114
1115
1116 myClass.getField not implemented
1117 --------------------------------
1118
1119 java.lang.reflect.Field is implemented minimally. It is not
1120 certain that Field.getDeclaringClass() will work. If you just want a 
1121 value of a field, you can do this:
1122
1123 /**
1124  *@j2sNative
1125  *
1126  * return myClass[name]
1127  */   
1128
1129 But that is not a java.lang.reflection.Field object.
1130
1131
1132 "window" and other reserved JavaScript names
1133 --------------------------------------------
1134
1135 No reserved top-level JavaScript name is allowed for a package name. So, for example, 
1136 one must rename packages such as "window" or "document" to names such as "win" or "doc".
1137
1138 reserved field and method names
1139 -------------------------------
1140
1141 In order to minimize the chance of added SwingJS field and method names colliding with ones 
1142 developers might use in subclassing Java classes, we have added U+79D8 (first character of Mandarin 
1143 "secret") to the characters already disrecommended by Java documentation ("$" and "_"). The only problem
1144 would be if you use that character followed by certain English words in certain classes. For example
1145 \u79D8canvas for JComponents (in java.awt.JSComponent) and \u79D8byte (in java.io.File).
1146
1147 qualified field and method names
1148 --------------------------------
1149
1150 Method names in SwingJS are fully qualified, meaning two methods with the same Java name but different
1151 parameters, such as write(int) and write(double), must not have the same name in JavaScript. (In this
1152 case, we will have write$I and write$D.) However, in certain cases it may be desirable to leave the
1153 method names unqualified. In particular, when an interface actually represents a JavaScript object, 
1154 the transpiler can leave a method name unqualified. The default situation for this is a class name 
1155 includes ".api.js" (case-sensitive). This means that any method in any class in a package js within 
1156 a package api, or any private interface js that has an outer interface api, will have all-unqualified
1157 methods. An example of this is swingjs.plaf.JSComboPopupList, which needs to communicate with a jQuery 
1158 object directly using the following interface:
1159
1160         private interface api {
1161
1162                 interface js extends JQueryObject {
1163
1164                         abstract js j2sCB(Object options);
1165
1166                         abstract Object[] j2sCB(String method);
1167
1168                         abstract Object[] j2sCB(String method, Object o);
1169
1170                         abstract Object[] j2sCB(String method, int i);
1171
1172                         abstract int j2sCB(String OPTION, String name);
1173
1174                 }
1175         }
1176
1177 Notice that all these variants of j2sCB() will call the same method in JavaScript by design.
1178
1179
1180 missing Math methods
1181 --------------------
1182
1183 java.lang.Math is worked out, but some methods are missing, either because they
1184 involve long integer value that are inaccessible in JavaScript, or because I just
1185 didn't implement them. This is a result of continued Java development. 
1186 It is easy enough to add these methods if you have the source. They go into j2sClazz.js, 
1187 which is combined with other initial libraries into swingjs2.js by build_site.xml
1188
1189
1190 Component.getGraphics(), Graphics.dispose()
1191 -------------------------------------------
1192
1193 Use of component.getGraphics() is discouraged in Java and in SwingJS. 
1194 Specifically in SwingJS, any call to component.getGraphics() or 
1195 BufferedImage.createGraphics() or Graphics.create(...) should be matched with graphics.dispose(), 
1196 particularly when it is called outside the context of a paint(Graphics)
1197 call from the system. 
1198
1199 If you see your graphics scrolling down the page with each repaint, 
1200 look for where you have used Component.getGraphics() and not Graphics.dispose().
1201 For example, this will definitely NOT work in SwingJS:
1202
1203   this.paint(getGraphics())
1204   
1205 and really should not work in Java, either, as it is technically a resource memory leak.
1206
1207 Instead, if you really do not want to use repaint(), use this:
1208
1209   Graphics g = getGraphics();
1210   paint(g);
1211   g.dispose();
1212
1213
1214
1215 Graphics.setClip()
1216 ------------------
1217
1218 The HTML5 canvas.clip() method is permanent. You can only reset the clip using
1219 save/restore. This is different from Java, where you can temporarily change it using
1220
1221   Shape oldClip = Graphics.getClip();
1222   Graphics.setClip(newClip);
1223    ...
1224   Graphics.setClip(oldClip); 
1225
1226 If you need to do something like this, you must schedule the paints
1227 to not have overlapping clip needs.
1228
1229
1230 MAJOR ISSUES--for Bob and Udo within SwingJS
1231 ============================================
1232
1233 fonts
1234 -----
1235
1236 Fonts and FontMetrics will all be handled in JavaScript. Font matching will 
1237 not be exact, and composite (drawn) fonts will not be supported. 
1238
1239 SwingJS handles calls such as font.getFontMetrics(g).stringWidth("xxx") by 
1240 creating a <div> containing that text, placing it in an obscure location on 
1241 the page, and reading div.getBoundingClientRect(). This is a VERY precise
1242 value, but can be a pixel or two off from what Java reports for the same font.
1243  
1244  
1245 OS-dependent classes
1246 --------------------
1247
1248 Static classes such as:
1249
1250    java.awt.Toolkit
1251    java.awt.GraphicsEnvironment
1252    
1253    
1254 which are created using Class.forName are implemented using classes in the swingjs package.
1255
1256 AWTAccessor is not implemented. 
1257
1258    
1259 AWT component peers and component "ui" user interfaces
1260 ------------------------------------------------------
1261
1262 ComponentPeer is a class that represents a native AWT component.
1263 Components with such peers are called "heavy-weight" components.
1264 They are expected to do the dirty work of graphics drawing. 
1265
1266 Java Swing implements peers only for JApplet, JDialog, JFrame, and JWindow. 
1267 References to such objects have been removed, but clearly there must be 
1268 some connection to similar DOM objects, even for "light-weight" components. 
1269
1270
1271   
1272 MAJOR ISSUES--to be resolved by implementers
1273 ============================================
1274
1275 fonts
1276 -----
1277
1278 Glyph/composite/outline fonts are not supported.
1279    
1280
1281
1282 threads
1283 -------
1284
1285 Thread locking and synchronization are not relevant to JavaScript.
1286 Thus, anything requiring "notify.." or "waitFor.." could be a serious issue.
1287  
1288 All threading must be "faked" in JavaScript. Specifically not available is:
1289
1290   Thread.sleep()
1291   
1292 javax.swing.AbstractButton#doClick(pressTime) will not work, as it requires Thread.sleep();
1293     
1294 However, java.lang.Thread itself is implemented and used extensively. 
1295
1296 Methods thread.start() and thread.run() both work fine. 
1297
1298 For simple applications that use Thread.sleep() just to have a delay, as in a frame rate, for 
1299 example, one can use javax.swing.Timer instead. That is fully implemented. 
1300
1301 Likewise, java.util.Timer can be replaced with no loss of performance with javax.Swing.Timer.
1302 Note that java.util.TimerTask is implemented, but it can also be replaced by an implementation of Runnable.
1303
1304 task = new TimerTask(){....};
1305 t = new java.util.Timer();
1306 t.schedule(task, 0, 1);
1307
1308 becomes
1309
1310 task = new TimerTask(){....}; // or task = new Runnable() {...}
1311 t = new javax.swing.Timer(1, new ActionListener() {
1312         @Override
1313         public void actionPerformed(ActionEvent e) {
1314                 task.run();
1315         }
1316 };
1317 t.setInitialDelay(0); // not particularly necessary
1318 t.start();
1319
1320 In addition, SwingJS provides swingjs.JSThread, which can be subclassed
1321 if desired. This class allows simple 
1322
1323   while(!interrupted()){
1324         wait()
1325         ...
1326   }  
1327
1328 action through an asynchronous function run1(mode). For example:
1329
1330         protected void run1(int mode) {
1331                 try {
1332                         while (true)
1333                                 switch (mode) {
1334                                 case INIT:
1335                                         // once-through stuff here
1336                                         mode = LOOP;
1337                                         break;
1338                                 case LOOP:
1339                                         if (!doDispatch || isInterrupted()) {
1340                                                 mode = DONE;
1341                                         } else {
1342                                                 Runnable r = new Runnable() {
1343                                                         public void run() {
1344                                                                 // put the loop code here
1345                                                         }
1346                                                 };
1347                                                 dispatchAndReturn(r);
1348                                                 if (isJS)
1349                                                         return;
1350                                         }
1351                                         break;
1352                                 // add more cases as needed
1353                                 case DONE:
1354                                         // finish up here
1355                                         if (isInterrupted())
1356                                                 return;
1357                                         // or here
1358                                         break;
1359                                 }
1360                 } finally {
1361                         // stuff here to be executed after each loop in JS or at the end in Java
1362                 }
1363         }
1364
1365 image loading
1366 -------------
1367 - All image loading in SwingJS is synchronous. A MediaTracker call will immediately return "complete".
1368   However, it still may take one system clock tick to fully load images. Thus, it is recommended that
1369   images be preloaded in the static block of the applet if it is necessary that they be available in init().
1370   This is only an issue if you are trying to access the pixel buffer of the image in JavaScript. 
1371   
1372 - Applet.getImage(path, name) will return null if the image does not exist. 
1373
1374 - BufferedImage: only "support" imageType RGB and ARGB
1375
1376   -BH: This is a temporary edit, just to get us started. Certainly GRAY will be needed
1377
1378
1379 BigInteger and BigDecimal
1380 -------------------------
1381
1382 java.math.BigInteger is fully supported; java.math.BigDecimal is roughed 
1383 in and not fully tested (07/2019). 
1384
1385 Both classes present significant issues for JavaScript, as they are based in 
1386 Java's 64-bit long for all their operations. Here is the JavaDoc note I added
1387 to BigInteger:
1388
1389  * SwingJS note: Because of the limitations of JavaScript with regard
1390  * to long-integer bit storage as a double, this implementation drops
1391  * the integer storage bit length to 24, giving 48 for long and leaving
1392  * the last 16 bits clear for the exponent of the double number. This should
1393  * not affect performance significantly. It does increase the storage 
1394  * size by about 33%. By bringing an "int" to 3 bytes, we can easily construct
1395  * and use byte[] data intended for the original BitSet.  
1396
1397 "Easily" may be a bit strong there. This was a serious challenge.
1398
1399 BigDecimal seems to run normally, but in order to do that, my hack involves
1400 reducing the size of an integer that is allowed to be stored as such and not
1401 in byte[] as a BigInteger. I'm sure there is a performance hit, but it does work.
1402
1403 no format internationalization
1404 ------------------------------
1405
1406 For now, just en for number and date formatters
1407
1408 no winding rules
1409 ----------------
1410
1411   When filling a graphic, only nonzero winding rule is implemented in HTML5 Canvas2D.
1412
1413
1414
1415 text-related field implementation
1416 ---------------------------------
1417
1418 Text fields are:
1419
1420 JTextField   (JavaScript <input type="text">)
1421 JTextArea    (JavaScript <textarea>)
1422 JTextPane    (JavaScript <div>)
1423 JEditorPane  (JavaScript <div>)
1424
1425 For the initial implementation, we don't implement infinite undo/redo, and the abstract 
1426 document model is much less elaborate. Only PlainDocument (in the form of JSPlainDocument)
1427 is implemented. The Document returned by JTextField.getDocument() is a javax.swing.text.Document.
1428
1429 All scrolling is handled by HTML5. javax.swing.AutoScroller is not implemented.
1430 public static methods .stop, .isRunning, .processMouseDragged require true Java threading
1431 and so are not implmented. javax.swing.text.View and its subclasses are not implemented. 
1432
1433 The JS document model does not allow two text fields to address the same underlying document. 
1434
1435
1436 Formatter/Regex limitations
1437 ---------------------------
1438
1439 Some browsers cannot process Regex "look-behind" process such as (?<=\W)
1440 java.util.regex.Matcher and Pattern use JavaScript's RegExp object rather than
1441 the native Java object. These are not identical. Only flags /igm are supported.
1442 Matcher.start(groupID) is not supported.
1443
1444 java.util.Formatter will function correctly for all standard %... patterns.
1445
1446 integer 1/0 == Infinity
1447 -----------------------
1448
1449 1/0 in Java throws "java.lang.ArithmeticException: / by zero", but in JavaScript is just Infinity. 
1450  
1451
1452
1453 Summary
1454 -------
1455
1456 These are all the known limitations of SwingJS. We have not found any of these limitations
1457 to be show-stoppers. The primary issue for newcomers to SwingJS is having the source code.
1458 You must check that source code for all your library jar files is available or, if you
1459 choose, you will need to decompile those classes. We have used decompilation on some projects,
1460 and it works just fine. So, technically, all we really need are JAR/class files. But the 
1461 source is by far superior. It's generally prettier, and it has the license information that
1462 may or may not be present with the JAR or class files. Use class files at your own risk.
1463
1464 Bob Hanson
1465 2019.08.16
1466
1467
1468 Additional Issues
1469 -----------------
1470
1471 Annotation is working for classes, methods, and fields (12/22/19). Method reflection, however,
1472 is limited. Interfaces do not expose their methods, as the transpiler does not actually transpile
1473 the interfaces themselves. And method reflection only includes annotated methods.
1474
1475 java.util.concurrent is not fully elaborated. This package is rewritten to not actually use the
1476 memory handling capabilities of concurrency, which JavaScript does not have access to.
1477
1478 System.getProperties() just returns a minimal set of properties.
1479
1480