You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-users@xmlgraphics.apache.org by Vlad Berditchevskiy <vl...@tzi.de> on 2004/02/23 00:36:23 UTC

Customizing the Rhino interpreter

Hi there,

I'm new to batik and tried to add some custom functions to the Rhino
Interpreter as mentioned in docs/scripting.html. However I found out
that the source example doesn't work.

| org.apache.batik.bridge BridgeContext ctx = ...;

I realized that "..." actually means
"svgCanvas.getUpdateManager().getBridgeContext();", however the
documentations doens't say anything about *where* this code should be
placed. Just after creation of the Canvas and loading the URL
bridgeContext doesn't yet exist, so it would raise
NullPointerException. Putting this code in the gvtBuildCompleted()
method of the GVTTreeBuilderListener() worked for me, is it the right
place?

| org.apache.batik.script.InterpreterPool pool =
|     new org.apache.batik.script.InterpreterPool();
| pool.putInterpreterFactory("text/ecmascript", 
|                            new ExtendedRhinoInterpreterFactory());
| ctx.setInterpreterPool(pool);

This would fail, because setInterpreterPool() is protected. I worked
around this problem by patching batik sources and making this public,
but I guess, this is not what users are supposed to do. Is there a
better solution?

BTW, the example code in the docs contains three typos ("intepreter"
instead of "interpreter").

P.S. Is this a bug or a feature that the line number in script errors is
always relative to the beginning of the script and not the actual line
number in the corresponding SVG file?

-- 
\  /                                       vlad@hashbang.de
 \/lad                                     http://www.hashbang.de 


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-users-help@xml.apache.org


Re: Customizing the Rhino interpreter

Posted by Vlad Berditchevskiy <vl...@tzi.de>.
Hm... for some strange reason, only the attachment got posted on the
mailing list, while the message text disappeared. Here is the text
again:

----------------------------------------------------------------------------
>| BridgeContext(UserAgent userAgent, InterpreterPool interpreterPool, DocumentLoader documentLoader)
> 
> Is it what you mean? What should I supply as UserAgent and
> DocumentLoader? Can I call getUserAgent() and getDocumentLoader() on the
> BridgeContext created by the super class and then use them in my own
> BridgeContext?

I tried this way and it worked for me:

,----
| import org.apache.batik.swing.*;
| import org.apache.batik.swing.svg.*;
| import org.apache.batik.bridge.*;
| 
| class JExtendedSVGCanvas extends JSVGCanvas
| {
|   protected BridgeContext createBridgeContext()
|   {
|     BridgeContext bridgeContext = super.createBridgeContext();
| 
|     org.apache.batik.script.InterpreterPool pool = new org.apache.batik.script.InterpreterPool();
|     pool.putInterpreterFactory("text/ecmascript", new ExtendedRhinoInterpreterFactory());
|     BridgeContext newBridgeContext = new BridgeContext(
|       bridgeContext.getUserAgent(), pool, bridgeContext.getDocumentLoader());
| 
|     // Check if the original BridgeContext is dynamic and set newBridgeContext
|     // to the same state (otherwise it won't update the document)
|     if (bridgeContext.isDynamic())
|       newBridgeContext.setDynamicState(BridgeContext.DYNAMIC);
| 
|     return newBridgeContext;
|   }
| }
`----

I hope, reusing UserAgent and DocumentLoader won't break anything?

Suggestion for future releases: please consider including some working
code samples in the distribution, it would simplify the learning process
significantly! I attached a complete working version of the "print"
example from the tutorial.

----------------------------------------------------------------------------

-- 
\  /                                       vlad@hashbang.de
 \/lad                                     http://www.hashbang.de 


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-users-help@xml.apache.org


Re: Customizing the Rhino interpreter

Posted by Vlad Berditchevskiy <vl...@tzi.de>.
---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-users-help@xml.apache.org

Re: Customizing the Rhino interpreter

Posted by Vlad Berditchevskiy <vl...@tzi.de>.
Thomas DeWeese <Th...@Kodak.com> writes:

>     Actually it does:
>       For example if you are using the Batik SVGBrowser application you
>       should be able to use the previous piece of code on a subclass of
>       the JSVGCanvas class in the createBridgeContext() method.
> 
>     This would be the 'best' place to put it for two reasons, firstly
> it would ensure that no-one has looked at the bridge context
> interpreter pool yet. And Second, see below...

I'm not using the Batik SVGBrowser application, just JSVGCanvas. So, the
user is expected to subclass JSVGCanvas and override the
createBridgeContext() method, something like this?

,----
| import org.apache.batik.swing.*;
| import org.apache.batik.swing.svg.*;
| import org.apache.batik.bridge.*;
| 
| class JExtendedSVGComponent extends JSVGCanvas
| {
|   protected BridgeContext createBridgeContext()
|   {
|     BridgeContext bridgeContext = super.createBridgeContext();
| 
|     org.apache.batik.script.InterpreterPool pool = new org.apache.batik.script.InterpreterPool();
|     pool.putInterpreterFactory("text/ecmascript", new ExtendedRhinoInterpreterFactory());
|     bridgeContext.setInterpreterPool(pool);
| 
|     return bridgeContext;
|   }
| }
`----

But we still have the problem that setInterpreterPool() is protected...

>     Yes, second you can change the constructor it calls so that it
> uses your interpreter pool rather than the default one

What constructor should I change? Create my own BridgeContext instead of
calling super.createBridgeContext()? I found this constructor:

| BridgeContext(UserAgent userAgent, InterpreterPool interpreterPool, DocumentLoader documentLoader)

Is it what you mean? What should I supply as UserAgent and
DocumentLoader? Can I call getUserAgent() and getDocumentLoader() on the
BridgeContext created by the super class and then use them in my own
BridgeContext?

> (or subclass so you can call setInterpreterPool).

If I subclass BridgeContext, how should I tell JSVGCanvas to use my new
class?

-- 
\  /                                       vlad@hashbang.de
 \/lad                                     http://www.hashbang.de 


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-users-help@xml.apache.org


Re: Customizing the Rhino interpreter

Posted by Thomas DeWeese <Th...@Kodak.com>.
Vlad Berditchevskiy wrote:

> Hi there,
> 
> I'm new to batik and tried to add some custom functions to the Rhino
> Interpreter as mentioned in docs/scripting.html. However I found out
> that the source example doesn't work.
> 
> | org.apache.batik.bridge BridgeContext ctx = ...;
> 
> I realized that "..." actually means
> "svgCanvas.getUpdateManager().getBridgeContext();", however the
> documentations doens't say anything about *where* this code should be
> placed. 

    Actually it does:

      For example if you are using the Batik SVGBrowser application 
you
      should be able to use the previous piece of code on a subclass of
      the JSVGCanvas class in the createBridgeContext() method.

    This would be the 'best' place to put it for two reasons, firstly
it would ensure that no-one has looked at the bridge context
interpreter pool yet. And Second, see below...


> Just after creation of the Canvas and loading the URL
> bridgeContext doesn't yet exist, so it would raise
> NullPointerException. Putting this code in the gvtBuildCompleted()
> method of the GVTTreeBuilderListener() worked for me, is it the right
> place?

    This is pretty early in the processes and in particular I think
it is before 'onload' dispatch so I think it would work but I
think that the tutorial's suggestion is 'the right one'.

> 
> | org.apache.batik.script.InterpreterPool pool =
> |     new org.apache.batik.script.InterpreterPool();
> | pool.putInterpreterFactory("text/ecmascript", 
> |                            new ExtendedRhinoInterpreterFactory());
> | ctx.setInterpreterPool(pool);
> 
> This would fail, because setInterpreterPool() is protected. I worked
> around this problem by patching batik sources and making this public,
> but I guess, this is not what users are supposed to do. Is there a
> better solution?

    Yes, second you can change the constructor it calls so that it
uses your interpreter pool rather than the default one (or subclass
so you can call setInterpreterPool).

> BTW, the example code in the docs contains three typos ("intepreter"
> instead of "interpreter").

    Thanks I'll take a look at fixing these.

> P.S. Is this a bug or a feature that the line number in script errors is
> always relative to the beginning of the script and not the actual line
> number in the corresponding SVG file?

    In the current version of Batik (1.5.1) it is improved somewhat,
it includes the line in the SVG that the script starts and the line
within in the script it's self.  I think I recently noticed that
an API exists to tell Rhino what line a piece of script actually
starts on so it might be possible to have it merge these two.



---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-users-help@xml.apache.org