1. /*
  2. * @(#)MediaTracker.java 1.42 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt;
  8. import java.awt.Component;
  9. import java.awt.Image;
  10. import java.awt.Graphics;
  11. import java.awt.image.ImageObserver;
  12. /**
  13. * The <code>MediaTracker</code> class is a utility class to track
  14. * the status of a number of media objects. Media objects could
  15. * include audio clips as well as images, though currently only
  16. * images are supported.
  17. * <p>
  18. * To use a media tracker, create an instance of
  19. * <code>MediaTracker</code> and call its <code>addImage</code>
  20. * method for each image to be tracked. In addition, each image can
  21. * be assigned a unique identifier. This identifier controls the
  22. * priority order in which the images are fetched. It can also be used
  23. * to identify unique subsets of the images that can be waited on
  24. * independently. Images with a lower ID are loaded in preference to
  25. * those with a higher ID number.
  26. *
  27. * <p>
  28. *
  29. * Tracking an animated image
  30. * might not always be useful
  31. * due to the multi-part nature of animated image
  32. * loading and painting,
  33. * but it is supported.
  34. * <code>MediaTracker</code> treats an animated image
  35. * as completely loaded
  36. * when the first frame is completely loaded.
  37. * At that point, the <code>MediaTracker</code>
  38. * signals any waiters
  39. * that the image is completely loaded.
  40. * If no <code>ImageObserver</code>s are observing the image
  41. * when the first frame has finished loading,
  42. * the image might flush itself
  43. * to conserve resources
  44. * (see {@link Image#flush()}).
  45. *
  46. * <p>
  47. * Here is an example of using <code>MediaTracker</code>:
  48. * <p>
  49. * <hr><blockquote><pre>
  50. * import java.applet.Applet;
  51. * import java.awt.Color;
  52. * import java.awt.Image;
  53. * import java.awt.Graphics;
  54. * import java.awt.MediaTracker;
  55. *
  56. * public class ImageBlaster extends Applet implements Runnable {
  57. * MediaTracker tracker;
  58. * Image bg;
  59. * Image anim[] = new Image[5];
  60. * int index;
  61. * Thread animator;
  62. *
  63. * // Get the images for the background (id == 0)
  64. * // and the animation frames (id == 1)
  65. * // and add them to the MediaTracker
  66. * public void init() {
  67. * tracker = new MediaTracker(this);
  68. * bg = getImage(getDocumentBase(),
  69. * "images/background.gif");
  70. * tracker.addImage(bg, 0);
  71. * for (int i = 0; i < 5; i++) {
  72. * anim[i] = getImage(getDocumentBase(),
  73. * "images/anim"+i+".gif");
  74. * tracker.addImage(anim[i], 1);
  75. * }
  76. * }
  77. *
  78. * // Start the animation thread.
  79. * public void start() {
  80. * animator = new Thread(this);
  81. * animator.start();
  82. * }
  83. *
  84. * // Stop the animation thread.
  85. * public void stop() {
  86. * animator = null;
  87. * }
  88. *
  89. * // Run the animation thread.
  90. * // First wait for the background image to fully load
  91. * // and paint. Then wait for all of the animation
  92. * // frames to finish loading. Finally, loop and
  93. * // increment the animation frame index.
  94. * public void run() {
  95. * try {
  96. * tracker.waitForID(0);
  97. * tracker.waitForID(1);
  98. * } catch (InterruptedException e) {
  99. * return;
  100. * }
  101. * Thread me = Thread.currentThread();
  102. * while (animator == me) {
  103. * try {
  104. * Thread.sleep(100);
  105. * } catch (InterruptedException e) {
  106. * break;
  107. * }
  108. * synchronized (this) {
  109. * index++;
  110. * if (index >= anim.length) {
  111. * index = 0;
  112. * }
  113. * }
  114. * repaint();
  115. * }
  116. * }
  117. *
  118. * // The background image fills the frame so we
  119. * // don't need to clear the applet on repaints.
  120. * // Just call the paint method.
  121. * public void update(Graphics g) {
  122. * paint(g);
  123. * }
  124. *
  125. * // Paint a large red rectangle if there are any errors
  126. * // loading the images. Otherwise always paint the
  127. * // background so that it appears incrementally as it
  128. * // is loading. Finally, only paint the current animation
  129. * // frame if all of the frames (id == 1) are done loading,
  130. * // so that we don't get partial animations.
  131. * public void paint(Graphics g) {
  132. * if ((tracker.statusAll(false) & MediaTracker.ERRORED) != 0) {
  133. * g.setColor(Color.red);
  134. * g.fillRect(0, 0, size().width, size().height);
  135. * return;
  136. * }
  137. * g.drawImage(bg, 0, 0, this);
  138. * if (tracker.statusID(1, false) == MediaTracker.COMPLETE) {
  139. * g.drawImage(anim[index], 10, 10, this);
  140. * }
  141. * }
  142. * }
  143. * </pre></blockquote><hr>
  144. *
  145. * @version 1.42, 12/19/03
  146. * @author Jim Graham
  147. * @since JDK1.0
  148. */
  149. public class MediaTracker implements java.io.Serializable {
  150. /**
  151. * A given <code>Component</code> that will be
  152. * tracked by a media tracker where the image will
  153. * eventually be drawn.
  154. *
  155. * @serial
  156. * @see #MediaTracker(Component)
  157. */
  158. Component target;
  159. /**
  160. * The head of the list of <code>Images</code> that is being
  161. * tracked by the <code>MediaTracker</code>.
  162. *
  163. * @serial
  164. * @see #addImage(Image, int)
  165. * @see #removeImage(Image)
  166. */
  167. MediaEntry head;
  168. /*
  169. * JDK 1.1 serialVersionUID
  170. */
  171. private static final long serialVersionUID = -483174189758638095L;
  172. /**
  173. * Creates a media tracker to track images for a given component.
  174. * @param comp the component on which the images
  175. * will eventually be drawn
  176. */
  177. public MediaTracker(Component comp) {
  178. target = comp;
  179. }
  180. /**
  181. * Adds an image to the list of images being tracked by this media
  182. * tracker. The image will eventually be rendered at its default
  183. * (unscaled) size.
  184. * @param image the image to be tracked
  185. * @param id an identifier used to track this image
  186. */
  187. public void addImage(Image image, int id) {
  188. addImage(image, id, -1, -1);
  189. }
  190. /**
  191. * Adds a scaled image to the list of images being tracked
  192. * by this media tracker. The image will eventually be
  193. * rendered at the indicated width and height.
  194. *
  195. * @param image the image to be tracked
  196. * @param id an identifier that can be used to track this image
  197. * @param w the width at which the image is rendered
  198. * @param h the height at which the image is rendered
  199. */
  200. public synchronized void addImage(Image image, int id, int w, int h) {
  201. head = MediaEntry.insert(head,
  202. new ImageMediaEntry(this, image, id, w, h));
  203. }
  204. /**
  205. * Flag indicating that media is currently being loaded.
  206. * @see java.awt.MediaTracker#statusAll
  207. * @see java.awt.MediaTracker#statusID
  208. */
  209. public static final int LOADING = 1;
  210. /**
  211. * Flag indicating that the downloading of media was aborted.
  212. * @see java.awt.MediaTracker#statusAll
  213. * @see java.awt.MediaTracker#statusID
  214. */
  215. public static final int ABORTED = 2;
  216. /**
  217. * Flag indicating that the downloading of media encountered
  218. * an error.
  219. * @see java.awt.MediaTracker#statusAll
  220. * @see java.awt.MediaTracker#statusID
  221. */
  222. public static final int ERRORED = 4;
  223. /**
  224. * Flag indicating that the downloading of media was completed
  225. * successfully.
  226. * @see java.awt.MediaTracker#statusAll
  227. * @see java.awt.MediaTracker#statusID
  228. */
  229. public static final int COMPLETE = 8;
  230. static final int DONE = (ABORTED | ERRORED | COMPLETE);
  231. /**
  232. * Checks to see if all images being tracked by this media tracker
  233. * have finished loading.
  234. * <p>
  235. * This method does not start loading the images if they are not
  236. * already loading.
  237. * <p>
  238. * If there is an error while loading or scaling an image, then that
  239. * image is considered to have finished loading. Use the
  240. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  241. * check for errors.
  242. * @return <code>true</code> if all images have finished loading,
  243. * have been aborted, or have encountered
  244. * an error; <code>false</code> otherwise
  245. * @see java.awt.MediaTracker#checkAll(boolean)
  246. * @see java.awt.MediaTracker#checkID
  247. * @see java.awt.MediaTracker#isErrorAny
  248. * @see java.awt.MediaTracker#isErrorID
  249. */
  250. public boolean checkAll() {
  251. return checkAll(false, true);
  252. }
  253. /**
  254. * Checks to see if all images being tracked by this media tracker
  255. * have finished loading.
  256. * <p>
  257. * If the value of the <code>load</code> flag is <code>true</code>,
  258. * then this method starts loading any images that are not yet
  259. * being loaded.
  260. * <p>
  261. * If there is an error while loading or scaling an image, that
  262. * image is considered to have finished loading. Use the
  263. * <code>isErrorAny</code> and <code>isErrorID</code> methods to
  264. * check for errors.
  265. * @param load if <code>true</code>, start loading any
  266. * images that are not yet being loaded
  267. * @return <code>true</code> if all images have finished loading,
  268. * have been aborted, or have encountered
  269. * an error; <code>false</code> otherwise
  270. * @see java.awt.MediaTracker#checkID
  271. * @see java.awt.MediaTracker#checkAll()
  272. * @see java.awt.MediaTracker#isErrorAny()
  273. * @see java.awt.MediaTracker#isErrorID(int)
  274. */
  275. public boolean checkAll(boolean load) {
  276. return checkAll(load, true);
  277. }
  278. private synchronized boolean checkAll(boolean load, boolean verify) {
  279. MediaEntry cur = head;
  280. boolean done = true;
  281. while (cur != null) {
  282. if ((cur.getStatus(load, verify) & DONE) == 0) {
  283. done = false;
  284. }
  285. cur = cur.next;
  286. }
  287. return done;
  288. }
  289. /**
  290. * Checks the error status of all of the images.
  291. * @return <code>true</code> if any of the images tracked
  292. * by this media tracker had an error during
  293. * loading; <code>false</code> otherwise
  294. * @see java.awt.MediaTracker#isErrorID
  295. * @see java.awt.MediaTracker#getErrorsAny
  296. */
  297. public synchronized boolean isErrorAny() {
  298. MediaEntry cur = head;
  299. while (cur != null) {
  300. if ((cur.getStatus(false, true) & ERRORED) != 0) {
  301. return true;
  302. }
  303. cur = cur.next;
  304. }
  305. return false;
  306. }
  307. /**
  308. * Returns a list of all media that have encountered an error.
  309. * @return an array of media objects tracked by this
  310. * media tracker that have encountered
  311. * an error, or <code>null</code> if
  312. * there are none with errors
  313. * @see java.awt.MediaTracker#isErrorAny
  314. * @see java.awt.MediaTracker#getErrorsID
  315. */
  316. public synchronized Object[] getErrorsAny() {
  317. MediaEntry cur = head;
  318. int numerrors = 0;
  319. while (cur != null) {
  320. if ((cur.getStatus(false, true) & ERRORED) != 0) {
  321. numerrors++;
  322. }
  323. cur = cur.next;
  324. }
  325. if (numerrors == 0) {
  326. return null;
  327. }
  328. Object errors[] = new Object[numerrors];
  329. cur = head;
  330. numerrors = 0;
  331. while (cur != null) {
  332. if ((cur.getStatus(false, false) & ERRORED) != 0) {
  333. errors[numerrors++] = cur.getMedia();
  334. }
  335. cur = cur.next;
  336. }
  337. return errors;
  338. }
  339. /**
  340. * Starts loading all images tracked by this media tracker. This
  341. * method waits until all the images being tracked have finished
  342. * loading.
  343. * <p>
  344. * If there is an error while loading or scaling an image, then that
  345. * image is considered to have finished loading. Use the
  346. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  347. * check for errors.
  348. * @see java.awt.MediaTracker#waitForID(int)
  349. * @see java.awt.MediaTracker#waitForAll(long)
  350. * @see java.awt.MediaTracker#isErrorAny
  351. * @see java.awt.MediaTracker#isErrorID
  352. * @exception InterruptedException if another thread has
  353. * interrupted this thread
  354. */
  355. public void waitForAll() throws InterruptedException {
  356. waitForAll(0);
  357. }
  358. /**
  359. * Starts loading all images tracked by this media tracker. This
  360. * method waits until all the images being tracked have finished
  361. * loading, or until the length of time specified in milliseconds
  362. * by the <code>ms</code> argument has passed.
  363. * <p>
  364. * If there is an error while loading or scaling an image, then
  365. * that image is considered to have finished loading. Use the
  366. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  367. * check for errors.
  368. * @param ms the number of milliseconds to wait
  369. * for the loading to complete
  370. * @return <code>true</code> if all images were successfully
  371. * loaded; <code>false</code> otherwise
  372. * @see java.awt.MediaTracker#waitForID(int)
  373. * @see java.awt.MediaTracker#waitForAll(long)
  374. * @see java.awt.MediaTracker#isErrorAny
  375. * @see java.awt.MediaTracker#isErrorID
  376. * @exception InterruptedException if another thread has
  377. * interrupted this thread.
  378. */
  379. public synchronized boolean waitForAll(long ms)
  380. throws InterruptedException
  381. {
  382. long end = System.currentTimeMillis() + ms;
  383. boolean first = true;
  384. while (true) {
  385. int status = statusAll(first, first);
  386. if ((status & LOADING) == 0) {
  387. return (status == COMPLETE);
  388. }
  389. first = false;
  390. long timeout;
  391. if (ms == 0) {
  392. timeout = 0;
  393. } else {
  394. timeout = end - System.currentTimeMillis();
  395. if (timeout <= 0) {
  396. return false;
  397. }
  398. }
  399. wait(timeout);
  400. }
  401. }
  402. /**
  403. * Calculates and returns the bitwise inclusive <b>OR</b> of the
  404. * status of all media that are tracked by this media tracker.
  405. * <p>
  406. * Possible flags defined by the
  407. * <code>MediaTracker</code> class are <code>LOADING</code>,
  408. * <code>ABORTED</code>, <code>ERRORED</code>, and
  409. * <code>COMPLETE</code>. An image that hasn't started
  410. * loading has zero as its status.
  411. * <p>
  412. * If the value of <code>load</code> is <code>true</code>, then
  413. * this method starts loading any images that are not yet being loaded.
  414. *
  415. * @param load if <code>true</code>, start loading
  416. * any images that are not yet being loaded
  417. * @return the bitwise inclusive <b>OR</b> of the status of
  418. * all of the media being tracked
  419. * @see java.awt.MediaTracker#statusID(int, boolean)
  420. * @see java.awt.MediaTracker#LOADING
  421. * @see java.awt.MediaTracker#ABORTED
  422. * @see java.awt.MediaTracker#ERRORED
  423. * @see java.awt.MediaTracker#COMPLETE
  424. */
  425. public int statusAll(boolean load) {
  426. return statusAll(load, true);
  427. }
  428. private synchronized int statusAll(boolean load, boolean verify) {
  429. MediaEntry cur = head;
  430. int status = 0;
  431. while (cur != null) {
  432. status = status | cur.getStatus(load, verify);
  433. cur = cur.next;
  434. }
  435. return status;
  436. }
  437. /**
  438. * Checks to see if all images tracked by this media tracker that
  439. * are tagged with the specified identifier have finished loading.
  440. * <p>
  441. * This method does not start loading the images if they are not
  442. * already loading.
  443. * <p>
  444. * If there is an error while loading or scaling an image, then that
  445. * image is considered to have finished loading. Use the
  446. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  447. * check for errors.
  448. * @param id the identifier of the images to check
  449. * @return <code>true</code> if all images have finished loading,
  450. * have been aborted, or have encountered
  451. * an error; <code>false</code> otherwise
  452. * @see java.awt.MediaTracker#checkID(int, boolean)
  453. * @see java.awt.MediaTracker#checkAll()
  454. * @see java.awt.MediaTracker#isErrorAny()
  455. * @see java.awt.MediaTracker#isErrorID(int)
  456. */
  457. public boolean checkID(int id) {
  458. return checkID(id, false, true);
  459. }
  460. /**
  461. * Checks to see if all images tracked by this media tracker that
  462. * are tagged with the specified identifier have finished loading.
  463. * <p>
  464. * If the value of the <code>load</code> flag is <code>true</code>,
  465. * then this method starts loading any images that are not yet
  466. * being loaded.
  467. * <p>
  468. * If there is an error while loading or scaling an image, then that
  469. * image is considered to have finished loading. Use the
  470. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  471. * check for errors.
  472. * @param id the identifier of the images to check
  473. * @param load if <code>true</code>, start loading any
  474. * images that are not yet being loaded
  475. * @return <code>true</code> if all images have finished loading,
  476. * have been aborted, or have encountered
  477. * an error; <code>false</code> otherwise
  478. * @see java.awt.MediaTracker#checkID(int, boolean)
  479. * @see java.awt.MediaTracker#checkAll()
  480. * @see java.awt.MediaTracker#isErrorAny()
  481. * @see java.awt.MediaTracker#isErrorID(int)
  482. */
  483. public boolean checkID(int id, boolean load) {
  484. return checkID(id, load, true);
  485. }
  486. private synchronized boolean checkID(int id, boolean load, boolean verify)
  487. {
  488. MediaEntry cur = head;
  489. boolean done = true;
  490. while (cur != null) {
  491. if (cur.getID() == id
  492. && (cur.getStatus(load, verify) & DONE) == 0)
  493. {
  494. done = false;
  495. }
  496. cur = cur.next;
  497. }
  498. return done;
  499. }
  500. /**
  501. * Checks the error status of all of the images tracked by this
  502. * media tracker with the specified identifier.
  503. * @param id the identifier of the images to check
  504. * @return <code>true</code> if any of the images with the
  505. * specified identifier had an error during
  506. * loading; <code>false</code> otherwise
  507. * @see java.awt.MediaTracker#isErrorAny
  508. * @see java.awt.MediaTracker#getErrorsID
  509. */
  510. public synchronized boolean isErrorID(int id) {
  511. MediaEntry cur = head;
  512. while (cur != null) {
  513. if (cur.getID() == id
  514. && (cur.getStatus(false, true) & ERRORED) != 0)
  515. {
  516. return true;
  517. }
  518. cur = cur.next;
  519. }
  520. return false;
  521. }
  522. /**
  523. * Returns a list of media with the specified ID that
  524. * have encountered an error.
  525. * @param id the identifier of the images to check
  526. * @return an array of media objects tracked by this media
  527. * tracker with the specified identifier
  528. * that have encountered an error, or
  529. * <code>null</code> if there are none with errors
  530. * @see java.awt.MediaTracker#isErrorID
  531. * @see java.awt.MediaTracker#isErrorAny
  532. * @see java.awt.MediaTracker#getErrorsAny
  533. */
  534. public synchronized Object[] getErrorsID(int id) {
  535. MediaEntry cur = head;
  536. int numerrors = 0;
  537. while (cur != null) {
  538. if (cur.getID() == id
  539. && (cur.getStatus(false, true) & ERRORED) != 0)
  540. {
  541. numerrors++;
  542. }
  543. cur = cur.next;
  544. }
  545. if (numerrors == 0) {
  546. return null;
  547. }
  548. Object errors[] = new Object[numerrors];
  549. cur = head;
  550. numerrors = 0;
  551. while (cur != null) {
  552. if (cur.getID() == id
  553. && (cur.getStatus(false, false) & ERRORED) != 0)
  554. {
  555. errors[numerrors++] = cur.getMedia();
  556. }
  557. cur = cur.next;
  558. }
  559. return errors;
  560. }
  561. /**
  562. * Starts loading all images tracked by this media tracker with the
  563. * specified identifier. This method waits until all the images with
  564. * the specified identifier have finished loading.
  565. * <p>
  566. * If there is an error while loading or scaling an image, then that
  567. * image is considered to have finished loading. Use the
  568. * <code>isErrorAny</code> and <code>isErrorID</code> methods to
  569. * check for errors.
  570. * @param id the identifier of the images to check
  571. * @see java.awt.MediaTracker#waitForAll
  572. * @see java.awt.MediaTracker#isErrorAny()
  573. * @see java.awt.MediaTracker#isErrorID(int)
  574. * @exception InterruptedException if another thread has
  575. * interrupted this thread.
  576. */
  577. public void waitForID(int id) throws InterruptedException {
  578. waitForID(id, 0);
  579. }
  580. /**
  581. * Starts loading all images tracked by this media tracker with the
  582. * specified identifier. This method waits until all the images with
  583. * the specified identifier have finished loading, or until the
  584. * length of time specified in milliseconds by the <code>ms</code>
  585. * argument has passed.
  586. * <p>
  587. * If there is an error while loading or scaling an image, then that
  588. * image is considered to have finished loading. Use the
  589. * <code>statusID</code>, <code>isErrorID</code>, and
  590. * <code>isErrorAny</code> methods to check for errors.
  591. * @param id the identifier of the images to check
  592. * @param ms the length of time, in milliseconds, to wait
  593. * for the loading to complete
  594. * @see java.awt.MediaTracker#waitForAll
  595. * @see java.awt.MediaTracker#waitForID(int)
  596. * @see java.awt.MediaTracker#statusID
  597. * @see java.awt.MediaTracker#isErrorAny()
  598. * @see java.awt.MediaTracker#isErrorID(int)
  599. * @exception InterruptedException if another thread has
  600. * interrupted this thread.
  601. */
  602. public synchronized boolean waitForID(int id, long ms)
  603. throws InterruptedException
  604. {
  605. long end = System.currentTimeMillis() + ms;
  606. boolean first = true;
  607. while (true) {
  608. int status = statusID(id, first, first);
  609. if ((status & LOADING) == 0) {
  610. return (status == COMPLETE);
  611. }
  612. first = false;
  613. long timeout;
  614. if (ms == 0) {
  615. timeout = 0;
  616. } else {
  617. timeout = end - System.currentTimeMillis();
  618. if (timeout <= 0) {
  619. return false;
  620. }
  621. }
  622. wait(timeout);
  623. }
  624. }
  625. /**
  626. * Calculates and returns the bitwise inclusive <b>OR</b> of the
  627. * status of all media with the specified identifier that are
  628. * tracked by this media tracker.
  629. * <p>
  630. * Possible flags defined by the
  631. * <code>MediaTracker</code> class are <code>LOADING</code>,
  632. * <code>ABORTED</code>, <code>ERRORED</code>, and
  633. * <code>COMPLETE</code>. An image that hasn't started
  634. * loading has zero as its status.
  635. * <p>
  636. * If the value of <code>load</code> is <code>true</code>, then
  637. * this method starts loading any images that are not yet being loaded.
  638. * @param id the identifier of the images to check
  639. * @param load if <code>true</code>, start loading
  640. * any images that are not yet being loaded
  641. * @return the bitwise inclusive <b>OR</b> of the status of
  642. * all of the media with the specified
  643. * identifier that are being tracked
  644. * @see java.awt.MediaTracker#statusAll(boolean)
  645. * @see java.awt.MediaTracker#LOADING
  646. * @see java.awt.MediaTracker#ABORTED
  647. * @see java.awt.MediaTracker#ERRORED
  648. * @see java.awt.MediaTracker#COMPLETE
  649. */
  650. public int statusID(int id, boolean load) {
  651. return statusID(id, load, true);
  652. }
  653. private synchronized int statusID(int id, boolean load, boolean verify) {
  654. MediaEntry cur = head;
  655. int status = 0;
  656. while (cur != null) {
  657. if (cur.getID() == id) {
  658. status = status | cur.getStatus(load, verify);
  659. }
  660. cur = cur.next;
  661. }
  662. return status;
  663. }
  664. /**
  665. * Removes the specified image from this media tracker.
  666. * All instances of the specified image are removed,
  667. * regardless of scale or ID.
  668. * @param image the image to be removed
  669. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int)
  670. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
  671. * @since JDK1.1
  672. */
  673. public synchronized void removeImage(Image image) {
  674. MediaEntry cur = head;
  675. MediaEntry prev = null;
  676. while (cur != null) {
  677. MediaEntry next = cur.next;
  678. if (cur.getMedia() == image) {
  679. if (prev == null) {
  680. head = next;
  681. } else {
  682. prev.next = next;
  683. }
  684. cur.cancel();
  685. } else {
  686. prev = cur;
  687. }
  688. cur = next;
  689. }
  690. notifyAll(); // Notify in case remaining images are "done".
  691. }
  692. /**
  693. * Removes the specified image from the specified tracking
  694. * ID of this media tracker.
  695. * All instances of <code>Image</code> being tracked
  696. * under the specified ID are removed regardless of scale.
  697. * @param image the image to be removed
  698. * @param id the tracking ID frrom which to remove the image
  699. * @see java.awt.MediaTracker#removeImage(java.awt.Image)
  700. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
  701. * @since JDK1.1
  702. */
  703. public synchronized void removeImage(Image image, int id) {
  704. MediaEntry cur = head;
  705. MediaEntry prev = null;
  706. while (cur != null) {
  707. MediaEntry next = cur.next;
  708. if (cur.getID() == id && cur.getMedia() == image) {
  709. if (prev == null) {
  710. head = next;
  711. } else {
  712. prev.next = next;
  713. }
  714. cur.cancel();
  715. } else {
  716. prev = cur;
  717. }
  718. cur = next;
  719. }
  720. notifyAll(); // Notify in case remaining images are "done".
  721. }
  722. /**
  723. * Removes the specified image with the specified
  724. * width, height, and ID from this media tracker.
  725. * Only the specified instance (with any duplicates) is removed.
  726. * @param image the image to be removed
  727. * @param id the tracking ID from which to remove the image
  728. * @param width the width to remove (-1 for unscaled)
  729. * @param height the height to remove (-1 for unscaled)
  730. * @see java.awt.MediaTracker#removeImage(java.awt.Image)
  731. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int)
  732. * @since JDK1.1
  733. */
  734. public synchronized void removeImage(Image image, int id,
  735. int width, int height) {
  736. MediaEntry cur = head;
  737. MediaEntry prev = null;
  738. while (cur != null) {
  739. MediaEntry next = cur.next;
  740. if (cur.getID() == id && cur instanceof ImageMediaEntry
  741. && ((ImageMediaEntry) cur).matches(image, width, height))
  742. {
  743. if (prev == null) {
  744. head = next;
  745. } else {
  746. prev.next = next;
  747. }
  748. cur.cancel();
  749. } else {
  750. prev = cur;
  751. }
  752. cur = next;
  753. }
  754. notifyAll(); // Notify in case remaining images are "done".
  755. }
  756. synchronized void setDone() {
  757. notifyAll();
  758. }
  759. }
  760. abstract class MediaEntry {
  761. MediaTracker tracker;
  762. int ID;
  763. MediaEntry next;
  764. int status;
  765. boolean cancelled;
  766. MediaEntry(MediaTracker mt, int id) {
  767. tracker = mt;
  768. ID = id;
  769. }
  770. abstract Object getMedia();
  771. static MediaEntry insert(MediaEntry head, MediaEntry me) {
  772. MediaEntry cur = head;
  773. MediaEntry prev = null;
  774. while (cur != null) {
  775. if (cur.ID > me.ID) {
  776. break;
  777. }
  778. prev = cur;
  779. cur = cur.next;
  780. }
  781. me.next = cur;
  782. if (prev == null) {
  783. head = me;
  784. } else {
  785. prev.next = me;
  786. }
  787. return head;
  788. }
  789. int getID() {
  790. return ID;
  791. }
  792. abstract void startLoad();
  793. void cancel() {
  794. cancelled = true;
  795. }
  796. static final int LOADING = MediaTracker.LOADING;
  797. static final int ABORTED = MediaTracker.ABORTED;
  798. static final int ERRORED = MediaTracker.ERRORED;
  799. static final int COMPLETE = MediaTracker.COMPLETE;
  800. static final int LOADSTARTED = (LOADING | ERRORED | COMPLETE);
  801. static final int DONE = (ABORTED | ERRORED | COMPLETE);
  802. synchronized int getStatus(boolean doLoad, boolean doVerify) {
  803. if (doLoad && ((status & LOADSTARTED) == 0)) {
  804. status = (status & ~ABORTED) | LOADING;
  805. startLoad();
  806. }
  807. return status;
  808. }
  809. void setStatus(int flag) {
  810. synchronized (this) {
  811. status = flag;
  812. }
  813. tracker.setDone();
  814. }
  815. }
  816. class ImageMediaEntry extends MediaEntry implements ImageObserver,
  817. java.io.Serializable {
  818. Image image;
  819. int width;
  820. int height;
  821. /*
  822. * JDK 1.1 serialVersionUID
  823. */
  824. private static final long serialVersionUID = 4739377000350280650L;
  825. ImageMediaEntry(MediaTracker mt, Image img, int c, int w, int h) {
  826. super(mt, c);
  827. image = img;
  828. width = w;
  829. height = h;
  830. }
  831. boolean matches(Image img, int w, int h) {
  832. return (image == img && width == w && height == h);
  833. }
  834. Object getMedia() {
  835. return image;
  836. }
  837. int getStatus(boolean doLoad, boolean doVerify) {
  838. if (doVerify) {
  839. int flags = tracker.target.checkImage(image, width, height, null);
  840. int s = parseflags(flags);
  841. if (s == 0) {
  842. if ((status & (ERRORED | COMPLETE)) != 0) {
  843. setStatus(ABORTED);
  844. }
  845. } else if (s != status) {
  846. setStatus(s);
  847. }
  848. }
  849. return super.getStatus(doLoad, doVerify);
  850. }
  851. void startLoad() {
  852. if (tracker.target.prepareImage(image, width, height, this)) {
  853. setStatus(COMPLETE);
  854. }
  855. }
  856. int parseflags(int infoflags) {
  857. if ((infoflags & ERROR) != 0) {
  858. return ERRORED;
  859. } else if ((infoflags & ABORT) != 0) {
  860. return ABORTED;
  861. } else if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
  862. return COMPLETE;
  863. }
  864. return 0;
  865. }
  866. public boolean imageUpdate(Image img, int infoflags,
  867. int x, int y, int w, int h) {
  868. if (cancelled) {
  869. return false;
  870. }
  871. int s = parseflags(infoflags);
  872. if (s != 0 && s != status) {
  873. setStatus(s);
  874. }
  875. return ((status & LOADING) != 0);
  876. }
  877. }