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