Hello, fellow vector graphics pioneers.

First the questions:

1) Why does JSVGCanvas.getGraphicsNode() sometimes return null, at first. What event must I wait on to be sure that the data is available?

2) Why does GraphicsNode.getBounds() sometimes return really tiny rectangles? (Drawing many of the sample SVGs included with Batik renders them in a 1 or 2 pixel box, and I have to zoom the hell out of the transform in order to see anything. Still, other SVG samples display at the proper size.)

Now the details:

I am developing a graphical application which displays a Figure, where a Figure comprises a set of Doodles. Each Doodle is an independent object that can be programmatically added to or removed from the Figure. There are ShapeDoodles, TextDoodles, ImageDoodles, and various other sorts of Doodles, depending on what the Figure needs to display. Each Doodle implements the Doodle interface. The relevant part of this interface is shown below:

/**
* Individual component in a figure.
*
* <p><b>Details:</b> A <code>Doodle</code> is a single, independent component
* of a [EMAIL PROTECTED] Figure}.  Each doodle defines its boundaries, appearance, and
* relative depth in the figure.</p>
*/
public interface Doodle
{

   /**
    * Renders doodle.
    *
    * <p><b>Details:</b> <code>draw</code> renders this doodle using the
    * supplied graphics environment.  When the host [EMAIL PROTECTED] FigureView} is
    * repainting itself, it will probably call this method, albeit indirectly,
    * to redraw its figure's components.  This method returns <code>true</code>
    * if drawing was successful, <code>false</code> otherwise.</p>
    *
    * @param ipG the graphics context
    * @return true iff drawing was successful
    */
   boolean draw(Graphics2D ipG);

   /**
    * Returns rectangular extent.
    *
    * <p><b>Details: </b> This method returns the rectangular extent of this
    * <code>Doodle</code>. The rectangle returned is in logical (i.e.
    * figure) units, not display units.</p>
    *
    * @return the extent
    */
   Rectangle2D getBounds();

}

As you may have guessed, I am developing an implementation of Doodle that renders SVG documents. A portion of my experimental implementation is shown below:

public class SvgDoodle implements Doodle
{

   private GraphicsNode mpGraphicsNode;

   public SvgDoodle(SVGDocument ipDocument)
   {
       JSVGCanvas vpCanvas = new JSVGCanvas();
       GvtTreeBuilderWaiter vpWaiter = new GvtTreeBuilderWaiter();
       vpCanvas.addGVTTreeBuilderListener(vpWaiter);
       vpCanvas.setDocument(ipDocument);
       vpWaiter.waitForResult();
       mpGraphicsNode = vpCanvas.getGraphicsNode();
       // What a hack!  This is horrible and needs to be fixed.
       while (mpGraphicsNode == null)
       {
           try
           {
               Thread.sleep(1000);
           }
           catch (InterruptedException ee)
           {
           }
           mpGraphicsNode = vpCanvas.getGraphicsNode();
       }
   }

   public boolean draw(Graphics2D ipG)
   {
       mpGraphicsNode.paint(ipG);
   }

   public Rectangle2D getBounds()
   {
       return mpGraphicsNode.getBounds();
   }

}

The class GvtTreeBuilderWaiter is implemented as follows:

/**
* Waits for GVT tree builder's final state.
*
* <p><b>Details:</b> This class listens to a GVT tree builder and tracks the
* tree's build state.  The utility of this class lies entirely in
* [EMAIL PROTECTED] #waitForResult()}, which blocks and does not return until the tree
* builder reaches its final state.</p>
*/
public class GvtTreeBuilderWaiter implements GVTTreeBuilderListener
{

   // Note: The values of the BUILD_* constants are not arbitrary.  Keep them
   // in the same numerical order.

   public static final int BUILD_STARTED = 1;

   public static final int BUILD_COMPLETED = 2;

   public static final int BUILD_CANCELLED = 3;

   public static final int BUILD_FAILED = 4;

   private int mnResult = 0;

   public void gvtBuildStarted(GVTTreeBuilderEvent ipIgnored)
   {
       mnResult = BUILD_STARTED;
   }

   public synchronized void gvtBuildCompleted(GVTTreeBuilderEvent ipIgnored)
   {
       mnResult = BUILD_COMPLETED;
       notifyAll();
   }

   public synchronized void gvtBuildCancelled(GVTTreeBuilderEvent ipIgnored)
   {
       mnResult = BUILD_CANCELLED;
       notifyAll();
   }

   public synchronized void gvtBuildFailed(GVTTreeBuilderEvent ipIgnored)
   {
       mnResult = BUILD_FAILED;
       notifyAll();
   }

   public synchronized boolean waitForResult()
   {
       while (mnResult < BUILD_COMPLETED)
           try
           {
               wait();
           }
           catch (InterruptedException ee)
           {
               return false;
           }
       return true;
   }

}

The bottom line is, I simply need a way to convert a URL into an object that has the following methods:
1.        a method that paints to any Graphics2D I supply
2.        a method that returns the document's rectangular bounds

The code shown above only works about half the time. Any ideas?

Reply via email to