[rfc][icedtea-web] plugin splash screen

Deepak Bhole dbhole at redhat.com
Mon Feb 13 09:06:20 PST 2012


* Jiri Vanek <jvanek at redhat.com> [2012-02-13 10:36]:
> Hi!
> 
> This is plugin's spalsh screen based on Deepak's old code.
> You can see imaged  spalshscreen here: http://download.eng.brq.redhat.com/scratch/jvanek/pluginLoading.gif
> Before JVM actually starts, there is just gray box. Currently I have no idea how to get rid of it. But I'm also not sure if it is possible or if it have some value to solve it.
> The grey box AFTER the splash-screen is correctly loaded empty applet (sorry for providing such a dummy one:-/). In case 3.5mb  animated gif is too big for you  just check this stalled one -  http://download.eng.brq.redhat.com/scratch/jvanek/screen55.gif ;)
> 
> The diff in atachement is code of spalsh creen nearly identical with original Deepak's one - just adapted for head.  I had just noticed that t is not at actual head - the diff of file b/netx/net/sourceforge/jnlp/Launcher.java is just "hardcoded" Danesh's fix for recent applet regression and have nothing to do with splash screen.
> The changes in testengine are just funny ones - for observering the spalsh screen, but I think they are worthy to be inside. In case that some test of splash screen will be in, they will be necessary.
> If you want to see the splash screen in work, make install and configure firefox, then check any applet;). If you want to see more of cycling sphere, you can start tests/netx/jnlp_testsengine/net/sourceforge/jnlp/ServerAccess.java class with -Dtest.server.dir setted correctly as tests do, add attached html file into this jnlp_server and lunch it... (It is how this gif was created).
> 
> Any comments to current approach are more then welcomed!
> 
> Things for future I'm thinking about
> - when applet will fail to load, something happens  - eg text with exception, just sad emoticon with information about debuging console....
> - javaws splash screen - I think that when plugin have spalsh screen, then javaws should have it too, to be unified - My ideas are  - at first use gif image for "java -splash" and then "quickly" replace him ASAP with true vector graphic. Both vorthy? Just vector graphics? Just animated gif? (not animated version of luncher is attached)
> - remake the loadng logo - I like Deepaks aproach, and I'm considering it as nice one.  But my sense for art is Zero-one. If you would like to suggest different one, please keep in mind it msut be vector one. A can also visit few frends oriented to computer graphic (I mean art, no pure programming)  and maybe we can find and create something better. But currently I consider it as waste of time.
> 
> 

I will let someone else review this since it would be unfair to review
my own old code :) One thing though -- this also includes
PluginSplashPanel2.java .. I think one of the classes was a test class
and the other one intended to be final. The *2 might have been the test
one..

Cheers,
Deepak

> Thanx for any thoughts!
> 
>   J.

> diff -r 528e354ff469 netx/net/sourceforge/jnlp/Launcher.java
> --- a/netx/net/sourceforge/jnlp/Launcher.java	Thu Feb 02 16:15:27 2012 -0500
> +++ b/netx/net/sourceforge/jnlp/Launcher.java	Mon Feb 13 15:57:17 2012 +0100
> @@ -708,6 +708,9 @@
>  
>              ThreadGroup group = Thread.currentThread().getThreadGroup();
>  
> +            // appletInstance is needed by ServiceManager when looking up 
> +            // services. This could potentially be done in applet constructor
> +            // so initialize appletInstance before creating applet.
>              AppletInstance appletInstance;
>              if (cont == null)
>                  appletInstance = new AppletInstance(file, group, loader, null);
> @@ -716,10 +719,14 @@
>  
>              loader.setApplication(appletInstance);
>  
> +            // Initialize applet now that ServiceManager has access to its
> +            // appletInstance.
>              String appletName = file.getApplet().getMainClass();
>              Class appletClass = loader.loadClass(appletName);
>              Applet applet = (Applet) appletClass.newInstance();
> +            // Finish setting up appletInstance.
>              appletInstance.setApplet(applet);
> +            appletInstance.getAppletEnvironment().setApplet(applet);
>              
>              setContextClassLoaderForAllThreads(appletInstance.getThreadGroup(), appletInstance.getClassLoader());
>  
> diff -r 528e354ff469 netx/net/sourceforge/jnlp/NetxPanel.java
> --- a/netx/net/sourceforge/jnlp/NetxPanel.java	Thu Feb 02 16:15:27 2012 -0500
> +++ b/netx/net/sourceforge/jnlp/NetxPanel.java	Mon Feb 13 15:57:17 2012 +0100
> @@ -35,6 +35,7 @@
>  
>  import sun.applet.AppletViewerPanel;
>  import sun.awt.SunToolkit;
> +import sun.awt.X11.XEmbeddedFrame;
>  
>  /**
>   * This panel calls into netx to run an applet, and pipes the display
> @@ -46,6 +47,7 @@
>      private PluginBridge bridge = null;
>      private boolean exitOnFailure = true;
>      private AppletInstance appInst = null;
> +    private XEmbeddedFrame appletViewerFrame;
>      private boolean appletAlive;
>      private final String uKey;
>  
> @@ -232,4 +234,14 @@
>              SunToolkit.createNewAppContext();
>          }
>      }
> +
> +    public XEmbeddedFrame getAppletViewerFrame() {
> +        return appletViewerFrame;
> +    }
> +
> +    public void setAppletViewerFrame(XEmbeddedFrame appletViewerFrame) {
> +        this.appletViewerFrame = appletViewerFrame;
> +    }
> +
> +    
>  }
> diff -r 528e354ff469 netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java
> --- a/netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java	Thu Feb 02 16:15:27 2012 -0500
> +++ b/netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java	Mon Feb 13 15:57:17 2012 +0100
> @@ -207,6 +207,20 @@
>      }
>  
>      /**
> +     * Set the applet of this environment; can only be called once.
> +     */
> +    public void setApplet(Applet applet) {
> +        if (this.applet != null) {
> +            if (JNLPRuntime.isDebug()) {
> +                Exception ex = new IllegalStateException("Applet can only be set once.");
> +                ex.printStackTrace();
> +            }
> +            return;
> +        }
> +        this.applet = applet;
> +    }
> +
> +    /**
>       * Returns an enumeration that contains only the applet
>       * from the JNLP file.
>       */
> diff -r 528e354ff469 plugin/icedteanp/java/sun/applet/PaintingAndStroking.java
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/plugin/icedteanp/java/sun/applet/PaintingAndStroking.java	Mon Feb 13 15:57:17 2012 +0100
> @@ -0,0 +1,42 @@
> +package sun.applet;
> +
> +import java.awt.BasicStroke;
> +import java.awt.Color;
> +import java.awt.GradientPaint;
> +import java.awt.Graphics;
> +import java.awt.Graphics2D;
> +import java.awt.geom.Ellipse2D;
> +
> +import javax.swing.JFrame;
> + 
> +public class PaintingAndStroking
> +    extends JFrame {
> +  public static void main(String[] args) {
> +    PaintingAndStroking f = new PaintingAndStroking();
> +    f.setTitle("PaintingAndStroking v1.0");
> +    f.setSize(300, 150);
> +    //f.center();
> +    f.setVisible(true);
> +  }
> +  
> +  public void paint(Graphics g) {
> +    Graphics2D g2 = (Graphics2D)g;
> +    double x = 15, y = 50, w = 70, h = 70;
> +    Ellipse2D e = new Ellipse2D.Double(x, y, w, h);
> +    GradientPaint gp = new GradientPaint(75, 75, Color.white,
> +        95, 95, Color.gray, true);
> +    // Fill with a gradient.
> +    //g2.setPaint(gp);
> +    //g2.fill(e);
> +    // Stroke with a solid color.
> +    e.setFrame(x + 100, y, w, h);
> +    g2.setPaint(Color.black);
> +    g2.setStroke(new BasicStroke(8));
> +    //g2.draw(e);
> +    // Stroke with a gradient.
> +    e.setFrame(x + 200, y, w, h);
> +    g2.setPaint(gp);
> +    g2.draw(e);
> +  }
> +}
> +
> diff -r 528e354ff469 plugin/icedteanp/java/sun/applet/PluginAppletViewer.java
> --- a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java	Thu Feb 02 16:15:27 2012 -0500
> +++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java	Mon Feb 13 15:57:17 2012 +0100
> @@ -76,6 +76,7 @@
>  import java.awt.event.WindowListener;
>  import java.awt.print.PageFormat;
>  import java.awt.print.Printable;
> +import java.awt.Component;
>  import java.io.IOException;
>  import java.io.InputStream;
>  import java.io.PrintStream;
> @@ -93,10 +94,8 @@
>  import java.security.PrivilegedExceptionAction;
>  import java.util.Enumeration;
>  import java.util.HashMap;
> -import java.util.Hashtable;
>  import java.util.Iterator;
>  import java.util.Map;
> -import java.util.Vector;
>  
>  import java.util.concurrent.ConcurrentHashMap;
>  import java.util.concurrent.ConcurrentMap;
> @@ -106,6 +105,7 @@
>  import java.util.concurrent.locks.ReentrantLock;
>  
>  import javax.swing.SwingUtilities;
> +import javax.swing.JPanel;
>  
>  import net.sourceforge.jnlp.NetxPanel;
>  import net.sourceforge.jnlp.runtime.JNLPClassLoader;
> @@ -115,6 +115,8 @@
>  import sun.misc.Ref;
>  
>  import com.sun.jndi.toolkit.url.UrlUtil;
> +import java.util.Hashtable;
> +import java.util.Vector;
>  
>  /**
>   * Lets us construct one using unix-style one shot behaviors
> @@ -145,7 +147,12 @@
>              @Override public void run() {
>                  panel.createNewAppContext();
>                  // create the frame.
> -                PluginAppletViewer.framePanel(identifier, handle, panel);
> +                int width = Integer.parseInt(atts.get("width"));
> +                int height = Integer.parseInt(atts.get("height"));
> +
> +                PluginDebug.debug("X and Y are: " + width + " " + height);
> +                panel.setAppletViewerFrame(PluginAppletViewer.framePanel(identifier,handle, width, height, panel));
> +
>                  panel.init();
>                  // Start the applet
>                  initEventQueue(panel);
> @@ -198,6 +205,8 @@
>              ie.printStackTrace();
>          }
>  
> +        ((PluginAppletViewer)(panel.getAppletViewerFrame())).removeSplash();
> +
>          AppletSecurityContextManager.getSecurityContext(0).associateSrc(panel.getAppletClassLoader(), doc);
>          AppletSecurityContextManager.getSecurityContext(0).associateInstance(identifier, panel.getAppletClassLoader());
>  
> @@ -323,26 +332,32 @@
>      private Image bufFrameImg;
>      private Graphics bufFrameImgGraphics;
>  
> +
> +    private PluginSplashPanel splashPanel;
> + 
>      /**
>       * Null constructor to allow instantiation via newInstance()
>       */
>      public PluginAppletViewer() {
>      }
>  
> -    public static void framePanel(int identifier, long handle, NetxPanel panel) {
> +     public static PluginAppletViewer framePanel(int identifier,long handle, int width, int height, NetxPanel panel) {
>  
>          PluginDebug.debug("Framing ", panel);
> -
> -        // SecurityManager MUST be set, and only privileged code may call reFrame()
> + 
> +        // SecurityManager MUST be set, and only privileged code may call framePanel()
>          System.getSecurityManager().checkPermission(new AllPermission());
>  
>          PluginAppletViewer appletFrame = new PluginAppletViewer(handle, identifier, panel);
> -
> -        appletFrame.add("Center", panel);
> -        appletFrame.pack();
> -
> +        
>          appletFrame.appletEventListener = new AppletEventListener(appletFrame, appletFrame);
>          panel.addAppletListener(appletFrame.appletEventListener);
> +         // Clear bindings, if any
> +        if (applets.containsKey(identifier)) {
> +            PluginAppletViewer oldFrame = applets.get(identifier);            
> +            oldFrame.remove(panel);
> +            panel.removeAppletListener(oldFrame.appletEventListener);
> +        }
>  
>          appletsLock.lock();
>          applets.put(identifier, appletFrame);
> @@ -350,6 +365,7 @@
>          appletsLock.unlock();
>  
>          PluginDebug.debug(panel, " framed");
> +               return appletFrame;
>      }
>  
>      /**
> @@ -383,7 +399,53 @@
>          };
>  
>          addWindowListener(windowEventListener);
> +        final AppletPanel fPanel = panel;
> +        try {
> +            SwingUtilities.invokeAndWait(new Runnable() {
> +                public void run() {
> +                    add("Center", fPanel);
> +                    fPanel.setVisible(false);
>  
> +                    splashPanel = new PluginSplashPanel(fPanel.getWidth(), fPanel.getHeight());
> +                    splashPanel.spin();
> +                    PluginDebug.debug("Added splash " + splashPanel);
> +
> +                    add("Center", splashPanel);
> +                    pack();
> +                }
> +            });
> +        } catch (Exception e) {
> +            e.printStackTrace(); // Not much we can do other and print
> +        }
> +
> +    }
> +
> +    public void removeSplash() {
> +
> +        // Loading done. Remove splash screen.
> +        splashPanel.stopSpinning();
> +
> +        try {
> +            SwingUtilities.invokeAndWait(new Runnable() {
> +                public void run() {
> +                    splashPanel.setVisible(false);
> +                    remove(splashPanel);
> +
> +                    // Re-add the applet
> +                    remove(panel);
> +                    add(panel);
> +                    panel.setVisible(true);
> +                    pack();
> +                }
> +            });
> +        } catch (Exception e) {
> +            e.printStackTrace(); // Not much we can do other and print
> +        }
> +    }
> +
> +    public void showErrorSplash () {
> +        splashPanel.stopSpinning();
> +        splashPanel.showError();
>      }
>  
>      private static class AppletEventListener implements AppletListener {
> @@ -436,6 +498,14 @@
>  
>                      break;
>                  }
> +                case AppletPanel.APPLET_START: {
> +                    PluginDebug.debug("Error detected");
> +                    if (src.status != AppletPanel.APPLET_INIT && src.status != AppletPanel.APPLET_STOP) {
> +                        appletViewer.showErrorSplash();
> +                    }
> +
> +                    break;
> +                }
>              }
>          }
>      }
> @@ -517,6 +587,10 @@
>                  waitForAppletInit(applets.get(identifier).panel);
>  
>                  // Should we proceed with reframing?
> +                //appletFrame.removeSplash();
> +                //framePanel(identifier, oldFrame.statusMsgStream, handle, applets.get(identifier).panel);
> +                System.err.println("Init complete");
> +
>                  if (updateStatus(identifier, PAV_INIT_STATUS.REFRAME_COMPLETE).equals(PAV_INIT_STATUS.INACTIVE)) {
>                      destroyApplet(identifier);
>                      return;
> @@ -656,6 +730,8 @@
>       */
>      public static void waitForAppletInit(NetxPanel panel) {
>  
> +        System.err.println("Waiting for applet init");
> +
>          // Wait till initialization finishes
>          long maxTimeToSleep = APPLET_TIMEOUT;
>  
> @@ -2097,7 +2173,7 @@
>       * the parent class's update() just does a couple of checks (both of
>       * which are accounted for) and then calls paint anyway.
>       */
> -    public void update(Graphics g) {
> +    public void paint(Graphics g) {
>  
>          // If the image or the graphics don't exist, create new ones
>          if (bufFrameImg == null || bufFrameImgGraphics == null) {
> @@ -2106,11 +2182,21 @@
>          }
>  
>          // Paint off-screen
> -        paint(bufFrameImgGraphics);
> +        for (Component c: this.getComponents()) {
> +                c.update(bufFrameImgGraphics);
> +        }
>  
>          // Draw the painted image
>          g.drawImage(bufFrameImg, 0, 0, this);
>      }
> +  
> +    public void update(Graphics g) {
> +        paint(g);
> +    }
> +
> +    private class PluginAppletPanel extends JPanel {
> +        // Nothing to do . Yet..
> +    }
>  
>      /**
>       * Waits on a given condition queue until timeout.
> diff -r 528e354ff469 plugin/icedteanp/java/sun/applet/PluginSplashPanel.java
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/plugin/icedteanp/java/sun/applet/PluginSplashPanel.java	Mon Feb 13 15:57:17 2012 +0100
> @@ -0,0 +1,579 @@
> +package sun.applet;
> +
> +import java.awt.BasicStroke;
> +import java.awt.Color;
> +import java.awt.Font;
> +import java.awt.FontMetrics;
> +import java.awt.Graphics;
> +import java.awt.Graphics2D;
> +import java.awt.Image;
> +import java.awt.Point;
> +import java.awt.RadialGradientPaint;
> +import java.awt.RenderingHints;
> +import java.awt.event.ComponentEvent;
> +import java.awt.event.ComponentListener;
> +import java.awt.geom.Ellipse2D;
> +import java.awt.geom.Point2D;
> +import java.awt.geom.RectangularShape;
> +import java.awt.geom.RoundRectangle2D;
> +import java.awt.image.BufferedImage;
> +
> +import javax.swing.JComponent;
> +import javax.swing.SwingUtilities;
> +import javax.swing.text.AttributeSet.ColorAttribute;
> +
> +public class PluginSplashPanel extends JComponent {
> +
> +    /** Width of the plugin window */
> +    private int pluginWidth;
> +
> +	/** Height of the plugin window */
> +	private int pluginHeight;
> +
> +    /** Position of the spinner (angle in degrees) */
> +    private int spinnerPos = 0;
> +
> +	/** How much the spinner should move in each time slice */
> +	private static final int spinFactor = 1;
> +
> +	/** Frequency (per X iterations) at which dot animation moves forward */
> +	private static final int dotAnimationFrequency = 18;
> +	
> +    /** The project name to display */
> +    private static final String projDisplayName = "IcedTea-Web Plugin";
> +    
> +    /** The loading message */
> +    private static final String loadingMsg = "Loading";
> +    
> +	/** The animated applet loading message (....'s are animated) */
> +	private static final String animatedLoadingMsg = loadingMsg + "....";
> +	
> +	/** Number of dots after the loading message (to animate it) */
> +	private int numDotsAfterLoadingMsg;
> +
> +	/** Dark color of icedtea */
> +	private Color darkIcedTeaColor = new Color(84, 0, 0);
> +	
> +	/** Light color of icedtea */
> +	private Color lightIcedTeaColor = new Color(217, 191, 55);
> +	
> +    /** The corner width for the rectangles */
> +	private int rectangleArcWidth;
> +
> +	/** The inner rectangle */
> +	private RectangularShape innerRectangle;
> +	   
> +    /** The shadow of the inner rectangle */
> +    private RectangularShape shadowRectangle;
> +    
> +    /** Returns the center circle */
> +    private Ellipse2D centerCircle;
> +
> +    /** Size of the shadow */
> +   	private int shadowSize;
> +
> +   	/** Whether to keep spinning */
> +   	volatile boolean spin = true;
> +
> +   	/** The background image (everything but the spinner) */
> +	private BufferedImage panelBG;
> +
> +	/** Image where everything is drawn off-screen */
> +	private Image bufferedPanelImage;
> +
> +	/** Graphics associated with the off-screen drawing image */
> +	private Graphics bufferedImageGraphics;
> +
> +	/** Minimum height/width for spinner */
> +	private static final int minSizeForSpinner = 120;
> +
> +	/** The minimum dimension (height of width) */
> +	private int minDimension;
> +	
> +	/**
> +	 * Constructor. Takes an initial size for the panel and sets up listeners for resize
> +	 * 
> +	 * @param initialPluginWidth The initial width of the plugin/panel
> +	 * @param initialPluginHeight The initial height of the plugin/panel
> +	 */
> +	public PluginSplashPanel(final int initialPluginWidth, final int initialPluginHeight) {
> +	    
> +	    // Adjust vars based on initial size
> +	    adjustForSize(initialPluginWidth, initialPluginHeight);
> +	    
> +	    // Add a new listener for resizes
> +	    addComponentListener(new ComponentListener() {
> +            
> +	        // Nothing to do for this
> +            @Override
> +            public void componentShown(ComponentEvent e) {
> +            }
> +
> +            // Re-adjust variables based on size
> +            @Override
> +            public void componentResized(ComponentEvent e) {
> +                adjustForSize(getWidth(), getHeight());
> +            }
> +
> +            // Nothing to do for this
> +            @Override
> +            public void componentMoved(ComponentEvent e) {
> +            }
> +
> +            // Nothing to do for this
> +            @Override
> +            public void componentHidden(ComponentEvent e) {
> +            }
> +        });
> +	    
> +	}
> +
> +	/**
> +	 * Adjusts drawing related variables based on size of the panel
> +	 * 
> +	 * @param pluginWidth The width of the panel
> +	 * @param pluginHeight The height of the panel
> +	 */
> +	private void adjustForSize(int pluginWidth, int pluginHeight) {
> +	    
> +	    // Set the class-wide variables
> +	    this.pluginWidth = pluginWidth;
> +	    this.pluginHeight = pluginHeight;
> +
> +	    // The minimum dimension (either height or width)
> +	    minDimension = Math.min(pluginHeight, pluginWidth);
> +
> +	    // The arc-width -- default is 20, but set to 0 (sharp corners) if panel is too small
> +	    rectangleArcWidth = 20;
> +	    rectangleArcWidth = minDimension >= rectangleArcWidth*2 ? rectangleArcWidth : 0;
> +
> +	    // Size of the simulated shadow cast
> +	    shadowSize = Math.max(minDimension/20, 5);
> +
> +	    // The shadow rectangle shape
> +	    shadowRectangle = getShadowRectangle(new Point(shadowSize, shadowSize));
> +	    
> +	    // The inner (reddish-maroon) box
> +	    innerRectangle = getInnerRect(new Point(0, 0));
> +	    
> +	    // The circle in the center around which the spinner runs
> +	    centerCircle = getCenterCircle();
> +
> +	    // Calculate how many dots after the loading message (so that we can animate that)
> +	    // Do it in a quick and dirty way.. this code is called only once per splash
> +
> +	    String loadingMsgCopy = new String(animatedLoadingMsg);
> +	    numDotsAfterLoadingMsg = 0;
> +	    while (loadingMsgCopy.endsWith(".")) {
> +
> +	        // shorten string by 1
> +	        loadingMsgCopy = loadingMsgCopy.substring(0, loadingMsgCopy.length()-1);
> +
> +	        // increment dot count
> +	        numDotsAfterLoadingMsg++;
> +	    }
> +
> +	    // The background panel (all the satic stuff is pre-drawn for speed)
> +	    panelBG = getBufferedBgImage(false);
> +	}
> +
> +	/**
> +	 * Methods to start the animation in the splash panel.
> +	 * 
> +	 * This method exits after starting a new thread to do the animation. It 
> +	 * is synchronized to prevent multiple spin threads from being created.
> +	 */
> +	public void spin () {
> +
> +	    /* If already spinning, don't do it again */
> +	    //if (spin)
> +	      //  return;
> +
> +	    // Create a new thread to increment spinFactor and repaint
> +		Thread t = new Thread () {
> +
> +			 public void run() {
> +
> +			     // While spinning
> +				 while (spin) {
> +					 try {
> +
> +					     // Reset spinner if we have crossed 360
> +						 if (spinnerPos > 360) {
> +							 spinnerPos = 0;
> +						 }
> +
> +						 // Move 1 degree per spin
> +						 spinnerPos += spinFactor;
> +
> +						 SwingUtilities.invokeAndWait(new Runnable() {
> +							 public void run() {
> +
> +							     // Force repaint
> +								 repaint();
> +							 }
> +						 });
> +
> +						 Thread.currentThread().sleep(30);
> +						 
> +						 if (spinnerPos%30 == 0) {
> +						     PluginDebug.debug(this + "spinning...");
> +						 }
> +					 } catch (Exception e) {
> +						 e.printStackTrace();
> +					 }
> +				 }
> +			 }
> +		};
> +		
> +		t.start(); // Start spinning
> +	}
> +
> +	/**
> +	 * Stops the animation
> +	 */
> +	public void stopSpinning() {
> +		spin = false;
> +	}
> +	
> +	/**
> +	 * Shows an error message 
> +	 */
> +	public void showError() {
> +	    panelBG = getBufferedBgImage(true);
> +	    repaint();
> +	}
> +
> +	/**
> +	 * Creates a background image with non-animated components and returns it
> +	 * 
> +	 * @param errorBg Boolean indicating if the background is for an error. 
> +	 * True indicates error background.
> +	 * 
> +	 * @return The background image
> +	 */
> +	public BufferedImage getBufferedBgImage(boolean errorBg) {
> +
> +	    // New static image for bg and text, so we don't have to redraw
> +		BufferedImage bi = new BufferedImage(pluginWidth, pluginHeight, BufferedImage.TYPE_INT_RGB);
> +
> +		// The graphics instance for the image
> +		Graphics2D g2d = (Graphics2D) bi.getGraphics();
> +
> +        // Text should look nice. Anti-alias it
> +        Object defaultAntialias = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
> +        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> +               	 			 RenderingHints.VALUE_ANTIALIAS_ON);
> +
> +        // Start drawing the elements. Complex drawing is split off 
> +        // into smaller functions, rest is done here
> +
> +        // == Back ground ==
> +        // First, paint a while background
> +        g2d.setPaint(new Color(255, 255, 255));
> +     	g2d.fillRect(0, 0, pluginWidth, pluginHeight);
> +
> +     	// == Shadow ==
> +       	drawShadow(g2d);
> +
> +        // == Inner rectangle ==
> +        // Set the rectangle color. Reddish-maroon for normal, dark gray for error
> +       	if (errorBg)
> +       	    g2d.setPaint(Color.DARK_GRAY);
> +       	else
> +       	    g2d.setPaint(darkIcedTeaColor);
> +
> +       	// Fill the inner rectangle with the above color
> +        g2d.fill(innerRectangle);
> +
> +        // == Project logo ==
> +        drawTextAroundCenter(g2d, -0.5, 0, projDisplayName);
> +
> +     	// == center circle ==
> +        if (!errorBg && minDimension >= minSizeForSpinner)
> +            drawCenterCircle(g2d);
> +
> +        // If there is an error, draw text as well
> +        if (errorBg)
> +            drawTextAroundCenter(g2d, 0, 0, "Loading failed");
> +
> +        // Set anti-aliasing back to whatever it was
> +        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, defaultAntialias);
> +
> +		return bi;
> +	}
> +	
> +	/**
> +	 * Returns the shadow shadow for the main rectangle
> +	 * 
> +	 * @param topLeft The start (top-left) co-ordinates of the shadow
> +	 * @return The shadow rectangle shape
> +	 */
> +	private RectangularShape getShadowRectangle(Point topLeft) {
> +
> +        // The height and width of the shadow
> +        
> +        // When computing shadow size, we want to deduct from the applet size:
> +        //   1) The top left starting point
> +        //   2) The thickness of the shadow (since we use stroke to blend into a white bg)
> +
> +        int shadowHeight = pluginHeight-topLeft.x-shadowSize;
> +        int shadowWidth = pluginWidth-topLeft.y-shadowSize;
> +
> +        return new RoundRectangle2D.Double(topLeft.x, topLeft.y, 
> +                                           shadowWidth, shadowHeight,
> +                                           rectangleArcWidth, rectangleArcWidth);
> +	}
> +	
> +	/**
> +	 * Returns the main rectangle shape
> +	 * 
> +	 * @param topLeft The start (top-left) co-ordinates of the rectangle
> +	 * @return The main rectangle shape
> +	 */
> +	private RectangularShape getInnerRect(Point topLeft) {
> +
> +        // When computing rect size, we want to deduct from the applet size:
> +        //   1) The top left starting point
> +        //   2) The thickness of the shadow
> +
> +        int rectHeight = pluginHeight - topLeft.x - shadowSize;
> +        int rectWidth = pluginWidth - topLeft.y - shadowSize;
> +
> +        return new RoundRectangle2D.Double(topLeft.x, topLeft.y, 
> +                                           rectWidth, rectHeight,
> +                                           rectangleArcWidth, rectangleArcWidth);
> +	}
> +	
> +	/**
> +	 * Returns the center circle around which the glowing sphere spins 
> +	 * 
> +	 * @return The circle shape
> +	 */
> +	private Ellipse2D getCenterCircle() {
> +
> +        // Radius should be decided by min of height/width
> +        int diameter = Math.min((int) innerRectangle.getHeight(), (int) innerRectangle.getWidth());
> +        diameter -= shadowSize*2; // Enough padding on all sides so that the glow stays in 
> +
> +        // Center of the rectangle
> +        Point innerRectCenter = new Point((int) innerRectangle.getCenterX(), (int) innerRectangle.getCenterY());
> +
> +        // Compute the top left point for the ellipse
> +        Point topLeft = new Point(innerRectCenter.x - (int) (diameter/2), innerRectCenter.y - (int) (diameter/2));
> +
> +        return new Ellipse2D.Double(topLeft.x, topLeft.y, diameter, diameter);
> +	}
> +
> +	/**
> +	 * Draws the shadow for the main rectangle 
> +	 * 
> +	 * @param g2d The Graphics2D object in which to draw
> +	 */
> +	private void drawShadow(Graphics2D g2d) {
> +	    
> +	    /* Successively stroke with different colors from white 
> +         * to black, with white being the thickest stroke and black being 
> +         * the thinnest. This approach makes rendering a lot faster than 
> +         * using alpha composites.
> +         */
> +        for (int width=shadowSize; width > 0; width--) {
> +            g2d.setColor(new Color((float) width/shadowSize, (float) width/shadowSize, (float) width/shadowSize));
> +            g2d.setStroke(new BasicStroke(width));
> +            g2d.draw(shadowRectangle);          
> +        }
> +	}
> +
> +	/**
> +	 * Draws text around the center area. 
> +	 * 
> +	 * This is a generic function that can draw text in the center as well 
> +	 * as around it vertically (based on the offset). It can also be told 
> +	 * to cut off the last X characters, which makes it useful for drawing 
> +	 * animated text content.
> +	 * 
> +	 * @param g2d The Graphics2D object
> +	 * @param heightOffset The offset from the center line in units of font height
> +	 * @param charsToCutOff How many characters to cut off from the string
> +	 * @param msg The text to draw
> +	 */
> +	private void drawTextAroundCenter(Graphics2D g2d, double heightOffset,
> +	                                  int charsToCutOff, String msg) {
> +
> +        // Font color = white
> +        g2d.setPaint(new Color(1.0f,1.0f,1.0f));
> +
> +        // Calculate font size
> +        // First, get the lower bound of height/width
> +        int minSize = Math.min(pluginHeight, pluginWidth);
> +        
> +        // Now, compute font size relative to the min size.
> +        int fontSize = Math.max(minSize/16, 7);
> +
> +        // Set the font
> +        Font msgFont = new Font("Dialog", Font.BOLD, fontSize);
> +        g2d.setFont(msgFont);
> +
> +        // Calculate font location
> +        FontMetrics fontMetrics;
> +        int fontWidth;
> +        int fontHeight;
> +
> +        // Get the rendered font size
> +        g2d.setFont(msgFont);
> +        fontMetrics = g2d.getFontMetrics();
> +        fontWidth = fontMetrics.stringWidth(msg);
> +        fontHeight = fontMetrics.getHeight();
> +
> +        // We now know the center of the rectangle, and the size of the text
> +        // Compute were the font should be drawn
> +
> +        // Horizontally
> +        int fontXLocation = (int) (innerRectangle.getCenterX() - fontWidth/2); // half-width right from center
> +        
> +        // Vertically (center + offset)
> +        int fontYLocation = (int) ((innerRectangle.getCenterY()) + heightOffset*fontHeight);
> +
> +        // Finally, make sure the string will be in bounds
> +        if (innerRectangle.getMinX() > fontXLocation /* top left X */ ||
> +            innerRectangle.getMinY() > fontYLocation /* top left Y */ ||
> +            innerRectangle.getMaxX() < fontXLocation + fontWidth /* bottom right X */ ||
> +            innerRectangle.getMaxY() < fontYLocation + fontHeight /* bottom right Y */)
> +            return;
> +
> +        // Everything is within bounds
> +        g2d.drawString(msg.substring(0, msg.length()-charsToCutOff), fontXLocation, fontYLocation);
> +	}
> +
> +	/**
> +	 * Draws the center circle along which a tiny sphere spins. The drawing is 
> +	 * done in successive steps to give it a soft edge. 
> +	 *  
> +	 *@param g2d The Graphics2D instance to draw onto
> +	 */
> +	private void drawCenterCircle(Graphics2D g2d) {
> +
> +	    // Calculate the thickness of the curcle
> +        int circleThickness = Math.min((int) Math.min(pluginHeight, pluginWidth)/25, shadowSize); // never make it bigger than shadow
> +        
> +        // Keep stroking successively, the higher the stroke 
> +        // width, the lighter the color
> +        for (int width=circleThickness; width > 0; width--) {
> +            g2d.setColor(getCompositedColor(lightIcedTeaColor, darkIcedTeaColor, width, circleThickness));
> +            g2d.setStroke(new BasicStroke(width));
> +            g2d.draw(centerCircle);         
> +        }
> +	}
> +	
> +	/**
> +	 * Function get composite color for use with iterative stroking for a soft edge
> +	 * 
> +	 * This function returns a color between 2 given colors, based on the width of 
> +	 * the stroke (higher width = most toward end color)
> +	 * 
> +	 * @param start The start color
> +	 * @param end The end color
> +	 * @param width The width of the current stroke
> +	 * @param totalWidth Total width across which the stroking will be done
> +	 * @return The resulting composite color
> +	 */
> +	private Color getCompositedColor(Color start, Color end, float width, float totalWidth) {
> +        
> +        // Find the distance between the colors
> +        int rColorDistance = start.getRed() - end.getRed();
> +        int gColorDistance = start.getGreen() - end.getGreen();
> +        int bColorDistance = start.getBlue() - end.getBlue();
> +
> +        // Compute the fraction by which it should be incremented
> +        int rIncr = (int) (((float) rColorDistance * width)/totalWidth);
> +        int gIncr = (int) (((float) gColorDistance * width)/totalWidth);
> +        int bIncr = (int) (((float) bColorDistance * width)/totalWidth);
> +
> +        return new Color(start.getRed() - rIncr, start.getGreen() - gIncr, start.getBlue() - bIncr);
> +	}
> +	
> +	/**
> +	 * Draws the spinner based on spinner position
> +	 * 
> +	 * @param g2d The Graphics2D object to draw on
> +	 */
> +	private void drawSpinner(Graphics2D g2d) {
> +
> +	    // Do nothing when we are not spinning
> +	    if (!spin)
> +	        return;
> +
> +	    // Use anti-aliasing to make things look good
> +        Object defaultAntialias = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
> +        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> +                RenderingHints.VALUE_ANTIALIAS_ON);
> +
> +        /* To show the "...." animation, we want to draw a new dot every 
> +         * X paint calls (where X is perfectly divisible by 360). 
> +         * So divide position by dotAnimationFrequency and mod by number 
> +         * of dots + 1 (the +1 because there are max + 1 states including 
> +         * the case of 0 dots) 
> +         */
> +
> +        // Figure out characters (dots) to cut
> +        int charsToCut = numDotsAfterLoadingMsg /*total */ - 
> +                         (spinnerPos/dotAnimationFrequency)%(numDotsAfterLoadingMsg+1) /* how many to cut off */;
> +
> +        // Draw the text
> +        drawTextAroundCenter(g2d, 0.5, charsToCut, animatedLoadingMsg);
> +
> +        if (minDimension < minSizeForSpinner)
> +            return;
> +
> +	    // In the parametric form, we can compute the positions on the 
> +	    // circumference using the equations:
> +
> +	    // x = x_center + radius*cos(t);
> +	    // y = y_center + radius*sin(t);
> +
> +	    // Where t is the angle from the X axis (in degrees)
> +	    float radius = (float) centerCircle.getWidth()/2;
> +
> +	    int x = (int) (centerCircle.getCenterX() + radius * (Math.cos(Math.toRadians(spinnerPos))));
> +	    int y = (int) (centerCircle.getCenterY() + radius * (Math.sin(Math.toRadians(spinnerPos))));
> +
> +	    // The spinning sphere size
> +	    int sphereSize = (int) (shadowSize);
> +
> +	    // Draw the sphere
> +	    Point2D center = new Point2D.Float(x, y);
> +	    float[] dist = {0.0f, 1.0f};
> +	    Color[] colors = {lightIcedTeaColor, darkIcedTeaColor};
> +	    RadialGradientPaint p = new RadialGradientPaint(center, sphereSize, dist, colors);
> +	    g2d.setPaint(p);
> +	    g2d.fillOval(x-sphereSize, y-sphereSize, sphereSize*2, sphereSize*2);
> +
> +        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, defaultAntialias);
> +	}
> +
> +    @Override
> +    public void paint(Graphics g) {
> +    	
> +    	Graphics2D g2d = (Graphics2D)g;
> +
> +    	// Draw the background
> +        g2d.drawImage(panelBG, 0, 0, null);
> +
> +        // Draw the spinner
> +        drawSpinner(g2d);
> +    }
> +
> +    @Override
> +    public void update (Graphics g) {
> +
> +        // If the buffered image or graphics don't exit, create them
> +        if (bufferedPanelImage == null || bufferedImageGraphics == null) {
> +            bufferedPanelImage = createImage(pluginWidth, pluginHeight);
> +            bufferedImageGraphics = bufferedPanelImage.getGraphics ();
> +        }
> +
> +    	paint(bufferedImageGraphics);
> +    	g.drawImage(bufferedPanelImage, 0, 0, this);
> +    }
> +
> +}
> \ No newline at end of file
> diff -r 528e354ff469 plugin/icedteanp/java/sun/applet/PluginSplashPanel2.java
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/plugin/icedteanp/java/sun/applet/PluginSplashPanel2.java	Mon Feb 13 15:57:17 2012 +0100
> @@ -0,0 +1,273 @@
> +package sun.applet;
> +
> +import java.awt.BasicStroke;
> +import java.awt.Color;
> +import java.awt.Font;
> +import java.awt.FontMetrics;
> +import java.awt.GradientPaint;
> +import java.awt.Graphics;
> +import java.awt.Graphics2D;
> +import java.awt.Image;
> +import java.awt.LinearGradientPaint;
> +import java.awt.MultipleGradientPaint;
> +import java.awt.Paint;
> +import java.awt.Point;
> +import java.awt.Rectangle;
> +import java.awt.RenderingHints;
> +import java.awt.geom.RoundRectangle2D;
> +import java.awt.image.BufferedImage;
> +
> +import javax.swing.JComponent;
> +import javax.swing.SwingUtilities;
> +
> +public class PluginSplashPanel2 extends JComponent {
> +
> +	/** Width of the plugin window */
> +	int pluginWidth;
> +	
> +	/** Height of the plugin window */
> +	int pluginHeight;
> +	
> +	/** Minimum width for text to appear */
> +	int minWidthForText = 140;
> +	
> +	/** Minimum height for text to appear */
> +	int minHeightForText = 65;
> +	
> +	/** The height of the spinners */
> +	int spinnerHeight = 10;
> +
> +	/** The width of each of the spinners */
> +	int spinnerWidth;
> +	
> +	/** How much the bars should move in each time slice */
> +	int spinnerSpinFactor;
> +
> +	/** Font for the plugin name */
> +	Font pluginNameStrFont;
> +
> +	/** Font for the loading msg */
> +	Font loadingMsgFont;
> +
> +	/** The plugin name to display */
> +	String pluginNameStr = "";
> +
> +	/** The applet loading message */
> +	String loadingMsg = "Applet Loading...";
> +	
> +	/** Dark color of icedtea */
> +	Color darkIcedTeaColor = new Color(84, 0, 0);
> +	
> +	/** Light color of icedtea */
> +	Color lightIcedTeaColor = new Color(217, 191, 55);
> +
> + 	Point shadowPosition = new Point(10, 10);
> +   	int shadowSize = 20;
> +   	int spinnerCorePos;
> +   	
> +   	volatile boolean spin = true;
> +	
> +	BufferedImage panelBG;
> +	Image bufferedPanelImage;
> +	Graphics bufferedImageGraphics;
> +	
> +	public PluginSplashPanel2(int pluginWidth, int pluginHeight) {
> +		this.pluginWidth = pluginWidth;
> +		this.pluginHeight = pluginHeight;
> +		
> +		spinnerWidth = pluginWidth/2;
> +		spinnerSpinFactor = pluginWidth/50;
> +
> +		spinnerCorePos = 0;
> +		
> +		int largeFontSize = 25;
> +		int smallFontSize = 15;
> +		
> +		// For each 100 increase above min height and width, increase font by 5
> +		int widthOverMin = pluginWidth - minWidthForText;
> +		int heightOverMin = pluginHeight - minHeightForText;
> +
> +		int sizeIncrease = Math.min(widthOverMin/100, heightOverMin/100)*5;
> +		
> +		largeFontSize += sizeIncrease;
> +		smallFontSize += sizeIncrease;
> +
> +		pluginNameStrFont = new Font("Monospaced", Font.BOLD, largeFontSize);
> +		loadingMsgFont = new Font("Dialog", Font.BOLD, smallFontSize);
> +		
> +		panelBG = getBufferedBgImage();
> +	}
> +
> +	public void spin () {
> +		 int decFactor = -spinnerSpinFactor;
> +
> +		 Thread t = new Thread () {
> +
> +			 public void run() {
> +
> +				 while (spin) {
> +					 try {
> +
> +						 if (spinnerCorePos >= pluginWidth) {
> +							 spinnerCorePos = 0;
> +						 }
> +
> +						 spinnerCorePos += spinnerSpinFactor;
> +
> +						 SwingUtilities.invokeAndWait(new Runnable() {
> +							 public void run() {
> +								 repaint();
> +							 }
> +						 });
> +
> +						 Thread.currentThread().sleep(50);
> +					 } catch (Exception e) {
> +						 e.printStackTrace();
> +					 }
> +				 }
> +			 }
> +		};
> +		
> +		t.start();
> +	}
> +
> +	public void stopSpinning() {
> +		spin = false;
> +	}
> +
> +	/**
> +	 * Creates a background image and returns it
> +	 * 
> +	 * @return The background image
> +	 */
> +	public BufferedImage getBufferedBgImage() {
> +		
> +		BufferedImage bi = new BufferedImage(pluginWidth, pluginHeight, BufferedImage.TYPE_INT_RGB);
> +		int arcWidth = 20;
> +
> +		Graphics2D g2d = (Graphics2D) bi.getGraphics();
> +        
> +        // Text should look nice. Anti-alias it
> +        Object defaultAntialias = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
> +        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> +               	 			 RenderingHints.VALUE_ANTIALIAS_ON);
> +
> +        // white background
> +        g2d.setPaint(new Color(255, 255, 255));
> +     	g2d.fillRect(0, 0, pluginWidth, pluginHeight);
> +
> +        // Create the shadow first
> +       	
> +       	RoundRectangle2D rect = new RoundRectangle2D.Double(
> +       									shadowPosition.x, shadowPosition.y, 
> +       									pluginWidth-shadowPosition.x-shadowSize, 
> +       									pluginHeight-shadowPosition.y-shadowSize,
> +       									arcWidth, arcWidth);
> +        for (int width=shadowSize; width > 0; width--) {
> +        	// Thicker == lighter
> +        	g2d.setColor(new Color((float) width/shadowSize, (float) width/shadowSize, (float) width/shadowSize));
> +        	g2d.setStroke(new BasicStroke(width));
> +        	g2d.draw(rect);        	
> +        }
> +
> +       	// Create the center rectangle
> +        Point rectPosition = new Point(5,5);
> +        rect = new RoundRectangle2D.Double(
> +        						rectPosition.x, rectPosition.y, 
> +        						pluginWidth-rectPosition.x-shadowSize, 
> +        						pluginHeight-rectPosition.y-shadowSize,
> +        						arcWidth, arcWidth);
> +       	g2d.setPaint(new GradientPaint(0, pluginHeight, darkIcedTeaColor, 0, 0, lightIcedTeaColor, false));
> +        g2d.fill(rect);
> +
> +     	// Border for center rectangle with a "glow"
> +     	g2d.setPaint(new Color(1.0f,1.0f,1.0f));
> +       	//g2d.drawRoundRect(5, 5, pluginWidth-30, pluginHeight-30, 20, 20);
> +
> +       	
> +        FontMetrics fontMetrics;
> +        
> +        int fontWidth;
> +        int fontHeight;
> +
> +        // Plugin name is printed only if width and height exceeds a certain size
> +        if (pluginWidth >= 160 && pluginHeight >= 90) {
> +        	g2d.setFont(pluginNameStrFont);
> +        	fontMetrics = g2d.getFontMetrics();
> +        	fontWidth = fontMetrics.stringWidth(pluginNameStr);
> +        	fontHeight = fontMetrics.getAscent();
> +
> +        	/* lower left X */
> +        	int x = pluginWidth/2 - 10 /* center */ - fontWidth/2;
> +        
> +        	/* lower left Y */
> +        	int y = pluginHeight/2 /* center */ - 25 /* center of rectangle */ + fontHeight/2 /* Height of font */;
> +        	if (y >= pluginHeight - 60 /* If it clashes with "Applet Loading..." */ )
> +        		y = pluginHeight - 65;
> +
> +        	g2d.drawString(pluginNameStr, x, y);
> +        }
> +
> +        // Applet loading message is only if width and height exceeds a certain size
> +        
> +        if (pluginWidth >= 140 && pluginHeight >= 65) {
> +        	g2d.setFont(loadingMsgFont);
> +        	fontMetrics = g2d.getFontMetrics();
> +        	fontWidth = fontMetrics.stringWidth(loadingMsg);
> +        	fontHeight = fontMetrics.getAscent();
> +
> +        	g2d.drawString(loadingMsg, pluginWidth-fontWidth-shadowSize-5, pluginHeight - spinnerHeight - shadowSize - 20 /* Padding */);
> +        }
> +
> +        // Done drawing text. Set back to what it was before
> +        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> +	 			 			 defaultAntialias);
> +       	
> +		return bi;
> +		
> +	}
> +
> +    @Override
> +    public void paint(Graphics g) {
> +    	
> +    	Graphics2D g2d = (Graphics2D)g;
> +    	Paint defaultPaint = g2d.getPaint();
> +
> +    	Color centerColor = lightIcedTeaColor;
> +        Color edgeColor = darkIcedTeaColor;
> +    	
> +        g2d.drawImage(panelBG, 0, 0, null);
> +
> +        System.err.println(spinnerCorePos);
> +
> +    	// Create a small rectangle
> +    	Rectangle rect = new Rectangle(5, pluginHeight-shadowSize-spinnerHeight-10, (pluginWidth-shadowSize-5), spinnerHeight);
> +    	
> +    	Color spinnerEdgeColor = new Color(
> +    									darkIcedTeaColor.getRGBColorComponents(null)[0], 
> +    									darkIcedTeaColor.getRGBColorComponents(null)[1], 
> +    									darkIcedTeaColor.getRGBColorComponents(null)[2],
> +    									0.0f);
> +
> +    	//LinearGradientPaint lGp = new LinearGradientPaint((float) spinnerCorePos-100, 0f, (float) spinnerCorePos+100, 0f, new float[]{0.0f, 0.5f, 1.0f}, new Color[]{spinnerEdgeColor, lightIcedTeaColor, spinnerEdgeColor}, MultipleGradientPaint.CycleMethod.NO_CYCLE);
> +    	GradientPaint gp = new GradientPaint((float) spinnerCorePos-100, 0f, lightIcedTeaColor, (float) spinnerCorePos, 0f, darkIcedTeaColor);
> +    	g2d.setPaint(gp);
> +    	g2d.fill(rect);
> +
> +    	PluginDebug.debug("Painted " + g2d.hashCode());
> +    }
> +
> +    public void update (Graphics g) {
> +
> +    	if (bufferedPanelImage == null || bufferedImageGraphics == null) {
> +    		bufferedPanelImage = createImage(pluginWidth, pluginHeight);
> +    		bufferedImageGraphics = bufferedPanelImage.getGraphics ();
> +    	}
> +
> +    	PluginDebug.debug("Updating splash");
> +    	
> +    	paint(bufferedImageGraphics);
> +    	g.drawImage(bufferedPanelImage, 0, 0, this);
> +    }
> +
> +}
> \ No newline at end of file
> diff -r 528e354ff469 plugin/icedteanp/java/sun/applet/PluginSplashPanelTest.java
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/plugin/icedteanp/java/sun/applet/PluginSplashPanelTest.java	Mon Feb 13 15:57:17 2012 +0100
> @@ -0,0 +1,76 @@
> +package sun.applet;
> +import java.awt.BorderLayout;
> +import java.awt.Container;
> +import java.awt.event.ComponentEvent;
> +import java.awt.event.ComponentListener;
> +import java.awt.event.WindowAdapter;
> +import java.awt.event.WindowEvent;
> +
> +import javax.swing.JFrame;
> +import javax.swing.SwingUtilities;
> +
> +
> +public class PluginSplashPanelTest extends JFrame {
> +
> +	static int width = 40; //860;
> +	static int height = 60; //610;
> +
> +	static PluginSplashPanel panel;
> +	
> +	public PluginSplashPanelTest() {
> +
> +		setSize(width, height);
> +		
> +		panel = new PluginSplashPanel(width, height-20);
> +		setLayout(new BorderLayout());
> +		getContentPane().add(panel, BorderLayout.CENTER);
> +
> +		setVisible(true);
> +		
> +	      addComponentListener(new ComponentListener() {
> +	            
> +	            @Override
> +	            public void componentShown(ComponentEvent e) {
> +	            }
> +	            
> +	            @Override
> +	            public void componentResized(ComponentEvent e) {
> +	                panel.setSize(getWidth(), getHeight()-20);
> +	            }
> +
> +	            @Override
> +	            public void componentMoved(ComponentEvent e) {
> +	            }
> +	            
> +	            @Override
> +	            public void componentHidden(ComponentEvent e) {
> +	            }
> +	        });
> +	}
> +
> +	public static void main( String args[] ) {
> +		 PluginSplashPanelTest app = new PluginSplashPanelTest();
> +
> +		 app.addWindowListener(
> +				 new WindowAdapter() {
> +					 public void windowClosing( WindowEvent e )
> +					 {
> +						 System.exit( 0 );
> +					 }
> +				 }
> +		 );
> +		 
> +		 panel.spin();
> +		 
> +		 /*try {
> +		     Thread.sleep(2000);
> +		 } catch (Exception e) {
> +		     
> +		 }
> +
> +		 panel.stopSpinning();
> +		 panel.showError();*/
> +		 
> +	 }
> +}
> +
> diff -r 528e354ff469 tests/netx/jnlp_testsengine/net/sourceforge/jnlp/ServerAccess.java
> --- a/tests/netx/jnlp_testsengine/net/sourceforge/jnlp/ServerAccess.java	Thu Feb 02 16:15:27 2012 -0500
> +++ b/tests/netx/jnlp_testsengine/net/sourceforge/jnlp/ServerAccess.java	Mon Feb 13 15:57:17 2012 +0100
> @@ -53,6 +53,7 @@
>  import java.net.MalformedURLException;
>  import java.net.ServerSocket;
>  import java.net.Socket;
> +import java.net.SocketException;
>  import java.net.URI;
>  import java.net.URL;
>  import java.net.URLDecoder;
> @@ -117,11 +118,27 @@
>  
>      /**
>       * main method of thos class prints out random free port
> +     * or runs server
> +     * param "port" prints out the port
> +     * nothing or number will run  sefrver on random(or on number specified)
> +     * port in -Dtest.server.dir
>       */
> -    public static void main(String[] args) throws IOException {
> -        int i = findFreePort();
> -        System.out.println(i);
> +    public static void main(String[] args) throws Exception {
> +        if (args.length > 0 && args[0].equalsIgnoreCase("port")) {
> +            int i = findFreePort();
> +            System.out.println(i);
> +            System.exit(0);
> +        } else {
> +            int port = 44321;
> +            if (args.length > 0) {
> +                port=new Integer(args[0]);
> +            }
> +            getIndependentInstance(port);
> +            while (true) {
> +                Thread.sleep(1000);
> +            }
>  
> +        }
>      }
>  
>      /**
> @@ -167,7 +184,22 @@
>       */
>      public static ServerLauncher getIndependentInstance() {
>          String dir = (System.getProperty(TEST_SERVER_DIR));
> -        return getIndependentInstance(dir);
> +        try{
> +        return getIndependentInstance(dir, findFreePort());
> +        }catch (Exception ex){
> +            throw  new RuntimeException(ex);
> +        }
> +    }
> +
> +
> +    /**
> +     *
> +     * @return new not cached iserver instance on random port,
> +     * usefull for testing application loading from different url then base
> +     */
> +    public static ServerLauncher getIndependentInstance(int port) {
> +        String dir = (System.getProperty(TEST_SERVER_DIR));
> +        return getIndependentInstance(dir,port);
>      }
>  
>      /**
> @@ -175,14 +207,13 @@
>       * @return new not cached iserver instance on random port upon custom www root directory,
>       * usefull for testing application loading from different url then base
>       */
> -    public static ServerLauncher getIndependentInstance(String dir) {
> +    public static ServerLauncher getIndependentInstance(String dir, int port) {
>  
>  
>          if (dir == null || dir.trim().length() == 0 || !new File(dir).exists() || !new File(dir).isDirectory()) {
>              throw new RuntimeException("test.server.dir property must be set to valid directory!");
>          }
>          try {
> -            int port = findFreePort();
>              ServerLauncher lServerLuncher = new ServerLauncher(port, new File(dir));
>              new Thread(lServerLuncher).start();
>              return lServerLuncher;
> @@ -314,6 +345,13 @@
>          Assert.assertEquals(new File(dirUrlContent.trim()), server.getDir());
>          Assert.assertEquals(new Integer(portUrlContent.trim()), server.getPort());
>  
> +         URL fastUrl = new URL("http", "localhost", server.getPort(), "/simpletest1.jnlp");
> +         URL slowUrl = new URL("http", "localhost", server.getPort(), "/XslowXsimpletest1.jnlp");
> +
> +        String fastUrlcontent = getContentOfStream(fastUrl.openConnection().getInputStream());
> +        String slowUrlContent = getContentOfStream(slowUrl.openConnection().getInputStream());
> +        Assert.assertEquals(fastUrlcontent, slowUrlContent);
> +
>      }
>  
>      /**
> @@ -789,6 +827,7 @@
>              private final File dir;
>              private final int port;
>              private boolean canRun = true;
> +            private static final String XSX="/XslowX";
>  
>              public void setCanRun(boolean canRun) {
>                  this.canRun = canRun;
> @@ -819,7 +858,9 @@
>                              if (s.startsWith("GET")) {
>                                  StringTokenizer t = new StringTokenizer(s, " ");
>                                  t.nextToken();
> -                                String p = t.nextToken();
> +                                String op = t.nextToken();
> +                                String p = op;
> +                                if (p.startsWith(XSX))p=p.replace(XSX, "/");
>                                  System.err.println("Getting: "+p);
>                                  p=URLDecoder.decode(p, "UTF-8");
>                                  System.err.println("Serving: "+p);
> @@ -832,9 +873,20 @@
>                                  f.read(b);
>                                  o.writeBytes("HTTP/1.0 200 OK\nConten"
>                                          + "t-Length:" + l + "\n\n");
> +                                if (op.startsWith(XSX)){
> +                                    byte[][] bb=ServerAccess.splitArray(b,10);
> +                                    for (int j = 0; j < bb.length; j++) {
> +                                        Thread.sleep(2000);
> +                                        byte[] bs = bb[j];
> +                                        o.write(bs, 0, bs.length);
> +                                    }
> +                                }else{
>                                  o.write(b, 0, l);
> +                                }
>                              }
>                          }
> +                    }catch (SocketException e) {
> +                        e.printStackTrace();
>                      } catch (Exception e) {
>                          o.writeBytes("HTTP/1.0 404 ERROR\n\n\n");
>                          e.printStackTrace();
> @@ -847,6 +899,89 @@
>          }
>      }
>  
> +    private static byte[][] splitArray(byte[] b, int i) {
> +
> +                byte[][] r=new byte[i][0];
> +                int ln=b.length % (i);
> +                int l1=(b.length) / (i);
> +                if (ln==0){
> +                    ln=l1;
> +                }else{
> +                    l1=l1+1;
> +                    ln=b.length%l1;;
> +                }
> +              for (int j = 0; j < r.length; j++) {
> +               if (j==r.length-1){
> +                r[j]=new byte[ln];
> +               }else{
> +               r[j]=new byte[l1];
> +               }
> +               byte[] q=r[j];
> +               for (int x=0; x< q.length;x++){
> +                   q[x]=b[x+l1*j];
> +               }
> +
> +
> +        }
> +                return r;
> +            }
> +
> +     @Test
> +    public void splitArrayTest0() throws Exception {
> +         byte[] b={1,2,3,4,5,6,7,8,9,10,11,12,13,14};
> +         byte[][] bb=splitArray(b, 3);
> +        //printArrays(bb);
> +        byte[] b1={1,2,3,4,5};
> +        byte[] b2={6,7,8,9,10};
> +        byte[] b3={11,12,13,14};
> +        Assert.assertEquals(3,bb.length);
> +        Assert.assertArrayEquals(b1,bb[0]);
> +        Assert.assertArrayEquals(b2,bb[1]);
> +        Assert.assertArrayEquals(b3,bb[2]);
> +     }
> +
> +     @Test
> +    public void splitArrayTest1() throws Exception {
> +         byte[] b={1,2,3,4,5,6,7,8,9,10,11,12,13};
> +         byte[][] bb=splitArray(b, 3);
> +        //printArrays(bb);
> +         byte[] b1={1,2,3,4,5};
> +        byte[] b2={6,7,8,9,10};
> +        byte[] b3={11,12,13};
> +        Assert.assertEquals(3,bb.length);
> +        Assert.assertArrayEquals(b1,bb[0]);
> +        Assert.assertArrayEquals(b2,bb[1]);
> +        Assert.assertArrayEquals(b3,bb[2]);
> +     }
> +
> +      @Test
> +    public void splitArrayTest2() throws Exception {
> +         byte[] b={1,2,3,4,5,6,7,8,9,10,11,12};
> +         byte[][] bb=splitArray(b, 3);
> +        //printArrays(bb);
> +        byte[] b1={1,2,3,4};
> +        byte[] b2={5,6,7,8};
> +        byte[] b3={9,10,11,12};
> +        Assert.assertEquals(3,bb.length);
> +        Assert.assertArrayEquals(b1,bb[0]);
> +        Assert.assertArrayEquals(b2,bb[1]);
> +        Assert.assertArrayEquals(b3,bb[2]);
> +     }
> +
> +    private void printArrays(byte[][] bb) {
> +        System.out.println("[][] l=" + bb.length);
> +        for (int i = 0; i < bb.length; i++) {
> +            byte[] bs = bb[i];
> +            System.out.println(i + ": l=" + bs.length);
> +            for (int j = 0; j < bs.length; j++) {
> +                byte c = bs[j];
> +                System.out.print(" " + j + ":" + c + " ");
> +            }
> +            System.out.println("");
> +        }
> +    }
> +
> +
>      /**
>       * class which timeout any ThreadedProcess. This killing of 'theread with process' replaced not working process.destroy().
>       */

>                               Resultant of Forces
>                              (Addition of Vectors)
> 
>                               Resultant of Forces
>                              (Addition of Vectors)

> #!/bin/bash
> 
> JAVA=/usr/lib/jvm/java-openjdk/jre/bin/java
> LAUNCHER_BOOTCLASSPATH="-Xbootclasspath/a:/home/jvanek/icedtea-web-image/share/icedtea-web/netx.jar:/usr/share/java/js.jar"
> LAUNCHER_FLAGS=-Xms8m
> CLASSNAME=net.sourceforge.jnlp.runtime.Boot
> BINARY_LOCATION=/home/jvanek/icedtea-web-image/bin/javaws
> PROGRAM_NAME=javaws
> CP=/usr/lib/jvm/java-openjdk/jre/lib/rt.jar
> 
> JAVA_ARGS=( )
> ARGS=( )
> COMMAND=()
> 
> i=0
> j=0
> 
> SPLASH="true"
> while [ "$#" -gt "0" ]; do
>   case "$1" in
>     -J*)
>       JAVA_ARGS[$i]="${1##-J}"
>       i=$((i+1))
>       ;;
>     *)
>       ARGS[$j]="$1"
>       j=$((j+1))
>       if [ "$1" = "-headless" ] ; then
>         SPLASH="false"
>       fi
>       ;;
>   esac
>   shift
> done
> 
> k=0
> COMMAND[k]="${JAVA}"
> k=$((k+1))
> if [ "$SPLASH" = "true" ] ; then
> COMMAND[k]="-splash:/home/jvanek/icedtea-web-image/bin/netxPlugin.png"
> k=$((k+1))
> fi;
> COMMAND[k]="${LAUNCHER_BOOTCLASSPATH}"
> k=$((k+1))
> COMMAND[k]="${LAUNCHER_FLAGS}"
> k=$((k+1))
> i=0
> while [ "$i" -lt "${#JAVA_ARGS[@]}" ]; do
>   COMMAND[k]="${JAVA_ARGS[$i]}"
>   i=$((i+1))
>   k=$((k+1))
> done
> COMMAND[k]="-classpath"
> k=$((k+1))
> COMMAND[k]="${CP}"
> k=$((k+1))
> COMMAND[k]="-Dicedtea-web.bin.name=${PROGRAM_NAME}"
> k=$((k+1))
> COMMAND[k]="-Dicedtea-web.bin.location=${BINARY_LOCATION}"
> k=$((k+1))
> COMMAND[k]="${CLASSNAME}"
> k=$((k+1))
> j=0
> while [ "$j" -lt "${#ARGS[@]}" ]; do
>   COMMAND[k]="${ARGS[$j]}"
>   j=$((j+1))
>   k=$((k+1))
> done
> 
> "${COMMAND[@]}"
> 
> exit $?




More information about the distro-pkg-dev mailing list