home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / Bitmap.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  32.6 KB  |  908 lines  |  [TEXT/CWIE]

  1. // Bitmap.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9. import java.awt.MediaTracker;
  10. import java.awt.image.ImageObserver;
  11. import java.net.URL;
  12.  
  13.  
  14. /** Image subclass that draws bitmapped data.  Typically, you retrieve a
  15.   * Bitmap by name from a GIF file:
  16.   * <pre>
  17.   *     bitmap = Bitmap.bitmapNamed("ColorBackground.gif");
  18.   * </pre>
  19.   * You can also use a Bitmap for offscreen drawing.  You can construct a
  20.   * Graphics object to draw into a Bitmap using the code:
  21.   * <pre>
  22.   *     bitmap = new Bitmap(width, height);
  23.   *     g = new Graphics(bitmap);
  24.   * </pre>
  25.   * @note 1.0 added alert images and keyboard arrow images to system images
  26.   * @note 1.0 added primative namedBitmap() to take cache flag, changed
  27.   *           conviences to call new primative. This will allow users to
  28.   *           create images that will be released.
  29.   * @note 1.0 getPixels will block until finished instead of 40ms timeout
  30.   * @note 1.1 references to mediaTracker and bitmapObserver are removed after loading
  31.   */
  32. public class Bitmap extends Image {
  33.     java.awt.Image      awtImage;
  34.     BitmapObserver      bitmapObserver;
  35.     Target              updateTarget;
  36.     Rect                updateRect;
  37.     String              name, updateCommand;
  38.     int                 imageNumber;
  39.     boolean             loaded = false, valid = true, transparent = true,
  40.                         loadIncrementally, added;
  41.     boolean             useStaticTracker = false;
  42.     java.awt.MediaTracker mediaTracker;
  43.  
  44.     final static int    WIDTH = 0, HEIGHT = 1;
  45.  
  46.     // Codable information
  47.  
  48.     private static Class bitmapClass;
  49.  
  50.     final static String NAME_KEY = "name";
  51.     final static String UPDATE_TARGET_KEY = "updateTarget";
  52.     final static String UPDATE_COMMAND_KEY = "updateCommand";
  53.     final static String TRANSPARENT_KEY = "transparent";
  54.     final static String LOAD_INCREMENTALLY_KEY = "loadIncrementally";
  55.  
  56. /* static methods */
  57.  
  58.     /** Returns the Bitmap named <b>bitmapName</b>. The application maintains
  59.       * a cache of named Bitmaps that it checks first.  If not located in
  60.       * the cache, this method looks for the specified bitmap in the "images"
  61.       * directory in the same directory as the Application's index.html
  62.       * file.  In other words, it constructs the URL
  63.       * <pre>
  64.       *     "codebase"/images/bitmapName
  65.       * </pre>
  66.       * and attempts to load this image.  <b>bitmapName</b> can specify a
  67.       * file name or path, such as "newImages/ColorBackground.gif".
  68.       * This method starts loading the bitmap's data if <b>startLoading</b> is
  69.       * <b>true</b>.  Otherwise, the IFC retrieves the data when needed.
  70.       * If <b>cache</b> is true the bitmap will be added to an Application
  71.       * cache for faster future lookups. Images placed in the cache are not
  72.       * released for the lifetime of the Application object. If <b>cache</b>
  73.       * is false, the image will not be placed in the application cache, and
  74.       * it will be released in the normal manner.
  75.       *
  76.       */
  77.     public static synchronized Bitmap bitmapNamed(String bitmapName,
  78.                                                   boolean startLoading,
  79.                                                   boolean cache) {
  80.         Application app;
  81.         Bitmap bitmap;
  82.         URL url;
  83.  
  84.         if (bitmapName == null || bitmapName.equals(""))
  85.             return null;
  86.  
  87.         app = application();
  88.         bitmap = (Bitmap)app.bitmapByName.get(bitmapName);
  89.  
  90.         if (bitmap != null)
  91.             return bitmap;
  92.  
  93.         // ALERT!  This is here until we get resources straight.
  94.         bitmap = systemBitmapNamed(bitmapName);
  95.         if (bitmap != null) {
  96.             if(cache)   {
  97.                 app.bitmapByName.put(bitmapName, bitmap);
  98.                 // If we are caching, we can use the shared media tracker,
  99.                 // because the image can not be released from bitmapByName
  100.                 // hashtable.
  101.                 // We are setting the value here so that tracker() returns the
  102.                 // proper value.
  103.                 // bitmap.mediaTracker = Application.application().mediaTracker();
  104.                 bitmap.useStaticTracker = true;
  105.             }
  106.             bitmap.name = bitmapName;
  107.             return bitmap;
  108.         }
  109.  
  110.         url = app._appResources.urlForBitmapNamed(bitmapName);
  111.         bitmap = bitmapFromURL(url);
  112.  
  113.         if (bitmap == null)
  114.             return null;
  115.  
  116.         if(cache)   {
  117.             app.bitmapByName.put(bitmapName, bitmap);
  118.             // If we are caching, we can use the shared media tracker,
  119.             // because the image can not be released from bitmapByName
  120.             // hashtable.
  121.             // We are setting the value here so that tracker() returns the
  122.             // proper value.
  123.             // bitmap.mediaTracker = Application.application().mediaTracker();
  124.             bitmap.useStaticTracker = true;
  125.         }
  126.         bitmap.name = bitmapName;
  127.  
  128.         /* start loading the bitmap */
  129.         if (startLoading) {
  130.             bitmap.startLoadingData();
  131.         }
  132.  
  133.         return bitmap;
  134.     }
  135.  
  136.  
  137.     /** Returns the Bitmap named <b>bitmapName</b>. The application maintains
  138.       * a cache of named Bitmaps that it checks first.  If not located in
  139.       * the cache, this method looks for the specified bitmap in the "images"
  140.       * directory in the same directory as the Application's index.html
  141.       * file.  In other words, it constructs the URL
  142.       * <pre>
  143.       *     "codebase"/images/bitmapName
  144.       * </pre>
  145.       * and attempts to load this image.  <b>bitmapName</b> can specify a
  146.       * file name or path, such as "newImages/ColorBackground.gif".
  147.       * This method starts loading the bitmap's data if <b>startLoading</b> is
  148.       * <b>true</b>.  Otherwise, the IFC retrieves the data when needed.
  149.       * This call is equivelent to:
  150.       * <PRE>
  151.       *      Bitmap.bitmapNamed(bitmapName, startLoading, true);
  152.       * </PRE>
  153.       * @see #bitmapNamed(String, boolean, boolean)
  154.       */
  155.     public static Bitmap bitmapNamed(String bitmapName,
  156.                                                   boolean startLoading) {
  157.         return bitmapNamed(bitmapName, startLoading, true);
  158.     }
  159.  
  160.     /** Convenience method for retrieving the bitmap <b>bitmapName</b>.
  161.       * Immediately begins loading its data.  Equivalent to the code:
  162.       * <pre>
  163.       *     Bitmap.bitmapNamed(bitmapName, true, true);
  164.       * </pre>
  165.       * @see #bitmapNamed(String, boolean, boolean)
  166.       */
  167.     public static Bitmap bitmapNamed(String bitmapName) {
  168.         return bitmapNamed(bitmapName, true, true);
  169.     }
  170.  
  171.     /** Returns a Bitmap initialized with data from the URL <b>url</b>.
  172.       */
  173.     public static Bitmap bitmapFromURL(URL url) {
  174.         java.awt.Image awtImage;
  175.         Bitmap bitmap;
  176.  
  177.         awtImage = AWTCompatibility.awtApplet().getImage(url);
  178.  
  179.         if (awtImage == null)
  180.             return null;
  181.  
  182.         bitmap = new Bitmap(awtImage);
  183.  
  184.         return bitmap;
  185.     }
  186.  
  187.     /** Returns a graphics object that can be used to draw into the Bitmap.
  188.       * The <b>dispose()</b> method should be called on this object when no
  189.       * longer needed, to immediately free its
  190.       * resources.  Bitmap subclasses can override this method to
  191.       * provide callers a Graphics subclass instance.
  192.       */
  193.     public Graphics createGraphics() {
  194.         return Graphics.newGraphics(this);
  195.     }
  196.  
  197. /* constructors */
  198.  
  199.  
  200.     /** Constructs a Bitmap with no name and no data. This method is only
  201.       * useful when decoding.
  202.       */
  203.     public Bitmap() {
  204.         super();
  205.  
  206.         imageNumber = application().nextBitmapNumber();
  207.     }
  208.  
  209.     /** Constructs a Bitmap of size (<b>width</b>, <b>height</b>) with blank
  210.       * contents. Typically, you use Bitmaps with no contents for offscreen
  211.       * composition.
  212.       */
  213.     public Bitmap(int width, int height) {
  214.         this();
  215.  
  216.         if (width <= 0 || height <= 0) {
  217.             throw new IllegalArgumentException("Invalid bitmap size: " +
  218.                                                width + "x" + height);
  219.         }
  220.         awtImage = AWTCompatibility.awtApplet().createImage(width, height);
  221.         setLoaded(true);
  222.     }
  223.  
  224.     Bitmap(java.awt.Image awtImage) {
  225.         this();
  226.         this.awtImage = awtImage;
  227.     }
  228.  
  229.     /** Constructs a Bitmap of size (<b>width</b>, <b>height</b>) with
  230.       * contents derived from the integer array <b>pixels</b>. Equivalent to
  231.       * the code:
  232.       * <pre>
  233.       *     Bitmap(pixels, width, height, 0, width)
  234.       * </pre>
  235.       * @see #Bitmap(int[], int, int, int, int)
  236.       */
  237.     public Bitmap(int pixels[], int width, int height) {
  238.         this(pixels, width, height, 0, width);
  239.     }
  240.  
  241.     /** Constructs a Bitmap of size (<b>width</b>, <b>height</b>) with
  242.       * contents derived from the integer array <b>pixels</b>. <b>offset</b>
  243.       * indicates the position of the first pixel in the array. <b>scanSize</b>
  244.       * indicates the number of pixels in the array per line.<p>
  245.       * The format follows the default Java color model, where each pixel is a
  246.       * 32-bit integer. Bits 24-31 are the alpha transparency, bits 16-23 are
  247.       * the red value, bits 8-15 are the green value, and bits 0-7 are the blue
  248.       * value.
  249.       */
  250.     public Bitmap(int pixels[], int width, int height, int offset,
  251.                   int scanSize) {
  252.         this();
  253.  
  254.         java.awt.image.MemoryImageSource   src;
  255.         java.awt.Image                     image;
  256.  
  257.         src = new java.awt.image.MemoryImageSource(width, height, pixels,
  258.                                                    offset, scanSize);
  259.         awtImage = AWTCompatibility.awtApplet().createImage(src);
  260.         setLoaded(true);
  261.     }
  262.  
  263.     /** Fills the integer array <b>pixels</b> with 32-bit pixel values
  264.       * for the entire Bitmap. The array should be large enough to hold
  265.       * (<b>width()</b> * <b>height()</b>) values. Equivalent to the code:
  266.       * <pre>
  267.       *     grabPixels(pixels, 0, 0, width(), height(), 0, width());
  268.       * </pre>
  269.       * Returns <b>true</b> on success, <b>false</b> on failure.
  270.       * @see #Bitmap(int[], int, int, int, int)
  271.       * @see #grabPixels(int[], int, int, int, int, int, int)
  272.       */
  273.     public boolean grabPixels(int pixels[]) {
  274.         return grabPixels(pixels, 0, 0, width(), height(), 0, width());
  275.     }
  276.  
  277.     /** Fills the integer array <b>pixels</b> with 32-bit pixel values
  278.       * for the Bitmap. The array should be large enough to hold (<b>width</b>
  279.       * <b>height</b>) values. <b>x</b> and <b>y</b> determine the origin of
  280.       * the rectangle of pixels to retrieve from the Bitmap, relative to the
  281.       * default (unscaled) size of the Bitmap. <b>width</b> and <b>height</b>
  282.       * indicate the size of the rectangle. <b>offset</b> indicates how far
  283.       * into the array the first pixel should be stored. <b>scanSize</b> is the
  284.       * distance from the start of one row of pixels to the start of the next
  285.       * row in the array. The pixel format follows the default Java RGB color
  286.       * model.<p>
  287.       * Returns <b>true</b> on success, <b>false</b> on failure.
  288.       * @see #Bitmap(int[], int, int, int, int)
  289.       */
  290.     public boolean grabPixels(int pixels[], int x, int y, int width,
  291.                               int height, int offset, int scanSize) {
  292.         java.awt.image.PixelGrabber  grabber;
  293.         java.awt.Image               image;
  294.         boolean                      status;
  295.  
  296.         image = AWTCompatibility.awtImageForBitmap(this);
  297.         grabber = new java.awt.image.PixelGrabber(image, x, y, width, height,
  298.                                                   pixels, offset, scanSize);
  299.         try {
  300.             status = grabber.grabPixels();
  301.         } catch (InterruptedException e) {
  302.             status = false;
  303.         }
  304.         return status;
  305.     }
  306.  
  307.     /** Returns the name used to load the Bitmap. Returns <b>null</b>
  308.       * if the Bitmap was not obtained via <b>Bitmap.bitmapNamed()</b>.
  309.       * @see #bitmapNamed(String)
  310.       */
  311.     public String name() {
  312.         return name;
  313.     }
  314.  
  315.     BitmapObserver bitmapObserver() {
  316.         if (bitmapObserver == null) {
  317.             if(updateTarget != null) {
  318.                 bitmapObserver = new BitmapObserver(application(), this);
  319.             } else {
  320.                 bitmapObserver = new BitmapObserver(null, this);
  321.         }
  322.         }
  323.         return bitmapObserver;
  324.     }
  325.  
  326.     int getWidthOrHeight(int dimension) {
  327.         BitmapObserver  observer;
  328.         int             value = -1;
  329.         boolean         done = false;
  330.  
  331.         if (dimension != WIDTH && dimension != HEIGHT) {
  332.             throw new IllegalArgumentException("Invalid dimension request: " +
  333.                                                dimension);
  334.         }
  335.  
  336.         if (hasLoadedData()) {
  337.             if (dimension == WIDTH) {
  338.                 return awtImage.getWidth(null);
  339.             } else {
  340.                 return awtImage.getHeight(null);
  341.             }
  342.         }
  343.  
  344. //      startLoadingData();
  345.  
  346.         observer = bitmapObserver();
  347.  
  348.         synchronized(observer) {
  349.             while (!done) {
  350.                 /// ALERT!
  351.                 /// Calling getWidth/Height twice here is intentional.
  352.                 /// Something has changed with the JDK 1.1.1 release,
  353.                 /// regarding MemoryImageSource. In the past, they would
  354.                 /// always return a valid value, and we would never call
  355.                 /// the wait(). Under JDK 1.1.1 they seem to return -1
  356.                 /// the first time and then never notify the observer that
  357.                 /// anything has changed. So the original code here got
  358.                 /// stuck in the wait() call and was never interupted.
  359.                 /// Calling these methods twice was the 'safest' fix we
  360.                 /// could find at this time. Investigate further and
  361.                 /// determine the true problem and solution.
  362.                 if (dimension == WIDTH) {
  363.                     value = awtImage.getWidth(observer);
  364.                     value = awtImage.getWidth(observer);
  365.                 } else {
  366.                     value = awtImage.getHeight(observer);
  367.                     value = awtImage.getHeight(observer);
  368.                 }
  369.                 if (value != -1 || !isValid()) {
  370.                     break;
  371.                 }
  372.  
  373.                 if ((observer.lastInfo & ImageObserver.ERROR) != 0 ||
  374.                     (observer.lastInfo & ImageObserver.ABORT) != 0) {
  375.                     valid = false;
  376.                     reportWhyInvalid();
  377.                     setLoaded(true);
  378.                 } else  {
  379.                     try {
  380.                         observer.wait();
  381.                     } catch (java.lang.InterruptedException e) {
  382.                     }
  383.                     /* are we valid? */
  384.                     if ((observer.lastInfo & ImageObserver.ERROR) != 0 ||
  385.                         (observer.lastInfo & ImageObserver.ABORT) != 0) {
  386.                         valid = false;
  387.                         reportWhyInvalid();
  388.                         setLoaded(true);
  389.                     }
  390.                 }
  391.             }
  392.         }
  393.  
  394.         return value;
  395.     }
  396.  
  397.     /** Returns the Bitmap's width.  Begins loading the Bitmap's data, if
  398.       * necessary, returning once the Bitmap's size information becomes
  399.       * available.
  400.       */
  401.     public int width() {
  402.         return getWidthOrHeight(WIDTH);
  403.     }
  404.  
  405.     /** Returns the Bitmap's height.  Begins loading the Bitmap's data, if
  406.       * necessary, returning once the Bitmap's size information becomes
  407.       * available.
  408.       */
  409.     public int height() {
  410.         return getWidthOrHeight(HEIGHT);
  411.     }
  412.  
  413.     /** Sets whether the Bitmap is transparent.
  414.       * @see #isTransparent
  415.       */
  416.     public void setTransparent(boolean transparent) {
  417.         this.transparent = transparent;
  418.     }
  419.  
  420.     /** Returns <b>true</b> if the Bitmap is transparent.  This method does
  421.       * <i>not</i> check the Bitmap's data.  A Bitmap assumes itself
  422.       * transparent unless modified using the <b>setTransparent()</b> method.
  423.       * Returning <b>true</b> is always safe, but an Image user may
  424.       * be able to avoid drawing the region under the Image if this method
  425.       * returns <b>false</b>.
  426.       * @see #setTransparent
  427.       */
  428.     public boolean isTransparent() {
  429.         return transparent;
  430.     }
  431.  
  432.     /** Draws the Bitmap at (<b>x</b>, <b>y</b>). */
  433.     public void drawAt(Graphics g, int x, int y) {
  434.         g.drawBitmapAt(this, x, y);
  435.     }
  436.  
  437.     /** Draws the Bitmap scaled to fit the supplied rectangle.
  438.       */
  439.     public void drawScaled(Graphics g, int x, int y, int width, int height) {
  440.         g.drawBitmapScaled(this, x, y, width, height);
  441.     }
  442.  
  443.     /** Overridden to generate an error message just like the other Image
  444.       * drawing methods do when confronted with in invalid bitmap.
  445.       * @private
  446.       */
  447.     public void drawTiled(Graphics g, int x, int y, int width, int height) {
  448.         if (!isValid()) {
  449.             System.err.println("Graphics.drawBitmapTiled() - Invalid bitmap: "+
  450.                                name());
  451.             return;
  452.         }
  453.  
  454.         super.drawTiled(g, x, y, width, height);
  455.     }
  456.  
  457.     /** Renders a scaled version of the Bitmap to
  458.       * have width <b>newWidth</b> and height <b>newHeight</b>,
  459.       * retrieving the Bitmap's original data if it has not already
  460.       * done so.  In general, you will never need to call this method.
  461.       * Instead, you'll call the Bitmap's <b>drawScaled()</b>, and the Bitmap
  462.       * will ensure that an appropriately-scaled version exists.  Returns
  463.       * <b>true</b> if the Bitmap's data was successfully
  464.       * loaded and scaled, <b>false</b> if there was a problem.
  465.       */
  466.     boolean createScaledVersion(int newWidth, int newHeight) {
  467.         Application     application;
  468.         BitmapObserver  observer;
  469.  
  470.         if (!isValid()) {
  471.             return false;
  472.         }
  473.  
  474.         application = application();
  475.         observer = bitmapObserver();
  476.  
  477.         while (!application.applet.prepareImage(awtImage, newWidth, newHeight,
  478.                                                                 observer)) {
  479.             if (loadsIncrementally()) {
  480.                 return true;
  481.             }
  482.  
  483.             try {
  484.                 Thread.sleep(40);
  485.             } catch (InterruptedException e) {
  486.             }
  487.         }
  488.  
  489. /*      observer = bitmapObserver(true);
  490.         synchronized(observer) {
  491.             while (!application.applet.prepareImage(awtImage, newWidth,
  492.                                                     newHeight, observer)) {
  493.                 if (loadsIncrementally() || observer.allBitsPresent() ||
  494.                     observer.imageHasProblem()) {
  495.                     return true;
  496.                 }
  497.  
  498.                 try {
  499.                     observer.wait();
  500.                 } catch (java.lang.InterruptedException e) {
  501.                 }
  502.             }
  503.         }*/
  504.  
  505.         return true;
  506.     }
  507.  
  508.     /** Convenience method for rendering a scaled version of the Bitmap,
  509.       * scaling its width by <b>scaleX</b> and height by <b>scaleY</b>.
  510.       * Equivalent to the code:
  511.       * <pre>
  512.       *     createScaledVersion((int)(scaleX * width()),
  513.       *                         (int)(scaleY * height()));
  514.       * </pre>
  515.       * @see #createScaledVersion
  516.       * @return <b>true</b> if the Bitmap's data was successfully
  517.       * loaded and scaled, <b>false</b> if there was a problem.
  518.       */
  519.     boolean createScaledVersion(float scaleX, float scaleY) {
  520.         return createScaledVersion((int)(scaleX * width()),
  521.                                    (int)(scaleY * height()));
  522.     }
  523.  
  524.     void startLoadingData() {
  525.         MediaTracker    tracker;
  526.  
  527.         tracker = tracker();
  528.  
  529.         /* add to the list */
  530.         if (!added) {
  531.             tracker.addImage(awtImage, imageNumber);
  532.             added = true;
  533.         }
  534.  
  535.         /* start loading its data */
  536.         tracker.checkID(imageNumber, true);
  537. //      valid = !tracker.isErrorID(imageNumber);
  538.     }
  539.  
  540.     /** Begins the loading of the Bitmap's data. This method does not return
  541.       * until the data has been loaded, unless the Bitmap is set to be loaded
  542.       * incrementally. In general, you never call this method.
  543.       * Any methods requiring the Bitmap's data will automatically call
  544.       * <b>loadData()</b>.
  545.       */
  546.     public void loadData() {
  547.         MediaTracker    tracker;
  548.  
  549.         if (loaded) {
  550.             return;
  551.         }
  552.  
  553.         tracker = tracker();
  554.  
  555.         while (!loaded) {
  556.             try {
  557.                 startLoadingData();
  558.  
  559.                 /* bail out if we don't want to block */
  560.                 if (loadIncrementally) {
  561.                     break;
  562.                 }
  563.  
  564.                 tracker.waitForID(imageNumber);
  565.                 setLoaded(true);
  566.             } catch (InterruptedException e) {
  567.                 System.err.println("Bitmap.loadData() - " + e);
  568.                 // valid = false;
  569.             }
  570.         }
  571.  
  572.         if (valid) {
  573.             valid = !tracker.isErrorID(imageNumber);
  574.         }
  575.  
  576.         if (!valid) {
  577.             reportWhyInvalid();
  578.             setLoaded(true);
  579.         }
  580.     }
  581.  
  582.     void setLoaded(boolean flag) {
  583.         loaded = flag;
  584.  
  585.         mediaTracker = null;
  586.         bitmapObserver = null;
  587.     }
  588.  
  589.     /** Returns <b>true</b> if the Bitmap attempted to load its data and
  590.       * succeeded.
  591.       * @see #loadData
  592.       */
  593.     public boolean hasLoadedData() {
  594.         return loaded;
  595.     }
  596.  
  597.     /** Configures the Bitmap to load and display its data incrementally.
  598.       * An incrementally-loaded Bitmap notifies its update Target when
  599.       * additional data becomes available, and when drawn, draws all available
  600.       * data rather than waiting until all data is present.
  601.       * @see #setUpdateTarget
  602.       */
  603.     public void setLoadsIncrementally(boolean flag) {
  604.         loadIncrementally = flag;
  605.     }
  606.  
  607.     /** Returns <b>true</b> if the Bitmap's data will load incrementally.
  608.       * @see #setLoadsIncrementally
  609.       */
  610.     public boolean loadsIncrementally() {
  611.         return loadIncrementally;
  612.     }
  613.  
  614.     /** Returns the Rect defining the newly-available portion of an
  615.       * incrementally-loaded Bitmap.  Returns an empty Rect if the Bitmap
  616.       * is not loading incrementally, or no additional data has become
  617.       * available since this method was most recently called.
  618.       * @see #setLoadsIncrementally
  619.       */
  620.     public synchronized Rect updateRect() {
  621.         Rect    tmpRect;
  622.  
  623.         if (updateRect == null) {
  624.             tmpRect = new Rect();
  625.         } else {
  626.             tmpRect = updateRect;
  627.             updateRect = null;
  628.         }
  629.  
  630.         return tmpRect;
  631.     }
  632.  
  633.     /** Sets the Target that should receive a command when the
  634.       * incrementally-loaded Bitmap receives additional data.
  635.       * @see #setLoadsIncrementally
  636.       * @see #setUpdateCommand
  637.       */
  638.     public synchronized void setUpdateTarget(Target aTarget) {
  639.         updateTarget = aTarget;
  640.     }
  641.  
  642.     /** Returns the Bitmap's update target.
  643.       * @see #setUpdateTarget
  644.       */
  645.     public synchronized Target updateTarget() {
  646.         return updateTarget;
  647.     }
  648.  
  649.     /** Sets the command sent to an incrementally-loaded Bitmap's update Target
  650.       * when additional data becomes available.
  651.       * @see #setUpdateTarget
  652.       */
  653.     public synchronized void setUpdateCommand(String command) {
  654.         updateCommand = command;
  655.     }
  656.  
  657.     /** Returns the Bitmap's update command.
  658.       * @see #setUpdateCommand
  659.       */
  660.     public synchronized String updateCommand() {
  661.         return updateCommand;
  662.     }
  663.  
  664.     void reportWhyInvalid() {
  665.         String          message = "";
  666.         int             status;
  667.  
  668.         status = tracker().statusID(imageNumber, false);
  669.  
  670.         if ((status & MediaTracker.ABORTED) != 0) {
  671.             message = message + " ABORTED";
  672.         } else if ((status & MediaTracker.COMPLETE) != 0) {
  673.             message = message + " COMPLETE";
  674.         } else if ((status & MediaTracker.ERRORED) != 0) {
  675.             message = message + " ERRORED";
  676.         } else if ((status & MediaTracker.LOADING) != 0) {
  677.             message = message + " LOADING";
  678.         }
  679.  
  680.         System.err.println("Invalid bitmap: " + name() + message);
  681.     }
  682.  
  683.     /** Returns <b>true</b> if the Bitmap's data was successfully loaded
  684.       * and is valid.
  685.       * @see #loadData
  686.       */
  687.     public boolean isValid() {
  688. // ALERT! - this method doesn't care if we've tried to load data or not!
  689.         return valid;
  690.     }
  691.  
  692.     /** Flushes all resources allocated to the Bitmap, including cached
  693.       * pixel data and system resources.
  694.       */
  695.     public void flush() {
  696.         awtImage.flush();
  697.     }
  698.  
  699.     /** Returns the Bitmap's String representation.
  700.       */
  701.     public String toString() {
  702.         if (name != null) {
  703.             return "Bitmap(" + name + ")";
  704.         } else
  705.             return super.toString();
  706.     }
  707.  
  708.     /** Describes the Bitmap class' coding information.
  709.       * @see Codable#describeClassInfo
  710.       */
  711.     public void describeClassInfo(ClassInfo info) {
  712.         super.describeClassInfo(info);
  713.  
  714.         info.addClass("netscape.application.Bitmap", 1);
  715.         info.addField(NAME_KEY, STRING_TYPE);
  716.         info.addField(UPDATE_TARGET_KEY, OBJECT_TYPE);
  717.         info.addField(UPDATE_COMMAND_KEY, STRING_TYPE);
  718.         info.addField(TRANSPARENT_KEY, BOOLEAN_TYPE);
  719.         info.addField(LOAD_INCREMENTALLY_KEY, BOOLEAN_TYPE);
  720.     }
  721.  
  722.     /** Encodes the Bitmap.  For now, Bitmaps are only encodable by name.
  723.       * @see Codable#encode
  724.       */
  725.     public void encode(Encoder encoder) throws CodingException {
  726.         super.encode(encoder);
  727.  
  728.         if (name == null) {
  729.             throw new CodingException("encoded Bitmaps must have a name");
  730.         }
  731.  
  732.         encoder.encodeString(NAME_KEY, name);
  733.         encoder.encodeObject(UPDATE_TARGET_KEY, (Codable)updateTarget);
  734.         encoder.encodeString(UPDATE_COMMAND_KEY, updateCommand);
  735.         encoder.encodeBoolean(TRANSPARENT_KEY, transparent);
  736.         encoder.encodeBoolean(LOAD_INCREMENTALLY_KEY, loadIncrementally);
  737.     }
  738.  
  739.     /** Decodes the Bitmap.  For now, this simply decodes the name
  740.       * and calls <b>Bitmap.bitmapNamed()</b>.
  741.       * @see Codable#decode
  742.       */
  743.     public void decode(Decoder decoder) throws CodingException {
  744.         Bitmap tmp;
  745.  
  746.         super.decode(decoder);
  747.  
  748.         name = decoder.decodeString(NAME_KEY);
  749.         if (name == null) {
  750.             throw new CodingException("encoded Bitmaps must have a name");
  751.         }
  752.  
  753.         // ALERT!  These are not preserved during the replacement.
  754.  
  755.         updateTarget = (Target)decoder.decodeObject(UPDATE_TARGET_KEY);
  756.         updateCommand = decoder.decodeString(UPDATE_COMMAND_KEY);
  757.         transparent = decoder.decodeBoolean(TRANSPARENT_KEY);
  758.         loadIncrementally = decoder.decodeBoolean(LOAD_INCREMENTALLY_KEY);
  759.  
  760.         tmp = bitmapNamed(name);
  761.         if (tmp == null)
  762.             throw new CodingException("unable to find bitmap named: " + name);
  763.  
  764.         // Only replace with the shared Bitmap if this is not a subclass of
  765.         // Bitmap.
  766.  
  767.         // ALERT!  How does this play with incremental loading?
  768.  
  769.         if (getClass() == bitmapClass()) {
  770.             decoder.replaceObject(tmp);
  771.         } else {
  772.             awtImage = tmp.awtImage;
  773.         }
  774.     }
  775.  
  776.     private static Class bitmapClass() {
  777.         if (bitmapClass == null)
  778.             bitmapClass = new Bitmap().getClass();
  779.  
  780.         return bitmapClass;
  781.     }
  782.  
  783.     private static Application application() {
  784.         return Application.application();
  785.     }
  786.  
  787.     // This crud is slammed into Bitmap to avoid bringing in the class
  788.     // SystemImages unless we actually need a bitmap from there.
  789.  
  790.     private static Bitmap systemBitmapNamed(String name) {
  791.         Bitmap bitmap = null;
  792.         String systemName;
  793.  
  794.         if (name == null)
  795.             return null;
  796.         else if (!name.startsWith("netscape/application/"))
  797.             return null;
  798.         else {
  799.             systemName = name.substring("netscape/application/".length());
  800.             if (systemName.equals("RedGrad.gif"))
  801.                 bitmap = SystemImages.redGrad();
  802.             else if (systemName.equals("GreenGrad.gif"))
  803.                 bitmap = SystemImages.greenGrad();
  804.             else if (systemName.equals("BlueGrad.gif"))
  805.                 bitmap = SystemImages.blueGrad();
  806.             else if (systemName.equals("CheckMark.gif"))
  807.                 bitmap = SystemImages.checkMark();
  808.             else if (systemName.equals("CloseButton.gif"))
  809.                 bitmap = SystemImages.closeButton();
  810.             else if (systemName.equals("CloseButtonActive.gif"))
  811.                 bitmap = SystemImages.closeButtonActive();
  812.             else if (systemName.equals("ColorScrollKnob.gif"))
  813.                 bitmap = SystemImages.colorScrollKnob();
  814.             else if (systemName.equals("PopupKnob.gif"))
  815.                 bitmap = SystemImages.popupKnob();
  816.             else if (systemName.equals("PopupKnobH.gif"))
  817.                 bitmap = SystemImages.popupKnobH();
  818.             else if (systemName.equals("RadioButtonOff.gif"))
  819.                 bitmap = SystemImages.radioButtonOff();
  820.             else if (systemName.equals("RadioButtonOn.gif"))
  821.                 bitmap = SystemImages.radioButtonOn();
  822.             else if (systemName.equals("ResizeLeft.gif"))
  823.                 bitmap = SystemImages.resizeLeft();
  824.             else if (systemName.equals("ResizeRight.gif"))
  825.                 bitmap = SystemImages.resizeRight();
  826.             else if (systemName.equals("ScrollDownArrow.gif"))
  827.                 bitmap = SystemImages.scrollDownArrow();
  828.             else if (systemName.equals("ScrollDownArrowActive.gif"))
  829.                 bitmap = SystemImages.scrollDownArrowActive();
  830.             else if (systemName.equals("ScrollKnobH.gif"))
  831.                 bitmap = SystemImages.scrollKnobH();
  832.             else if (systemName.equals("ScrollKnobV.gif"))
  833.                 bitmap = SystemImages.scrollKnobV();
  834.             else if (systemName.equals("ScrollLeftArrow.gif"))
  835.                 bitmap = SystemImages.scrollLeftArrow();
  836.             else if (systemName.equals("ScrollLeftArrowActive.gif"))
  837.                 bitmap = SystemImages.scrollLeftArrowActive();
  838.             else if (systemName.equals("ScrollRightArrow.gif"))
  839.                 bitmap = SystemImages.scrollRightArrow();
  840.             else if (systemName.equals("ScrollRightArrowActive.gif"))
  841.                 bitmap = SystemImages.scrollRightArrowActive();
  842.             else if (systemName.equals("ScrollTrayBottom.gif"))
  843.                 bitmap = SystemImages.scrollTrayBottom();
  844.             else if (systemName.equals("ScrollTrayLeft.gif"))
  845.                 bitmap = SystemImages.scrollTrayLeft();
  846.             else if (systemName.equals("ScrollTrayRight.gif"))
  847.                 bitmap = SystemImages.scrollTrayRight();
  848.             else if (systemName.equals("ScrollTrayTop.gif"))
  849.                 bitmap = SystemImages.scrollTrayTop();
  850.             else if (systemName.equals("ScrollUpArrow.gif"))
  851.                 bitmap = SystemImages.scrollUpArrow();
  852.             else if (systemName.equals("ScrollUpArrowActive.gif"))
  853.                 bitmap = SystemImages.scrollUpArrowActive();
  854.             else if (systemName.equals("TitleBarLeft.gif"))
  855.                 bitmap = SystemImages.titleBarLeft();
  856.             else if (systemName.equals("TitleBarRight.gif"))
  857.                 bitmap = SystemImages.titleBarRight();
  858.             else if (systemName.equals("alertNotification.gif"))
  859.                 bitmap = SystemImages.alertNotification();
  860.             else if (systemName.equals("alertQuestion.gif"))
  861.                 bitmap = SystemImages.alertQuestion();
  862.             else if (systemName.equals("alertWarning.gif"))
  863.                 bitmap = SystemImages.alertWarning();
  864.             else if (systemName.equals("topLeftArrow.gif"))
  865.                 bitmap = SystemImages.topLeftArrow();
  866.             else if (systemName.equals("topRightArrow.gif"))
  867.                 bitmap = SystemImages.topRightArrow();
  868.             else if (systemName.equals("bottomRightArrow.gif"))
  869.                 bitmap = SystemImages.bottomRightArrow();
  870.             else if (systemName.equals("bottomLeftArrow.gif"))
  871.                 bitmap = SystemImages.bottomLeftArrow();
  872.         }
  873.  
  874.         return bitmap;
  875.     }
  876.  
  877.     /** Overridden to return the Bitmap with name <b>name</b>.  If you want
  878.       * to locate a Bitmap by name, call the static <b>Bitmap.bitmapNamed()</b>
  879.       * method.
  880.       * @see #bitmapNamed
  881.       * @see Image#imageNamed
  882.       * @private
  883.       */
  884.     public Image imageWithName(String name) {
  885.         return Bitmap.bitmapNamed(name);
  886.     }
  887.  
  888.     synchronized void unionWithUpdateRect(int x, int y, int width,
  889.                                           int height) {
  890.         if (updateRect == null) {
  891.             updateRect = new Rect(x, y, width, height);
  892.         } else {
  893.             updateRect.unionWith(x, y, width, height);
  894.         }
  895.     }
  896.  
  897.     private java.awt.MediaTracker tracker() {
  898.         if(mediaTracker == null)    {
  899.             if(useStaticTracker)
  900.                 mediaTracker = Application.application().mediaTracker();
  901.             else
  902.                 mediaTracker = new java.awt.MediaTracker(AWTCompatibility.awtApplet());
  903.         }
  904.         return mediaTracker;
  905.     }
  906.  
  907. }
  908.