This brings the ImageView together with the new async loading by making
it more thread-safe.

2006-12-05  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/text/html/ImageView.java
        (imageUpdate): Use spans field to determine if the CSS width/height
        are set. Call safePreferenceChanged to protect view structure
        from threading issues.
        (spans): Made package private.
        (ImageView): Initialize loadOnDemand with false.
        (loadImage): Call Toolkit.prepareImage() to make sure we have
        our Observer registered.
        (safePreferenceChanged): New helper method. Calls preferenceChanged
        in a thread safe environment.

/Roman

Index: javax/swing/text/html/ImageView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/ImageView.java,v
retrieving revision 1.5
diff -u -1 -5 -r1.5 ImageView.java
--- javax/swing/text/html/ImageView.java	1 Dec 2006 14:43:43 -0000	1.5
+++ javax/swing/text/html/ImageView.java	5 Dec 2006 11:19:44 -0000
@@ -1,67 +1,67 @@
 package javax.swing.text.html;
 
-import gnu.javax.swing.text.html.CombinedAttributes;
 import gnu.javax.swing.text.html.ImageViewIconFactory;
 import gnu.javax.swing.text.html.css.Length;
 
 import java.awt.Graphics;
 import java.awt.Image;
 import java.awt.MediaTracker;
 import java.awt.Rectangle;
 import java.awt.Shape;
 import java.awt.Toolkit;
 import java.awt.image.ImageObserver;
 import java.net.MalformedURLException;
 import java.net.URL;
 
 import javax.swing.Icon;
+import javax.swing.SwingUtilities;
+import javax.swing.text.AbstractDocument;
 import javax.swing.text.AttributeSet;
 import javax.swing.text.BadLocationException;
 import javax.swing.text.Document;
 import javax.swing.text.Element;
 import javax.swing.text.View;
 import javax.swing.text.Position.Bias;
 import javax.swing.text.html.HTML.Attribute;
 
 /**
  * A view, representing a single image, represented by the HTML IMG tag.
  * 
  * @author Audrius Meskauskas ([EMAIL PROTECTED]) 
  */
 public class ImageView extends View
 {
   /**
    * Tracks image loading state and performs the necessary layout updates.
    */
   class Observer
     implements ImageObserver
   {
 
     public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height)
     {
       boolean widthChanged = false;
-      if ((flags & ImageObserver.WIDTH) != 0
-          && ! getElement().getAttributes().isDefined(HTML.Attribute.WIDTH))
+      if ((flags & ImageObserver.WIDTH) != 0 && spans[X_AXIS] == null)
         widthChanged = true;
       boolean heightChanged = false;
-      if ((flags & ImageObserver.HEIGHT) != 0
-          && ! getElement().getAttributes().isDefined(HTML.Attribute.HEIGHT))
-        widthChanged = true;
+      if ((flags & ImageObserver.HEIGHT) != 0 && spans[Y_AXIS] == null)
+        heightChanged = true;
       if (widthChanged || heightChanged)
-        preferenceChanged(ImageView.this, widthChanged, heightChanged);
-      return (flags & ALLBITS) != 0;
+        safePreferenceChanged(ImageView.this, widthChanged, heightChanged);
+      boolean ret = (flags & ALLBITS) != 0;
+      return ret;
     }
     
   }
 
   /**
    * True if the image loads synchronuosly (on demand). By default, the image
    * loads asynchronuosly.
    */
   boolean loadOnDemand;
 
   /**
    * The image icon, wrapping the image,
    */
   Image image;
  
@@ -100,49 +100,52 @@
    */
   private int width;
 
   /**
    * The current height of the image.
    */
   private int height;
 
   /**
    * Our ImageObserver for tracking the loading state.
    */
   private ImageObserver observer;
 
   /**
    * The CSS width and height.
+   *
+   * Package private to avoid synthetic accessor methods.
    */
-  private Length[] spans;
+  Length[] spans;
 
   /**
    * The cached attributes.
    */
   private AttributeSet attributes;
 
   /**
    * Creates the image view that represents the given element.
    * 
    * @param element the element, represented by this image view.
    */
   public ImageView(Element element)
   {
     super(element);
     observer = new Observer();
     reloadProperties = true;
     reloadImage = true;
+    loadOnDemand = false;
   }
  
   /**
    * Load or reload the image. This method initiates the image reloading. After
    * the image is ready, the repaint event will be scheduled. The current image,
    * if it already exists, will be discarded.
    */
   private void reloadImage()
   {
     loading = true;
     reloadImage = false;
     haveWidth = false;
     haveHeight = false;
     image = null;
     width = 0;
@@ -475,31 +478,33 @@
       reloadImage();
     if (reloadProperties)
       setPropertiesFromAttributes();
   }
 
   /**
    * Actually loads the image.
    */
   private void loadImage()
   {
     URL src = getImageURL();
     Image newImage = null;
     if (src != null)
       {
         // Call getImage(URL) to allow the toolkit caching of that image URL.
-        newImage = Toolkit.getDefaultToolkit().getImage(src);
+        Toolkit tk = Toolkit.getDefaultToolkit();
+        newImage = tk.getImage(src);
+        tk.prepareImage(newImage, -1, -1, observer);
         if (newImage != null && getLoadsSynchronously())
           {
             // Load image synchronously.
             MediaTracker tracker = new MediaTracker(getContainer());
             tracker.addImage(newImage, 0);
             try
               {
                 tracker.waitForID(0);
               }
             catch (InterruptedException ex)
               {
                 Thread.interrupted();
               }
             
           }
@@ -536,16 +541,54 @@
             newH = (int) l.getValue();
             haveHeight = true;
           }
         else
           {
             newW = newIm.getWidth(observer);
           }
         // Go and trigger loading.
         Toolkit tk = Toolkit.getDefaultToolkit();
         if (haveWidth || haveHeight)
           tk.prepareImage(newIm, width, height, observer);
         else
           tk.prepareImage(newIm, -1, -1, observer);
       }
   }
+
+  /**
+   * Calls preferenceChanged from the event dispatch thread and within
+   * a read lock to protect us from threading issues.
+   *
+   * @param v the view
+   * @param width true when the width changed
+   * @param height true when the height changed
+   */
+  void safePreferenceChanged(final View v, final boolean width,
+                             final boolean height)
+  {
+    if (SwingUtilities.isEventDispatchThread())
+      {
+        Document doc = getDocument();
+        if (doc instanceof AbstractDocument)
+          ((AbstractDocument) doc).readLock();
+        try
+          {
+            preferenceChanged(v, width, height);
+          }
+        finally
+          {
+            if (doc instanceof AbstractDocument)
+              ((AbstractDocument) doc).readUnlock();
+          }
+      }
+    else
+      {
+        SwingUtilities.invokeLater(new Runnable()
+        {
+          public void run()
+          {
+            safePreferenceChanged(v, width, height);
+          }
+        });
+      }
+  }
 }

Reply via email to