|  | /* | 
|  | * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. | 
|  | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|  | * | 
|  | * This code is free software; you can redistribute it and/or modify it | 
|  | * under the terms of the GNU General Public License version 2 only, as | 
|  | * published by the Free Software Foundation.  Oracle designates this | 
|  | * particular file as subject to the "Classpath" exception as provided | 
|  | * by Oracle in the LICENSE file that accompanied this code. | 
|  | * | 
|  | * This code is distributed in the hope that it will be useful, but WITHOUT | 
|  | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|  | * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|  | * version 2 for more details (a copy is included in the LICENSE file that | 
|  | * accompanied this code). | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License version | 
|  | * 2 along with this work; if not, write to the Free Software Foundation, | 
|  | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|  | * | 
|  | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|  | * or visit www.oracle.com if you need additional information or have any | 
|  | * questions. | 
|  | */ | 
|  |  | 
|  | package java.awt; | 
|  |  | 
|  | import java.awt.Component; | 
|  | import java.awt.Image; | 
|  | import java.awt.image.ImageObserver; | 
|  | import sun.awt.image.MultiResolutionToolkitImage; | 
|  |  | 
|  | /** | 
|  | * The <code>MediaTracker</code> class is a utility class to track | 
|  | * the status of a number of media objects. Media objects could | 
|  | * include audio clips as well as images, though currently only | 
|  | * images are supported. | 
|  | * <p> | 
|  | * To use a media tracker, create an instance of | 
|  | * <code>MediaTracker</code> and call its <code>addImage</code> | 
|  | * method for each image to be tracked. In addition, each image can | 
|  | * be assigned a unique identifier. This identifier controls the | 
|  | * priority order in which the images are fetched. It can also be used | 
|  | * to identify unique subsets of the images that can be waited on | 
|  | * independently. Images with a lower ID are loaded in preference to | 
|  | * those with a higher ID number. | 
|  | * | 
|  | * <p> | 
|  | * | 
|  | * Tracking an animated image | 
|  | * might not always be useful | 
|  | * due to the multi-part nature of animated image | 
|  | * loading and painting, | 
|  | * but it is supported. | 
|  | * <code>MediaTracker</code> treats an animated image | 
|  | * as completely loaded | 
|  | * when the first frame is completely loaded. | 
|  | * At that point, the <code>MediaTracker</code> | 
|  | * signals any waiters | 
|  | * that the image is completely loaded. | 
|  | * If no <code>ImageObserver</code>s are observing the image | 
|  | * when the first frame has finished loading, | 
|  | * the image might flush itself | 
|  | * to conserve resources | 
|  | * (see {@link Image#flush()}). | 
|  | * | 
|  | * <p> | 
|  | * Here is an example of using <code>MediaTracker</code>: | 
|  | * <p> | 
|  | * <hr><blockquote><pre>{@code | 
|  | * import java.applet.Applet; | 
|  | * import java.awt.Color; | 
|  | * import java.awt.Image; | 
|  | * import java.awt.Graphics; | 
|  | * import java.awt.MediaTracker; | 
|  | * | 
|  | * public class ImageBlaster extends Applet implements Runnable { | 
|  | *      MediaTracker tracker; | 
|  | *      Image bg; | 
|  | *      Image anim[] = new Image[5]; | 
|  | *      int index; | 
|  | *      Thread animator; | 
|  | * | 
|  | *      // Get the images for the background (id == 0) | 
|  | *      // and the animation frames (id == 1) | 
|  | *      // and add them to the MediaTracker | 
|  | *      public void init() { | 
|  | *          tracker = new MediaTracker(this); | 
|  | *          bg = getImage(getDocumentBase(), | 
|  | *                  "images/background.gif"); | 
|  | *          tracker.addImage(bg, 0); | 
|  | *          for (int i = 0; i < 5; i++) { | 
|  | *              anim[i] = getImage(getDocumentBase(), | 
|  | *                      "images/anim"+i+".gif"); | 
|  | *              tracker.addImage(anim[i], 1); | 
|  | *          } | 
|  | *      } | 
|  | * | 
|  | *      // Start the animation thread. | 
|  | *      public void start() { | 
|  | *          animator = new Thread(this); | 
|  | *          animator.start(); | 
|  | *      } | 
|  | * | 
|  | *      // Stop the animation thread. | 
|  | *      public void stop() { | 
|  | *          animator = null; | 
|  | *      } | 
|  | * | 
|  | *      // Run the animation thread. | 
|  | *      // First wait for the background image to fully load | 
|  | *      // and paint.  Then wait for all of the animation | 
|  | *      // frames to finish loading. Finally, loop and | 
|  | *      // increment the animation frame index. | 
|  | *      public void run() { | 
|  | *          try { | 
|  | *              tracker.waitForID(0); | 
|  | *              tracker.waitForID(1); | 
|  | *          } catch (InterruptedException e) { | 
|  | *              return; | 
|  | *          } | 
|  | *          Thread me = Thread.currentThread(); | 
|  | *          while (animator == me) { | 
|  | *              try { | 
|  | *                  Thread.sleep(100); | 
|  | *              } catch (InterruptedException e) { | 
|  | *                  break; | 
|  | *              } | 
|  | *              synchronized (this) { | 
|  | *                  index++; | 
|  | *                  if (index >= anim.length) { | 
|  | *                      index = 0; | 
|  | *                  } | 
|  | *              } | 
|  | *              repaint(); | 
|  | *          } | 
|  | *      } | 
|  | * | 
|  | *      // The background image fills the frame so we | 
|  | *      // don't need to clear the applet on repaints. | 
|  | *      // Just call the paint method. | 
|  | *      public void update(Graphics g) { | 
|  | *          paint(g); | 
|  | *      } | 
|  | * | 
|  | *      // Paint a large red rectangle if there are any errors | 
|  | *      // loading the images.  Otherwise always paint the | 
|  | *      // background so that it appears incrementally as it | 
|  | *      // is loading.  Finally, only paint the current animation | 
|  | *      // frame if all of the frames (id == 1) are done loading, | 
|  | *      // so that we don't get partial animations. | 
|  | *      public void paint(Graphics g) { | 
|  | *          if ((tracker.statusAll(false) & MediaTracker.ERRORED) != 0) { | 
|  | *              g.setColor(Color.red); | 
|  | *              g.fillRect(0, 0, size().width, size().height); | 
|  | *              return; | 
|  | *          } | 
|  | *          g.drawImage(bg, 0, 0, this); | 
|  | *          if (tracker.statusID(1, false) == MediaTracker.COMPLETE) { | 
|  | *              g.drawImage(anim[index], 10, 10, this); | 
|  | *          } | 
|  | *      } | 
|  | * } | 
|  | * } </pre></blockquote><hr> | 
|  | * | 
|  | * @author      Jim Graham | 
|  | * @since       JDK1.0 | 
|  | */ | 
|  | public class MediaTracker implements java.io.Serializable { | 
|  |  | 
|  | /** | 
|  | * A given <code>Component</code> that will be | 
|  | * tracked by a media tracker where the image will | 
|  | * eventually be drawn. | 
|  | * | 
|  | * @serial | 
|  | * @see #MediaTracker(Component) | 
|  | */ | 
|  | Component target; | 
|  | /** | 
|  | * The head of the list of <code>Images</code> that is being | 
|  | * tracked by the <code>MediaTracker</code>. | 
|  | * | 
|  | * @serial | 
|  | * @see #addImage(Image, int) | 
|  | * @see #removeImage(Image) | 
|  | */ | 
|  | MediaEntry head; | 
|  |  | 
|  | /* | 
|  | * JDK 1.1 serialVersionUID | 
|  | */ | 
|  | private static final long serialVersionUID = -483174189758638095L; | 
|  |  | 
|  | /** | 
|  | * Creates a media tracker to track images for a given component. | 
|  | * @param     comp the component on which the images | 
|  | *                     will eventually be drawn | 
|  | */ | 
|  | public MediaTracker(Component comp) { | 
|  | target = comp; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Adds an image to the list of images being tracked by this media | 
|  | * tracker. The image will eventually be rendered at its default | 
|  | * (unscaled) size. | 
|  | * @param     image   the image to be tracked | 
|  | * @param     id      an identifier used to track this image | 
|  | */ | 
|  | public void addImage(Image image, int id) { | 
|  | addImage(image, id, -1, -1); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Adds a scaled image to the list of images being tracked | 
|  | * by this media tracker. The image will eventually be | 
|  | * rendered at the indicated width and height. | 
|  | * | 
|  | * @param     image   the image to be tracked | 
|  | * @param     id   an identifier that can be used to track this image | 
|  | * @param     w    the width at which the image is rendered | 
|  | * @param     h    the height at which the image is rendered | 
|  | */ | 
|  | public synchronized void addImage(Image image, int id, int w, int h) { | 
|  | addImageImpl(image, id, w, h); | 
|  | Image rvImage = getResolutionVariant(image); | 
|  | if (rvImage != null) { | 
|  | addImageImpl(rvImage, id, | 
|  | w == -1 ? -1 : 2 * w, | 
|  | h == -1 ? -1 : 2 * h); | 
|  | } | 
|  | } | 
|  |  | 
|  | private void addImageImpl(Image image, int id, int w, int h) { | 
|  | head = MediaEntry.insert(head, | 
|  | new ImageMediaEntry(this, image, id, w, h)); | 
|  | } | 
|  | /** | 
|  | * Flag indicating that media is currently being loaded. | 
|  | * @see         java.awt.MediaTracker#statusAll | 
|  | * @see         java.awt.MediaTracker#statusID | 
|  | */ | 
|  | public static final int LOADING = 1; | 
|  |  | 
|  | /** | 
|  | * Flag indicating that the downloading of media was aborted. | 
|  | * @see         java.awt.MediaTracker#statusAll | 
|  | * @see         java.awt.MediaTracker#statusID | 
|  | */ | 
|  | public static final int ABORTED = 2; | 
|  |  | 
|  | /** | 
|  | * Flag indicating that the downloading of media encountered | 
|  | * an error. | 
|  | * @see         java.awt.MediaTracker#statusAll | 
|  | * @see         java.awt.MediaTracker#statusID | 
|  | */ | 
|  | public static final int ERRORED = 4; | 
|  |  | 
|  | /** | 
|  | * Flag indicating that the downloading of media was completed | 
|  | * successfully. | 
|  | * @see         java.awt.MediaTracker#statusAll | 
|  | * @see         java.awt.MediaTracker#statusID | 
|  | */ | 
|  | public static final int COMPLETE = 8; | 
|  |  | 
|  | static final int DONE = (ABORTED | ERRORED | COMPLETE); | 
|  |  | 
|  | /** | 
|  | * Checks to see if all images being tracked by this media tracker | 
|  | * have finished loading. | 
|  | * <p> | 
|  | * This method does not start loading the images if they are not | 
|  | * already loading. | 
|  | * <p> | 
|  | * If there is an error while loading or scaling an image, then that | 
|  | * image is considered to have finished loading. Use the | 
|  | * <code>isErrorAny</code> or <code>isErrorID</code> methods to | 
|  | * check for errors. | 
|  | * @return      <code>true</code> if all images have finished loading, | 
|  | *                       have been aborted, or have encountered | 
|  | *                       an error; <code>false</code> otherwise | 
|  | * @see         java.awt.MediaTracker#checkAll(boolean) | 
|  | * @see         java.awt.MediaTracker#checkID | 
|  | * @see         java.awt.MediaTracker#isErrorAny | 
|  | * @see         java.awt.MediaTracker#isErrorID | 
|  | */ | 
|  | public boolean checkAll() { | 
|  | return checkAll(false, true); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks to see if all images being tracked by this media tracker | 
|  | * have finished loading. | 
|  | * <p> | 
|  | * If the value of the <code>load</code> flag is <code>true</code>, | 
|  | * then this method starts loading any images that are not yet | 
|  | * being loaded. | 
|  | * <p> | 
|  | * If there is an error while loading or scaling an image, that | 
|  | * image is considered to have finished loading. Use the | 
|  | * <code>isErrorAny</code> and <code>isErrorID</code> methods to | 
|  | * check for errors. | 
|  | * @param       load   if <code>true</code>, start loading any | 
|  | *                       images that are not yet being loaded | 
|  | * @return      <code>true</code> if all images have finished loading, | 
|  | *                       have been aborted, or have encountered | 
|  | *                       an error; <code>false</code> otherwise | 
|  | * @see         java.awt.MediaTracker#checkID | 
|  | * @see         java.awt.MediaTracker#checkAll() | 
|  | * @see         java.awt.MediaTracker#isErrorAny() | 
|  | * @see         java.awt.MediaTracker#isErrorID(int) | 
|  | */ | 
|  | public boolean checkAll(boolean load) { | 
|  | return checkAll(load, true); | 
|  | } | 
|  |  | 
|  | private synchronized boolean checkAll(boolean load, boolean verify) { | 
|  | MediaEntry cur = head; | 
|  | boolean done = true; | 
|  | while (cur != null) { | 
|  | if ((cur.getStatus(load, verify) & DONE) == 0) { | 
|  | done = false; | 
|  | } | 
|  | cur = cur.next; | 
|  | } | 
|  | return done; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks the error status of all of the images. | 
|  | * @return   <code>true</code> if any of the images tracked | 
|  | *                  by this media tracker had an error during | 
|  | *                  loading; <code>false</code> otherwise | 
|  | * @see      java.awt.MediaTracker#isErrorID | 
|  | * @see      java.awt.MediaTracker#getErrorsAny | 
|  | */ | 
|  | public synchronized boolean isErrorAny() { | 
|  | MediaEntry cur = head; | 
|  | while (cur != null) { | 
|  | if ((cur.getStatus(false, true) & ERRORED) != 0) { | 
|  | return true; | 
|  | } | 
|  | cur = cur.next; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a list of all media that have encountered an error. | 
|  | * @return       an array of media objects tracked by this | 
|  | *                        media tracker that have encountered | 
|  | *                        an error, or <code>null</code> if | 
|  | *                        there are none with errors | 
|  | * @see          java.awt.MediaTracker#isErrorAny | 
|  | * @see          java.awt.MediaTracker#getErrorsID | 
|  | */ | 
|  | public synchronized Object[] getErrorsAny() { | 
|  | MediaEntry cur = head; | 
|  | int numerrors = 0; | 
|  | while (cur != null) { | 
|  | if ((cur.getStatus(false, true) & ERRORED) != 0) { | 
|  | numerrors++; | 
|  | } | 
|  | cur = cur.next; | 
|  | } | 
|  | if (numerrors == 0) { | 
|  | return null; | 
|  | } | 
|  | Object errors[] = new Object[numerrors]; | 
|  | cur = head; | 
|  | numerrors = 0; | 
|  | while (cur != null) { | 
|  | if ((cur.getStatus(false, false) & ERRORED) != 0) { | 
|  | errors[numerrors++] = cur.getMedia(); | 
|  | } | 
|  | cur = cur.next; | 
|  | } | 
|  | return errors; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Starts loading all images tracked by this media tracker. This | 
|  | * method waits until all the images being tracked have finished | 
|  | * loading. | 
|  | * <p> | 
|  | * If there is an error while loading or scaling an image, then that | 
|  | * image is considered to have finished loading. Use the | 
|  | * <code>isErrorAny</code> or <code>isErrorID</code> methods to | 
|  | * check for errors. | 
|  | * @see         java.awt.MediaTracker#waitForID(int) | 
|  | * @see         java.awt.MediaTracker#waitForAll(long) | 
|  | * @see         java.awt.MediaTracker#isErrorAny | 
|  | * @see         java.awt.MediaTracker#isErrorID | 
|  | * @exception   InterruptedException  if any thread has | 
|  | *                                     interrupted this thread | 
|  | */ | 
|  | public void waitForAll() throws InterruptedException { | 
|  | waitForAll(0); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Starts loading all images tracked by this media tracker. This | 
|  | * method waits until all the images being tracked have finished | 
|  | * loading, or until the length of time specified in milliseconds | 
|  | * by the <code>ms</code> argument has passed. | 
|  | * <p> | 
|  | * If there is an error while loading or scaling an image, then | 
|  | * that image is considered to have finished loading. Use the | 
|  | * <code>isErrorAny</code> or <code>isErrorID</code> methods to | 
|  | * check for errors. | 
|  | * @param       ms       the number of milliseconds to wait | 
|  | *                       for the loading to complete | 
|  | * @return      <code>true</code> if all images were successfully | 
|  | *                       loaded; <code>false</code> otherwise | 
|  | * @see         java.awt.MediaTracker#waitForID(int) | 
|  | * @see         java.awt.MediaTracker#waitForAll(long) | 
|  | * @see         java.awt.MediaTracker#isErrorAny | 
|  | * @see         java.awt.MediaTracker#isErrorID | 
|  | * @exception   InterruptedException  if any thread has | 
|  | *                                     interrupted this thread. | 
|  | */ | 
|  | public synchronized boolean waitForAll(long ms) | 
|  | throws InterruptedException | 
|  | { | 
|  | long end = System.currentTimeMillis() + ms; | 
|  | boolean first = true; | 
|  | while (true) { | 
|  | int status = statusAll(first, first); | 
|  | if ((status & LOADING) == 0) { | 
|  | return (status == COMPLETE); | 
|  | } | 
|  | first = false; | 
|  | long timeout; | 
|  | if (ms == 0) { | 
|  | timeout = 0; | 
|  | } else { | 
|  | timeout = end - System.currentTimeMillis(); | 
|  | if (timeout <= 0) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | wait(timeout); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Calculates and returns the bitwise inclusive <b>OR</b> of the | 
|  | * status of all media that are tracked by this media tracker. | 
|  | * <p> | 
|  | * Possible flags defined by the | 
|  | * <code>MediaTracker</code> class are <code>LOADING</code>, | 
|  | * <code>ABORTED</code>, <code>ERRORED</code>, and | 
|  | * <code>COMPLETE</code>. An image that hasn't started | 
|  | * loading has zero as its status. | 
|  | * <p> | 
|  | * If the value of <code>load</code> is <code>true</code>, then | 
|  | * this method starts loading any images that are not yet being loaded. | 
|  | * | 
|  | * @param        load   if <code>true</code>, start loading | 
|  | *                            any images that are not yet being loaded | 
|  | * @return       the bitwise inclusive <b>OR</b> of the status of | 
|  | *                            all of the media being tracked | 
|  | * @see          java.awt.MediaTracker#statusID(int, boolean) | 
|  | * @see          java.awt.MediaTracker#LOADING | 
|  | * @see          java.awt.MediaTracker#ABORTED | 
|  | * @see          java.awt.MediaTracker#ERRORED | 
|  | * @see          java.awt.MediaTracker#COMPLETE | 
|  | */ | 
|  | public int statusAll(boolean load) { | 
|  | return statusAll(load, true); | 
|  | } | 
|  |  | 
|  | private synchronized int statusAll(boolean load, boolean verify) { | 
|  | MediaEntry cur = head; | 
|  | int status = 0; | 
|  | while (cur != null) { | 
|  | status = status | cur.getStatus(load, verify); | 
|  | cur = cur.next; | 
|  | } | 
|  | return status; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks to see if all images tracked by this media tracker that | 
|  | * are tagged with the specified identifier have finished loading. | 
|  | * <p> | 
|  | * This method does not start loading the images if they are not | 
|  | * already loading. | 
|  | * <p> | 
|  | * If there is an error while loading or scaling an image, then that | 
|  | * image is considered to have finished loading. Use the | 
|  | * <code>isErrorAny</code> or <code>isErrorID</code> methods to | 
|  | * check for errors. | 
|  | * @param       id   the identifier of the images to check | 
|  | * @return      <code>true</code> if all images have finished loading, | 
|  | *                       have been aborted, or have encountered | 
|  | *                       an error; <code>false</code> otherwise | 
|  | * @see         java.awt.MediaTracker#checkID(int, boolean) | 
|  | * @see         java.awt.MediaTracker#checkAll() | 
|  | * @see         java.awt.MediaTracker#isErrorAny() | 
|  | * @see         java.awt.MediaTracker#isErrorID(int) | 
|  | */ | 
|  | public boolean checkID(int id) { | 
|  | return checkID(id, false, true); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks to see if all images tracked by this media tracker that | 
|  | * are tagged with the specified identifier have finished loading. | 
|  | * <p> | 
|  | * If the value of the <code>load</code> flag is <code>true</code>, | 
|  | * then this method starts loading any images that are not yet | 
|  | * being loaded. | 
|  | * <p> | 
|  | * If there is an error while loading or scaling an image, then that | 
|  | * image is considered to have finished loading. Use the | 
|  | * <code>isErrorAny</code> or <code>isErrorID</code> methods to | 
|  | * check for errors. | 
|  | * @param       id       the identifier of the images to check | 
|  | * @param       load     if <code>true</code>, start loading any | 
|  | *                       images that are not yet being loaded | 
|  | * @return      <code>true</code> if all images have finished loading, | 
|  | *                       have been aborted, or have encountered | 
|  | *                       an error; <code>false</code> otherwise | 
|  | * @see         java.awt.MediaTracker#checkID(int, boolean) | 
|  | * @see         java.awt.MediaTracker#checkAll() | 
|  | * @see         java.awt.MediaTracker#isErrorAny() | 
|  | * @see         java.awt.MediaTracker#isErrorID(int) | 
|  | */ | 
|  | public boolean checkID(int id, boolean load) { | 
|  | return checkID(id, load, true); | 
|  | } | 
|  |  | 
|  | private synchronized boolean checkID(int id, boolean load, boolean verify) | 
|  | { | 
|  | MediaEntry cur = head; | 
|  | boolean done = true; | 
|  | while (cur != null) { | 
|  | if (cur.getID() == id | 
|  | && (cur.getStatus(load, verify) & DONE) == 0) | 
|  | { | 
|  | done = false; | 
|  | } | 
|  | cur = cur.next; | 
|  | } | 
|  | return done; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks the error status of all of the images tracked by this | 
|  | * media tracker with the specified identifier. | 
|  | * @param        id   the identifier of the images to check | 
|  | * @return       <code>true</code> if any of the images with the | 
|  | *                          specified identifier had an error during | 
|  | *                          loading; <code>false</code> otherwise | 
|  | * @see          java.awt.MediaTracker#isErrorAny | 
|  | * @see          java.awt.MediaTracker#getErrorsID | 
|  | */ | 
|  | public synchronized boolean isErrorID(int id) { | 
|  | MediaEntry cur = head; | 
|  | while (cur != null) { | 
|  | if (cur.getID() == id | 
|  | && (cur.getStatus(false, true) & ERRORED) != 0) | 
|  | { | 
|  | return true; | 
|  | } | 
|  | cur = cur.next; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a list of media with the specified ID that | 
|  | * have encountered an error. | 
|  | * @param       id   the identifier of the images to check | 
|  | * @return      an array of media objects tracked by this media | 
|  | *                       tracker with the specified identifier | 
|  | *                       that have encountered an error, or | 
|  | *                       <code>null</code> if there are none with errors | 
|  | * @see         java.awt.MediaTracker#isErrorID | 
|  | * @see         java.awt.MediaTracker#isErrorAny | 
|  | * @see         java.awt.MediaTracker#getErrorsAny | 
|  | */ | 
|  | public synchronized Object[] getErrorsID(int id) { | 
|  | MediaEntry cur = head; | 
|  | int numerrors = 0; | 
|  | while (cur != null) { | 
|  | if (cur.getID() == id | 
|  | && (cur.getStatus(false, true) & ERRORED) != 0) | 
|  | { | 
|  | numerrors++; | 
|  | } | 
|  | cur = cur.next; | 
|  | } | 
|  | if (numerrors == 0) { | 
|  | return null; | 
|  | } | 
|  | Object errors[] = new Object[numerrors]; | 
|  | cur = head; | 
|  | numerrors = 0; | 
|  | while (cur != null) { | 
|  | if (cur.getID() == id | 
|  | && (cur.getStatus(false, false) & ERRORED) != 0) | 
|  | { | 
|  | errors[numerrors++] = cur.getMedia(); | 
|  | } | 
|  | cur = cur.next; | 
|  | } | 
|  | return errors; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Starts loading all images tracked by this media tracker with the | 
|  | * specified identifier. This method waits until all the images with | 
|  | * the specified identifier have finished loading. | 
|  | * <p> | 
|  | * If there is an error while loading or scaling an image, then that | 
|  | * image is considered to have finished loading. Use the | 
|  | * <code>isErrorAny</code> and <code>isErrorID</code> methods to | 
|  | * check for errors. | 
|  | * @param         id   the identifier of the images to check | 
|  | * @see           java.awt.MediaTracker#waitForAll | 
|  | * @see           java.awt.MediaTracker#isErrorAny() | 
|  | * @see           java.awt.MediaTracker#isErrorID(int) | 
|  | * @exception     InterruptedException  if any thread has | 
|  | *                          interrupted this thread. | 
|  | */ | 
|  | public void waitForID(int id) throws InterruptedException { | 
|  | waitForID(id, 0); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Starts loading all images tracked by this media tracker with the | 
|  | * specified identifier. This method waits until all the images with | 
|  | * the specified identifier have finished loading, or until the | 
|  | * length of time specified in milliseconds by the <code>ms</code> | 
|  | * argument has passed. | 
|  | * <p> | 
|  | * If there is an error while loading or scaling an image, then that | 
|  | * image is considered to have finished loading. Use the | 
|  | * <code>statusID</code>, <code>isErrorID</code>, and | 
|  | * <code>isErrorAny</code> methods to check for errors. | 
|  | * @param         id   the identifier of the images to check | 
|  | * @param         ms   the length of time, in milliseconds, to wait | 
|  | *                           for the loading to complete | 
|  | * @see           java.awt.MediaTracker#waitForAll | 
|  | * @see           java.awt.MediaTracker#waitForID(int) | 
|  | * @see           java.awt.MediaTracker#statusID | 
|  | * @see           java.awt.MediaTracker#isErrorAny() | 
|  | * @see           java.awt.MediaTracker#isErrorID(int) | 
|  | * @exception     InterruptedException  if any thread has | 
|  | *                          interrupted this thread. | 
|  | */ | 
|  | public synchronized boolean waitForID(int id, long ms) | 
|  | throws InterruptedException | 
|  | { | 
|  | long end = System.currentTimeMillis() + ms; | 
|  | boolean first = true; | 
|  | while (true) { | 
|  | int status = statusID(id, first, first); | 
|  | if ((status & LOADING) == 0) { | 
|  | return (status == COMPLETE); | 
|  | } | 
|  | first = false; | 
|  | long timeout; | 
|  | if (ms == 0) { | 
|  | timeout = 0; | 
|  | } else { | 
|  | timeout = end - System.currentTimeMillis(); | 
|  | if (timeout <= 0) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | wait(timeout); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Calculates and returns the bitwise inclusive <b>OR</b> of the | 
|  | * status of all media with the specified identifier that are | 
|  | * tracked by this media tracker. | 
|  | * <p> | 
|  | * Possible flags defined by the | 
|  | * <code>MediaTracker</code> class are <code>LOADING</code>, | 
|  | * <code>ABORTED</code>, <code>ERRORED</code>, and | 
|  | * <code>COMPLETE</code>. An image that hasn't started | 
|  | * loading has zero as its status. | 
|  | * <p> | 
|  | * If the value of <code>load</code> is <code>true</code>, then | 
|  | * this method starts loading any images that are not yet being loaded. | 
|  | * @param        id   the identifier of the images to check | 
|  | * @param        load   if <code>true</code>, start loading | 
|  | *                            any images that are not yet being loaded | 
|  | * @return       the bitwise inclusive <b>OR</b> of the status of | 
|  | *                            all of the media with the specified | 
|  | *                            identifier that are being tracked | 
|  | * @see          java.awt.MediaTracker#statusAll(boolean) | 
|  | * @see          java.awt.MediaTracker#LOADING | 
|  | * @see          java.awt.MediaTracker#ABORTED | 
|  | * @see          java.awt.MediaTracker#ERRORED | 
|  | * @see          java.awt.MediaTracker#COMPLETE | 
|  | */ | 
|  | public int statusID(int id, boolean load) { | 
|  | return statusID(id, load, true); | 
|  | } | 
|  |  | 
|  | private synchronized int statusID(int id, boolean load, boolean verify) { | 
|  | MediaEntry cur = head; | 
|  | int status = 0; | 
|  | while (cur != null) { | 
|  | if (cur.getID() == id) { | 
|  | status = status | cur.getStatus(load, verify); | 
|  | } | 
|  | cur = cur.next; | 
|  | } | 
|  | return status; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Removes the specified image from this media tracker. | 
|  | * All instances of the specified image are removed, | 
|  | * regardless of scale or ID. | 
|  | * @param   image     the image to be removed | 
|  | * @see     java.awt.MediaTracker#removeImage(java.awt.Image, int) | 
|  | * @see     java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int) | 
|  | * @since   JDK1.1 | 
|  | */ | 
|  | public synchronized void removeImage(Image image) { | 
|  | removeImageImpl(image); | 
|  | Image rvImage = getResolutionVariant(image); | 
|  | if (rvImage != null) { | 
|  | removeImageImpl(rvImage); | 
|  | } | 
|  | notifyAll();    // Notify in case remaining images are "done". | 
|  | } | 
|  |  | 
|  | private void removeImageImpl(Image image) { | 
|  | MediaEntry cur = head; | 
|  | MediaEntry prev = null; | 
|  | while (cur != null) { | 
|  | MediaEntry next = cur.next; | 
|  | if (cur.getMedia() == image) { | 
|  | if (prev == null) { | 
|  | head = next; | 
|  | } else { | 
|  | prev.next = next; | 
|  | } | 
|  | cur.cancel(); | 
|  | } else { | 
|  | prev = cur; | 
|  | } | 
|  | cur = next; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Removes the specified image from the specified tracking | 
|  | * ID of this media tracker. | 
|  | * All instances of <code>Image</code> being tracked | 
|  | * under the specified ID are removed regardless of scale. | 
|  | * @param      image the image to be removed | 
|  | * @param      id the tracking ID from which to remove the image | 
|  | * @see        java.awt.MediaTracker#removeImage(java.awt.Image) | 
|  | * @see        java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int) | 
|  | * @since      JDK1.1 | 
|  | */ | 
|  | public synchronized void removeImage(Image image, int id) { | 
|  | removeImageImpl(image, id); | 
|  | Image rvImage = getResolutionVariant(image); | 
|  | if (rvImage != null) { | 
|  | removeImageImpl(rvImage, id); | 
|  | } | 
|  | notifyAll();    // Notify in case remaining images are "done". | 
|  | } | 
|  |  | 
|  | private void removeImageImpl(Image image, int id) { | 
|  | MediaEntry cur = head; | 
|  | MediaEntry prev = null; | 
|  | while (cur != null) { | 
|  | MediaEntry next = cur.next; | 
|  | if (cur.getID() == id && cur.getMedia() == image) { | 
|  | if (prev == null) { | 
|  | head = next; | 
|  | } else { | 
|  | prev.next = next; | 
|  | } | 
|  | cur.cancel(); | 
|  | } else { | 
|  | prev = cur; | 
|  | } | 
|  | cur = next; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Removes the specified image with the specified | 
|  | * width, height, and ID from this media tracker. | 
|  | * Only the specified instance (with any duplicates) is removed. | 
|  | * @param   image the image to be removed | 
|  | * @param   id the tracking ID from which to remove the image | 
|  | * @param   width the width to remove (-1 for unscaled) | 
|  | * @param   height the height to remove (-1 for unscaled) | 
|  | * @see     java.awt.MediaTracker#removeImage(java.awt.Image) | 
|  | * @see     java.awt.MediaTracker#removeImage(java.awt.Image, int) | 
|  | * @since   JDK1.1 | 
|  | */ | 
|  | public synchronized void removeImage(Image image, int id, | 
|  | int width, int height) { | 
|  | removeImageImpl(image, id, width, height); | 
|  | Image rvImage = getResolutionVariant(image); | 
|  | if (rvImage != null) { | 
|  | removeImageImpl(rvImage, id, | 
|  | width == -1 ? -1 : 2 * width, | 
|  | height == -1 ? -1 : 2 * height); | 
|  | } | 
|  | notifyAll();    // Notify in case remaining images are "done". | 
|  | } | 
|  |  | 
|  | private void removeImageImpl(Image image, int id, int width, int height) { | 
|  | MediaEntry cur = head; | 
|  | MediaEntry prev = null; | 
|  | while (cur != null) { | 
|  | MediaEntry next = cur.next; | 
|  | if (cur.getID() == id && cur instanceof ImageMediaEntry | 
|  | && ((ImageMediaEntry) cur).matches(image, width, height)) | 
|  | { | 
|  | if (prev == null) { | 
|  | head = next; | 
|  | } else { | 
|  | prev.next = next; | 
|  | } | 
|  | cur.cancel(); | 
|  | } else { | 
|  | prev = cur; | 
|  | } | 
|  | cur = next; | 
|  | } | 
|  | } | 
|  |  | 
|  | synchronized void setDone() { | 
|  | notifyAll(); | 
|  | } | 
|  |  | 
|  | private static Image getResolutionVariant(Image image) { | 
|  | if (image instanceof MultiResolutionToolkitImage) { | 
|  | return ((MultiResolutionToolkitImage) image).getResolutionVariant(); | 
|  | } | 
|  | return null; | 
|  | } | 
|  | } | 
|  |  | 
|  | abstract class MediaEntry { | 
|  | MediaTracker tracker; | 
|  | int ID; | 
|  | MediaEntry next; | 
|  |  | 
|  | int status; | 
|  | boolean cancelled; | 
|  |  | 
|  | MediaEntry(MediaTracker mt, int id) { | 
|  | tracker = mt; | 
|  | ID = id; | 
|  | } | 
|  |  | 
|  | abstract Object getMedia(); | 
|  |  | 
|  | static MediaEntry insert(MediaEntry head, MediaEntry me) { | 
|  | MediaEntry cur = head; | 
|  | MediaEntry prev = null; | 
|  | while (cur != null) { | 
|  | if (cur.ID > me.ID) { | 
|  | break; | 
|  | } | 
|  | prev = cur; | 
|  | cur = cur.next; | 
|  | } | 
|  | me.next = cur; | 
|  | if (prev == null) { | 
|  | head = me; | 
|  | } else { | 
|  | prev.next = me; | 
|  | } | 
|  | return head; | 
|  | } | 
|  |  | 
|  | int getID() { | 
|  | return ID; | 
|  | } | 
|  |  | 
|  | abstract void startLoad(); | 
|  |  | 
|  | void cancel() { | 
|  | cancelled = true; | 
|  | } | 
|  |  | 
|  | static final int LOADING = MediaTracker.LOADING; | 
|  | static final int ABORTED = MediaTracker.ABORTED; | 
|  | static final int ERRORED = MediaTracker.ERRORED; | 
|  | static final int COMPLETE = MediaTracker.COMPLETE; | 
|  |  | 
|  | static final int LOADSTARTED = (LOADING | ERRORED | COMPLETE); | 
|  | static final int DONE = (ABORTED | ERRORED | COMPLETE); | 
|  |  | 
|  | synchronized int getStatus(boolean doLoad, boolean doVerify) { | 
|  | if (doLoad && ((status & LOADSTARTED) == 0)) { | 
|  | status = (status & ~ABORTED) | LOADING; | 
|  | startLoad(); | 
|  | } | 
|  | return status; | 
|  | } | 
|  |  | 
|  | void setStatus(int flag) { | 
|  | synchronized (this) { | 
|  | status = flag; | 
|  | } | 
|  | tracker.setDone(); | 
|  | } | 
|  | } | 
|  |  | 
|  | class ImageMediaEntry extends MediaEntry implements ImageObserver, | 
|  | java.io.Serializable { | 
|  | Image image; | 
|  | int width; | 
|  | int height; | 
|  |  | 
|  | /* | 
|  | * JDK 1.1 serialVersionUID | 
|  | */ | 
|  | private static final long serialVersionUID = 4739377000350280650L; | 
|  |  | 
|  | ImageMediaEntry(MediaTracker mt, Image img, int c, int w, int h) { | 
|  | super(mt, c); | 
|  | image = img; | 
|  | width = w; | 
|  | height = h; | 
|  | } | 
|  |  | 
|  | boolean matches(Image img, int w, int h) { | 
|  | return (image == img && width == w && height == h); | 
|  | } | 
|  |  | 
|  | Object getMedia() { | 
|  | return image; | 
|  | } | 
|  |  | 
|  | synchronized int getStatus(boolean doLoad, boolean doVerify) { | 
|  | if (doVerify) { | 
|  | int flags = tracker.target.checkImage(image, width, height, null); | 
|  | int s = parseflags(flags); | 
|  | if (s == 0) { | 
|  | if ((status & (ERRORED | COMPLETE)) != 0) { | 
|  | setStatus(ABORTED); | 
|  | } | 
|  | } else if (s != status) { | 
|  | setStatus(s); | 
|  | } | 
|  | } | 
|  | return super.getStatus(doLoad, doVerify); | 
|  | } | 
|  |  | 
|  | void startLoad() { | 
|  | if (tracker.target.prepareImage(image, width, height, this)) { | 
|  | setStatus(COMPLETE); | 
|  | } | 
|  | } | 
|  |  | 
|  | int parseflags(int infoflags) { | 
|  | if ((infoflags & ERROR) != 0) { | 
|  | return ERRORED; | 
|  | } else if ((infoflags & ABORT) != 0) { | 
|  | return ABORTED; | 
|  | } else if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) { | 
|  | return COMPLETE; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | public boolean imageUpdate(Image img, int infoflags, | 
|  | int x, int y, int w, int h) { | 
|  | if (cancelled) { | 
|  | return false; | 
|  | } | 
|  | int s = parseflags(infoflags); | 
|  | if (s != 0 && s != status) { | 
|  | setStatus(s); | 
|  | } | 
|  | return ((status & LOADING) != 0); | 
|  | } | 
|  | } |