[rfc][icedtea-web] plugin splash screen

Deepak Bhole dbhole at redhat.com
Tue Feb 14 11:47:51 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....

I wanted to do something similar, so definitely +1 :) I was thinking of
using the same shadowed rounded rectangle that the loading screen shows,
but with red color and different text inside.

> - 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)

javaws applications can already specify their own splash screen -- you
mean we should show one before that?

> - 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.
> 

Oh yeah, my work was pretty much a PoC. A more pretty splash screen is
quite welcome :)

> 
> 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