| 1 18 package org.apache.batik.bridge; 19 20 import java.io.BufferedReader ; 21 import java.io.InputStream ; 22 import java.io.InputStreamReader ; 23 import java.io.IOException ; 24 import java.io.OutputStream ; 25 import java.io.OutputStreamWriter ; 26 import java.io.Reader ; 27 import java.io.StringReader ; 28 import java.io.UnsupportedEncodingException ; 29 import java.io.Writer ; 30 31 import java.net.URL ; 32 import java.net.URLConnection ; 33 34 import java.util.HashMap ; 35 import java.util.Map ; 36 import java.util.Timer ; 37 import java.util.TimerTask ; 38 import java.util.zip.GZIPOutputStream ; 39 import java.util.zip.DeflaterOutputStream ; 40 41 import org.apache.batik.dom.GenericDOMImplementation; 42 import org.apache.batik.dom.svg.SAXSVGDocumentFactory; 43 import org.apache.batik.dom.svg.SVGOMDocument; 44 import org.apache.batik.dom.util.SAXDocumentFactory; 45 import org.apache.batik.dom.util.XLinkSupport; 46 import org.apache.batik.script.Interpreter; 47 import org.apache.batik.script.InterpreterException; 48 import org.apache.batik.util.EncodingUtilities; 49 import org.apache.batik.util.ParsedURL; 50 import org.apache.batik.util.RunnableQueue; 51 import org.apache.batik.util.SVGConstants; 52 import org.apache.batik.util.XMLResourceDescriptor; 53 54 import org.w3c.dom.Document ; 55 import org.w3c.dom.Element ; 56 import org.w3c.dom.Node ; 57 import org.w3c.dom.events.Event ; 58 import org.w3c.dom.events.EventListener ; 59 import org.w3c.dom.events.EventTarget ; 60 import org.w3c.dom.events.MutationEvent ; 61 import org.w3c.dom.svg.SVGDocument; 62 63 69 public class ScriptingEnvironment extends BaseScriptingEnvironment { 70 71 74 protected final static String FRAGMENT_PREFIX = 75 "<svg xmlns='" + 76 SVGConstants.SVG_NAMESPACE_URI + 77 "' xmlns:xlink='" + 78 XLinkSupport.XLINK_NAMESPACE_URI + 79 "'>"; 80 81 protected final static String FRAGMENT_SUFFIX = 82 "</svg>"; 83 84 public final static String [] SVG_EVENT_ATTRS = { 85 "onabort", "onerror", "onresize", "onscroll", "onunload", "onzoom", 92 "onbegin", "onend", "onrepeat", 96 "onfocusin", "onfocusout", "onactivate", "onclick", 101 "onmousedown", "onmouseup", "onmouseover", "onmouseout", "onmousemove", 107 "onkeypress", "onkeydown", "onkeyup" }; 111 112 public final static String [] SVG_DOM_EVENT = { 113 "SVGAbort", "SVGError", "SVGResize", "SVGScroll", "SVGUnload", "SVGZoom", 120 "beginEvent", "endEvent", "repeatEvent", 124 "DOMFocusIn", "DOMFocusOut", "DOMActivate", "click", "mousedown", "mouseup", "mouseover", "mouseout", "mousemove", "keypress", "keydown", "keyup" }; 137 138 141 protected Timer timer = new Timer (true); 142 143 146 protected UpdateManager updateManager; 147 148 151 protected RunnableQueue updateRunnableQueue; 152 153 156 protected EventListener domNodeInsertedListener 157 = new DOMNodeInsertedListener(); 158 159 162 protected EventListener domNodeRemovedListener 163 = new DOMNodeRemovedListener(); 164 165 168 protected EventListener domAttrModifiedListener 169 = new DOMAttrModifiedListener(); 170 171 174 protected EventListener svgAbortListener = 175 new ScriptingEventListener("onabort"); 176 177 180 protected EventListener svgErrorListener = 181 new ScriptingEventListener("onerror"); 182 183 186 protected EventListener svgResizeListener = 187 new ScriptingEventListener("onresize"); 188 189 192 protected EventListener svgScrollListener = 193 new ScriptingEventListener("onscroll"); 194 195 198 protected EventListener svgUnloadListener = 199 new ScriptingEventListener("onunload"); 200 201 204 protected EventListener svgZoomListener = 205 new ScriptingEventListener("onzoom"); 206 207 210 protected EventListener beginListener = 211 new ScriptingEventListener("onbegin"); 212 213 216 protected EventListener endListener = 217 new ScriptingEventListener("onend"); 218 219 222 protected EventListener repeatListener = 223 new ScriptingEventListener("onrepeat"); 224 225 228 protected EventListener focusinListener = 229 new ScriptingEventListener("onfocusin"); 230 231 234 protected EventListener focusoutListener = 235 new ScriptingEventListener("onfocusout"); 236 237 240 protected EventListener activateListener = 241 new ScriptingEventListener("onactivate"); 242 243 246 protected EventListener clickListener = 247 new ScriptingEventListener("onclick"); 248 249 252 protected EventListener mousedownListener = 253 new ScriptingEventListener("onmousedown"); 254 255 258 protected EventListener mouseupListener = 259 new ScriptingEventListener("onmouseup"); 260 261 264 protected EventListener mouseoverListener = 265 new ScriptingEventListener("onmouseover"); 266 267 270 protected EventListener mouseoutListener = 271 new ScriptingEventListener("onmouseout"); 272 273 276 protected EventListener mousemoveListener = 277 new ScriptingEventListener("onmousemove"); 278 279 282 protected EventListener keypressListener = 283 new ScriptingEventListener("onkeypress"); 284 285 288 protected EventListener keydownListener = 289 new ScriptingEventListener("onkeydown"); 290 291 294 protected EventListener keyupListener = 295 new ScriptingEventListener("onkeyup"); 296 297 298 protected EventListener [] listeners = { 299 svgAbortListener, 300 svgErrorListener, 301 svgResizeListener, 302 svgScrollListener, 303 svgUnloadListener, 304 svgZoomListener, 305 306 beginListener, 307 endListener, 308 repeatListener, 309 310 focusinListener, 311 focusoutListener, 312 activateListener, 313 clickListener, 314 315 mousedownListener, 316 mouseupListener, 317 mouseoverListener, 318 mouseoutListener, 319 mousemoveListener, 320 321 keypressListener, 322 keydownListener, 323 keyupListener 324 }; 325 326 Map attrToDOMEvent = new HashMap (SVG_EVENT_ATTRS.length); 327 Map attrToListener = new HashMap (SVG_EVENT_ATTRS.length); 328 { 329 for (int i=0; i<SVG_EVENT_ATTRS.length; i++) { 330 attrToDOMEvent.put(SVG_EVENT_ATTRS[i], SVG_DOM_EVENT[i]); 331 attrToListener.put(SVG_EVENT_ATTRS[i], listeners[i]); 332 } 333 } 334 335 339 public ScriptingEnvironment(BridgeContext ctx) { 340 super(ctx); 341 updateManager = ctx.getUpdateManager(); 342 updateRunnableQueue = updateManager.getUpdateRunnableQueue(); 343 344 addScriptingListeners(document.getDocumentElement()); 346 347 EventTarget et = (EventTarget )document; 349 et.addEventListener("DOMNodeInserted", 350 domNodeInsertedListener, 351 false); 352 et.addEventListener("DOMNodeRemoved", 353 domNodeRemovedListener, 354 false); 355 et.addEventListener("DOMAttrModified", 356 domAttrModifiedListener, 357 false); 358 } 359 360 363 public org.apache.batik.script.Window createWindow(Interpreter interp, 364 String lang) { 365 return new Window(interp, lang); 366 } 367 368 371 public void runEventHandler(String script, Event evt, 372 String lang, String desc) { 373 Interpreter interpreter = getInterpreter(lang); 374 if (interpreter == null) 375 return; 376 377 try { 378 checkCompatibleScriptURL(lang, docPURL); 379 380 interpreter.bindObject(EVENT_NAME, evt); 381 interpreter.bindObject(ALTERNATE_EVENT_NAME, evt); 382 interpreter.evaluate(new StringReader (script), desc); 383 } catch (IOException ioe) { 384 } catch (InterpreterException ie) { 386 handleInterpreterException(ie); 387 } catch (SecurityException se) { 388 handleSecurityException(se); 389 } 390 } 391 392 395 public void interrupt() { 396 timer.cancel(); 397 removeScriptingListeners(document.getDocumentElement()); 399 400 EventTarget et = (EventTarget )document; 402 et.removeEventListener("DOMNodeInserted", 403 domNodeInsertedListener, 404 false); 405 et.removeEventListener("DOMNodeRemoved", 406 domNodeRemovedListener, 407 false); 408 et.removeEventListener("DOMAttrModified", 409 domAttrModifiedListener, 410 false); 411 } 412 413 416 protected void addScriptingListeners(Node node) { 417 if (node.getNodeType() == Node.ELEMENT_NODE) { 418 Element elt = (Element )node; 420 EventTarget target = (EventTarget )elt; 421 if (SVGConstants.SVG_NAMESPACE_URI.equals(elt.getNamespaceURI())) { 422 if (SVGConstants.SVG_SVG_TAG.equals(elt.getLocalName())) { 423 if (elt.hasAttributeNS(null, "onabort")) { 425 target.addEventListener("SVGAbort", 426 svgAbortListener, false); 427 } 428 if (elt.hasAttributeNS(null, "onerror")) { 429 target.addEventListener("SVGError", 430 svgErrorListener, false); 431 } 432 if (elt.hasAttributeNS(null, "onresize")) { 433 target.addEventListener("SVGResize", 434 svgResizeListener, false); 435 } 436 if (elt.hasAttributeNS(null, "onscroll")) { 437 target.addEventListener("SVGScroll", 438 svgScrollListener, false); 439 } 440 if (elt.hasAttributeNS(null, "onunload")) { 441 target.addEventListener("SVGUnload", 442 svgUnloadListener, false); 443 } 444 if (elt.hasAttributeNS(null, "onzoom")) { 445 target.addEventListener("SVGZoom", 446 svgZoomListener, false); 447 } 448 } else { 449 String name = elt.getLocalName(); 450 if (name.equals(SVGConstants.SVG_SET_TAG) || 451 name.startsWith("animate")) { 452 if (elt.hasAttributeNS(null, "onbegin")) { 454 target.addEventListener("beginEvent", 455 beginListener , 456 false); 457 } 458 if (elt.hasAttributeNS(null, "onend")) { 459 target.addEventListener("endEvent", 460 endListener, 461 false); 462 } 463 if (elt.hasAttributeNS(null, "onrepeat")) { 464 target.addEventListener("repeatEvent", 465 repeatListener , 466 false); 467 } 468 return; 469 } 470 } 471 } 472 473 if (elt.hasAttributeNS(null, "onfocusin")) { 475 target.addEventListener("DOMFocusIn", focusinListener, false); 476 } 477 if (elt.hasAttributeNS(null, "onfocusout")) { 478 target.addEventListener("DOMFocusOut", focusoutListener, 479 false); 480 } 481 if (elt.hasAttributeNS(null, "onactivate")) { 482 target.addEventListener("DOMActivate", activateListener, 483 false); 484 } 485 if (elt.hasAttributeNS(null, "onclick")) { 486 target.addEventListener("click", clickListener, false); 487 } 488 if (elt.hasAttributeNS(null, "onmousedown")) { 489 target.addEventListener("mousedown", mousedownListener, false); 490 } 491 if (elt.hasAttributeNS(null, "onmouseup")) { 492 target.addEventListener("mouseup", mouseupListener, false); 493 } 494 if (elt.hasAttributeNS(null, "onmouseover")) { 495 target.addEventListener("mouseover", mouseoverListener, false); 496 } 497 if (elt.hasAttributeNS(null, "onmouseout")) { 498 target.addEventListener("mouseout", mouseoutListener, false); 499 } 500 if (elt.hasAttributeNS(null, "onmousemove")) { 501 target.addEventListener("mousemove", mousemoveListener, false); 502 } 503 if (elt.hasAttributeNS(null, "onkeypress")) { 504 target.addEventListener("keypress", keypressListener, false); 505 } 506 if (elt.hasAttributeNS(null, "onkeydown")) { 507 target.addEventListener("keydown", keydownListener, false); 508 } 509 if (elt.hasAttributeNS(null, "onkeyup")) { 510 target.addEventListener("keyup", keyupListener, false); 511 } 512 } 513 514 for (Node n = node.getFirstChild(); 516 n != null; 517 n = n.getNextSibling()) { 518 addScriptingListeners(n); 519 } 520 } 521 522 525 protected void removeScriptingListeners(Node node) { 526 if (node.getNodeType() == Node.ELEMENT_NODE) { 527 Element elt = (Element )node; 529 EventTarget target = (EventTarget )elt; 530 if (SVGConstants.SVG_NAMESPACE_URI.equals(elt.getNamespaceURI())) { 531 if (SVGConstants.SVG_SVG_TAG.equals(elt.getLocalName())) { 532 target.removeEventListener("SVGAbort", 534 svgAbortListener, false); 535 target.removeEventListener("SVGError", 536 svgErrorListener, false); 537 target.removeEventListener("SVGResize", 538 svgResizeListener, false); 539 target.removeEventListener("SVGScroll", 540 svgScrollListener, false); 541 target.removeEventListener("SVGUnload", 542 svgUnloadListener, false); 543 target.removeEventListener("SVGZoom", 544 svgZoomListener, false); 545 } else { 546 String name = elt.getLocalName(); 547 if (name.equals(SVGConstants.SVG_SET_TAG) || 548 name.startsWith("animate")) { 549 target.removeEventListener("beginEvent", 551 beginListener , 552 false); 553 target.removeEventListener("endEvent", 554 endListener, 555 false); 556 target.removeEventListener("repeatEvent", 557 repeatListener , 558 false); 559 return; 560 } 561 } 562 } 563 564 target.removeEventListener("DOMFocusIn", focusinListener, false); 566 target.removeEventListener("DOMFocusOut", focusoutListener, false); 567 target.removeEventListener("DOMActivate", activateListener, false); 568 target.removeEventListener("click", clickListener, false); 569 target.removeEventListener("mousedown", mousedownListener, false); 570 target.removeEventListener("mouseup", mouseupListener, false); 571 target.removeEventListener("mouseover", mouseoverListener, false); 572 target.removeEventListener("mouseout", mouseoutListener, false); 573 target.removeEventListener("mousemove", mousemoveListener, false); 574 target.removeEventListener("keypress", keypressListener, false); 575 target.removeEventListener("keydown", keydownListener, false); 576 target.removeEventListener("keyup", keyupListener, false); 577 } 578 579 for (Node n = node.getFirstChild(); 581 n != null; 582 n = n.getNextSibling()) { 583 removeScriptingListeners(n); 584 } 585 } 586 587 590 protected void updateScriptingListeners(Element elt, String attr) { 591 String domEvt = (String ) attrToDOMEvent.get(attr); 592 if (domEvt == null) return; EventListener listener = (EventListener )attrToListener.get(attr); 594 EventTarget target = (EventTarget ) elt; 595 if (elt.hasAttributeNS(null, attr)) 596 target.addEventListener(domEvt, listener, false); 597 else 598 target.removeEventListener(domEvt, listener, false); 599 } 600 601 602 605 protected class EvaluateRunnable implements Runnable { 606 protected Interpreter interpreter; 607 protected String script; 608 public EvaluateRunnable(String s, Interpreter interp) { 609 interpreter = interp; 610 script = s; 611 } 612 public void run() { 613 try { 614 interpreter.evaluate(script); 615 } catch (InterpreterException ie) { 616 handleInterpreterException(ie); 617 } 618 } 619 } 620 621 624 protected class EvaluateIntervalRunnable implements Runnable { 625 628 public int count; 629 public boolean error; 630 631 protected Interpreter interpreter; 632 protected String script; 633 634 public EvaluateIntervalRunnable(String s, Interpreter interp) { 635 interpreter = interp; 636 script = s; 637 } 638 public void run() { 639 synchronized (this) { 640 if (error) 641 return; 642 count--; 643 } 644 try { 645 interpreter.evaluate(script); 646 } catch (InterpreterException ie) { 647 handleInterpreterException(ie); 648 synchronized (this) { 649 error = true; 650 } 651 } catch (Exception e) { 652 if (userAgent != null) { 653 userAgent.displayError(e); 654 } else { 655 e.printStackTrace(); } 657 synchronized (this) { 658 error = true; 659 } 660 } 661 } 662 } 663 664 667 protected class EvaluateRunnableRunnable implements Runnable { 668 671 public int count; 672 public boolean error; 673 674 protected Runnable runnable; 675 676 public EvaluateRunnableRunnable(Runnable r) { 677 runnable = r; 678 } 679 public void run() { 680 synchronized (this) { 681 if (error) 682 return; 683 count--; 684 } 685 try { 686 runnable.run(); 687 } catch (Exception e) { 688 if (userAgent != null) { 689 userAgent.displayError(e); 690 } else { 691 e.printStackTrace(); } 693 synchronized (this) { 694 error = true; 695 } 696 } 697 } 698 } 699 700 703 protected class Window implements org.apache.batik.script.Window { 704 705 708 protected Interpreter interpreter; 709 710 713 protected String language; 714 715 718 public Window(Interpreter interp, String lang) { 719 interpreter = interp; 720 language = lang; 721 } 722 723 727 public Object setInterval(final String script, long interval) { 728 TimerTask tt = new TimerTask () { 729 EvaluateIntervalRunnable eir = 730 new EvaluateIntervalRunnable(script, interpreter); 731 public void run() { 732 synchronized |