1 #!/usr/bin/env python 2 3 """ 4 SVG-specific document support. 5 See: http://www.w3.org/TR/SVGMobile12/python-binding.html 6 See: http://www.w3.org/TR/SVGMobile12/svgudom.html 7 8 Copyright (C) 2007 Paul Boddie <paul@boddie.org.uk> 9 10 This library is free software; you can redistribute it and/or 11 modify it under the terms of the GNU Lesser General Public 12 License as published by the Free Software Foundation; either 13 version 2.1 of the License, or (at your option) any later version. 14 15 This library is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 Lesser General Public License for more details. 19 20 You should have received a copy of the GNU Lesser General Public 21 License along with this library; if not, write to the Free Software 22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 23 """ 24 25 import libxml2dom 26 from libxml2dom.events import * 27 from libxml2dom.macrolib import * 28 from libxml2dom.macrolib import \ 29 createDocument as Node_createDocument 30 import xml.dom 31 import urllib 32 import math 33 import re 34 35 SVG_NAMESPACE = "http://www.w3.org/2000/svg" 36 37 class _Exception(Exception): 38 39 "A generic SVG exception." 40 41 def __init__(self, code): 42 Exception.__init__(self, code) 43 self.code = code 44 45 class SVGException(_Exception): 46 47 "An SVG exception." 48 49 SVG_WRONG_TYPE_ERR = 0 50 SVG_INVALID_VALUE_ERR = 1 51 SVG_MATRIX_NOT_INVERTABLE = 2 52 53 class GlobalException(_Exception): 54 55 "A global exception." 56 57 NOT_CONNECTED_ERR = 1 58 ENCODING_ERR = 2 59 DENIED_ERR = 3 60 UNKNOWN_ERR = 4 61 62 class SVGImplementation(libxml2dom.Implementation): 63 64 "Contains an SVG-specific implementation." 65 66 # Wrapping of documents. 67 68 def adoptDocument(self, node): 69 return SVGDocument(node, self) 70 71 # Factory functions. 72 73 def get_node(self, _node, context_node): 74 if Node_nodeType(_node) == context_node.ELEMENT_NODE and \ 75 Node_namespaceURI(_node) == SVG_NAMESPACE: 76 77 if Node_localName(_node) == "svg": 78 return SVGSVGElement(_node, self, context_node.ownerDocument) 79 else: 80 return SVGElement(_node, self, context_node.ownerDocument) 81 else: 82 return libxml2dom.Implementation.get_node(self, _node, context_node) 83 84 def get_global(self, doc): 85 return SVGGlobal(doc) 86 87 # Convenience functions. 88 89 def createSVGDocument(self): 90 91 "Create a new SVG document." 92 93 return SVGDocument(Node_createDocument(SVG_NAMESPACE, "svg", None), self) 94 95 # Interfaces and helper classes. 96 97 class AsyncStatusCallback: 98 99 "An asynchronous callback interface." 100 101 def operationComplete(self, status): 102 pass 103 104 class AsyncURLStatus: 105 106 "The status of a URL retrieval operation." 107 108 def __init__(self, success, contentType, content): 109 self.success, self.contentType, self.content = success, contentType, content 110 111 class ElementTraversal: 112 113 "An interface for element traversal." 114 115 def _firstElementChild(self): 116 l = self.xpath("*") 117 if l: 118 return l[0] 119 else: 120 return None 121 122 def _lastElementChild(self): 123 l = self.xpath("*") 124 if l: 125 return l[-1] 126 else: 127 return None 128 129 def _nextElementSibling(self): 130 l = self.xpath("following-sibling::*") 131 if l: 132 return l[0] 133 else: 134 return None 135 136 def _previousElementSibling(self): 137 l = self.xpath("preceding-sibling::*") 138 if l: 139 return l[0] 140 else: 141 return None 142 143 firstElementChild = property(_firstElementChild) 144 lastElementChild = property(_lastElementChild) 145 nextElementSibling = property(_nextElementSibling) 146 previousElementSibling = property(_previousElementSibling) 147 148 class EventListenerInitializer2: 149 150 "An event listener initialisation interface." 151 152 def initializeEventListeners(self, scriptElement): 153 pass 154 155 def createEventListener(self, handlerElement): 156 pass 157 158 class Global: 159 160 "An empty global interface." 161 162 pass 163 164 class SVGGlobal(Global, EventListenerInitializer2): 165 166 "An SVG global." 167 168 def __init__(self, document): # parent 169 170 "Initialise the global with the given 'document'." 171 172 self.document = document 173 174 # Listener management. 175 176 self.listeners = {} 177 178 def createConnection(self): 179 raise NotImplementedError, "createConnection" 180 181 def createTimer(self, initialInterval, repeatInterval): 182 raise NotImplementedError, "createTimer" 183 184 def gotoLocation(self, newIRI): 185 raise NotImplementedError, "gotoLocation" 186 187 def binaryToString(self, octets, encoding): 188 try: 189 return unicode(octets, encoding) 190 except UnicodeDecodeError, exc: 191 raise GlobalException(GlobalException.ENCODING_ERR) 192 193 def stringToBinary(self, data, encoding): 194 try: 195 return data.encode(encoding) 196 except UnicodeEncodeError, exc: 197 raise GlobalException(GlobalException.ENCODING_ERR) 198 199 def getURL(self, iri, callback): 200 201 # NOTE: Not asynchronous. 202 # NOTE: The urlopen function may not support IRIs. 203 # No exceptions are supposed to be raised, which is a bit nasty. 204 205 f = urllib.urlopen(iri) 206 try: 207 try: 208 content = f.read() 209 contentType = f.headers["Content-Type"] 210 callback.operationComplete(AsyncURLStatus(1, contentType, content)) 211 except: 212 callback.operationComplete(AsyncURLStatus(0, None, None)) 213 finally: 214 f.close() 215 216 def postURL(self, iri, data, callback, type=None, encoding=None): 217 218 # NOTE: Not asynchronous. 219 # NOTE: The urlopen function may not support IRIs. 220 # No exceptions are supposed to be raised, which is a bit nasty. 221 222 opener = urllib.URLopener() 223 opener.addheader("Content-Type", type or "text/plain") 224 if encoding: 225 opener.addheader("Content-Encoding", encoding) 226 f = opener.open(iri, data) 227 try: 228 try: 229 content = f.read() 230 contentType = f.headers["Content-Type"] 231 callback.operationComplete(AsyncURLStatus(1, contentType, content)) 232 except: 233 callback.operationComplete(AsyncURLStatus(0, None, None)) 234 finally: 235 f.close() 236 opener.close() 237 238 def parseXML(self, data, contextDoc): 239 doc = parseString(data) 240 return contextDoc.importNode(doc.documentElement, 1) 241 242 class SVGLocatable: 243 244 "A locatable interface." 245 246 pass 247 248 class SVGMatrix: 249 250 """ 251 A matrix. 252 See: http://www.w3.org/TR/SVGMobile12/svgudom.html#svg__SVGMatrix 253 """ 254 255 translate_regexp = re.compile("translate\((.*)\)$") 256 scale_regexp = re.compile("scale\((.*)\)$") 257 rotate_regexp = re.compile("rotate\((.*)\)$") 258 skewX_regexp = re.compile("skewX\((.*)\)$") 259 skewY_regexp = re.compile("skewY\((.*)\)$") 260 matrix_regexp = re.compile("matrix\((.*)\)$") 261 262 def __init__(self, a=0, b=0, c=0, d=0, e=0, f=0): 263 self.matrix = a, b, c, d, e, f 264 265 def __eq__(self, other): 266 return self.matrix == other.matrix 267 268 def __ne__(self, other): 269 return not (self == other) 270 271 def _get_params(self, param_string): 272 return map(float, map(lambda s: s.strip(), param_string.split(","))) 273 274 def fromNode(self, node, name): 275 276 """ 277 Initialise this object from the trait on the 'node' having the given 278 'name'. 279 """ 280 281 value = node.getAttribute(name) 282 if value is None: 283 raise xml.dom.DOMException(xml.dom.NOT_SUPPORTED_ERR) 284 285 value = value.strip() 286 287 # Translation. 288 289 m = self.translate_regexp.match(value) 290 if m: 291 a, b, c, d = 1, 0, 0, 1 292 e, f = self._get_params(m.group(1)) 293 self.matrix = a, b, c, d, e, f 294 return 295 296 # Scaling. 297 298 m = self.scale_regexp.match(value) 299 if m: 300 b, c, e, f = 0, 0, 0, 0 301 a, d = self._get_params(m.group(1)) 302 self.matrix = a, b, c, d, e, f 303 return 304 305 # Rotation. 306 307 m = self.rotate_regexp.match(value) 308 if m: 309 e, f = 0, 0 310 angle = float(m.group(1).strip()) 311 a = d = math.cos(math.radians(angle)) 312 b = math.sin(math.radians(angle)) 313 c = -b 314 self.matrix = a, b, c, d, e, f 315 return 316 317 # Skew. 318 319 m = self.skewX_regexp.match(value) 320 if m: 321 a, b, d, e, f = 1, 0, 1, 0, 0 322 angle = float(m.group(1).strip()) 323 c = math.tan(math.radians(angle)) 324 self.matrix = a, b, c, d, e, f 325 return 326 327 m = self.skewY_regexp.match(value) 328 if m: 329 a, c, d, e, f = 1, 0, 1, 0, 0 330 angle = float(m.group(1).strip()) 331 b = math.tan(math.radians(angle)) 332 self.matrix = a, b, c, d, e, f 333 return 334 335 # Generic. 336 337 m = self.matrix_regexp.match(value) 338 if m: 339 self.matrix = self._get_params(m.group(1)) 340 return 341 342 # Otherwise, complain. 343 344 raise xml.dom.DOMException(xml.dom.TYPE_MISMATCH_ERR) 345 346 def toNode(self, node, name): 347 348 """ 349 Set the trait on the given 'node' using the given 'name' according to 350 this object's attributes. 351 """ 352 353 a, b, c, d, e, f = self.matrix 354 355 # Translation. 356 357 if (a, b, c, d) == (1, 0, 0, 1): 358 node.setAttribute(name, "translate(%f, %f)" % (e, f)) 359 360 # Scaling. 361 362 elif (b, c, e, f) == (0, 0, 0, 0): 363 node.setAttribute(name, "scale(%f, %f)" % (a, d)) 364 365 # Rotation. 366 367 elif a == d and b == -c and (e, f) == (0, 0) and math.degrees(math.acos(a)) == math.degrees(math.asin(b)): 368 node.setAttribute(name, "rotate(%f)" % math.degrees(math.acos(a))) 369 370 # Skew. 371 372 elif (a, b, d, e, f) == (1, 0, 1, 0, 0) and c != 0: 373 node.setAttribute(name, "skewX(%f)" % math.degrees(math.atan(c))) 374 375 elif (a, c, d, e, f) == (1, 0, 1, 0, 0) and b != 0: 376 node.setAttribute(name, "skewX(%f)" % math.degrees(math.atan(b))) 377 378 # Generic matrix. 379 380 else: 381 node.setAttribute(name, "matrix(%f, %f, %f, %f, %f, %f)" % (a, b, c, d, e, f)) 382 383 def getComponent(self, index): 384 385 """ 386 Return the component with the given 'index' (starting at zero) from the 387 sequence a, b, c, d, e, f where each element corresponds to the matrix 388 as follows: 389 390 [ a c e ] 391 [ b d f ] 392 [ 0 0 1 ] 393 """ 394 395 try: 396 return self.matrix[index] 397 except IndexError: 398 raise xml.dom.DOMException(xml.dom.INDEX_SIZE_ERR) 399 400 def mMultiply(self, secondMatrix): 401 402 """ 403 Multiply this matrix with 'secondMatrix' and update its contents to the 404 result of the multiplication operation defined as follows: 405 406 [ a c e ] [ A C E ] 407 [ b d f ] [ B D F ] 408 [ 0 0 1 ] [ 0 0 1 ] 409 410 Return this object as a result. 411 """ 412 413 a, b, c, d, e, f = self.matrix 414 A, B, C, D, E, F = secondMatrix.matrix 415 self.matrix = a*A + c*B, b*A + d*B, a*C + c*D, b*C + d*D, a*E + c*F + e, b*E + d*F + f 416 return self 417 418 def inverse(self): 419 420 """ 421 det = ad - cb 422 423 See (for example): http://mathworld.wolfram.com/MatrixInverse.html 424 """ 425 426 det = a*d - c*b 427 if det != 0: 428 m = 1/det 429 a, b, c, d, e, f = self.matrix 430 self.matrix = m * d, m * -b, m * -c, m * a, m * (c*f - e*d), m * (e*b - a*f) 431 return self 432 else: 433 raise SVGException(SVGException.SVG_MATRIX_NOT_INVERTABLE) 434 435 def mTranslate(self, x, y): 436 437 """ 438 [ 1 0 x ] 439 [ 0 1 y ] 440 [ 0 0 1 ] 441 """ 442 443 return self.mMultiply(SVGMatrix(1, 0, 0, 1, x, y)) 444 445 def mScale(self, scaleFactor): 446 447 """ 448 [ scaleFactor 0 0 ] 449 [ 0 scaleFactor 0 ] 450 [ 0 0 1 ] 451 """ 452 453 return self.mMultiply(SVGMatrix(scaleFactor, 0, 0, scaleFactor, 0, 0)) 454 455 def mRotate(self, angle): 456 457 """ 458 [ cos(angle) -sin(angle) 0 ] 459 [ sin(angle) cos(angle) 0 ] 460 [ 0 0 1 ] 461 """ 462 463 return self.mMultiply( 464 SVGMatrix( 465 math.cos(math.radians(angle)), 466 math.sin(math.radians(angle)), 467 -math.sin(math.radians(angle)), 468 math.cos(math.radians(angle)), 469 0, 0 470 ) 471 ) 472 473 class SVGPath: 474 475 """ 476 A path. 477 See: http://www.w3.org/TR/SVGMobile12/svgudom.html#svg__SVGPath 478 See: http://www.w3.org/TR/SVGMobile12/paths.html 479 """ 480 481 MOVE_TO = 77 482 LINE_TO = 76 483 CURVE_TO = 67 484 QUAD_TO = 81 485 CLOSE = 90 486 _CLOSE = 122 # More baggage (name not standard). 487 488 nparams = { 489 MOVE_TO : 2, 490 LINE_TO : 2, 491 CURVE_TO : 6, 492 QUAD_TO : 4, 493 CLOSE : 0, 494 _CLOSE : 0 495 } 496 497 def __init__(self): 498 self.segments = [] 499 500 def __eq__(self, other): 501 return self.segments == other.segments 502 503 def __ne__(self, other): 504 return not (self == other) 505 506 def fromNode(self, node, name): 507 508 """ 509 Initialise this object from the trait on the 'node' having the given 510 'name'. 511 """ 512 513 value = node.getAttribute(name) 514 if value is None: 515 raise xml.dom.DOMException(xml.dom.NOT_SUPPORTED_ERR) 516 517 # Try and unpack the attribute value. 518 519 data = value.split() 520 self.segments = [] 521 try: 522 i = 0 523 while i < len(data): 524 cmd = ord(data[i]) 525 if cmd == self._CLOSE: 526 cmd = self.CLOSE 527 i += 1 528 n = self.nparams[cmd] 529 params = map(float, data[i:i+n]) 530 self.segments.append((cmd, params)) 531 i += n 532 except (IndexError, ValueError): 533 raise xml.dom.DOMException(xml.dom.TYPE_MISMATCH_ERR) 534 535 def toNode(self, node, name): 536 537 """ 538 Set the trait on the given 'node' using the given 'name' according to 539 this object's attributes. 540 """ 541 542 try: 543 l = [] 544 for cmd, params in self.segments: 545 l.append(unichr(cmd)) 546 for param in params: 547 l.append(str(param)) 548 node.setAttribute(name, " ".join(l)) 549 except (IndexError, ValueError): 550 raise xml.dom.DOMException(xml.dom.TYPE_MISMATCH_ERR) 551 552 # Interface methods. 553 554 def _numberOfSegments(self): 555 return len(self.segments) 556 557 numberOfSegments = property(_numberOfSegments) 558 559 def getSegment(self, cmdIndex): 560 try: 561 return self.segments[cmdIndex][0] 562 except IndexError: 563 raise xml.dom.DOMException(xml.dom.INDEX_SIZE_ERR) 564 565 def getSegmentParam(self, cmdIndex, paramIndex): 566 try: 567 return self.segments[cmdIndex][1][paramIndex] 568 except IndexError: 569 raise xml.dom.DOMException(xml.dom.INDEX_SIZE_ERR) 570 571 def moveTo(self, x, y): 572 self.segments.append((self.MOVE_TO, (x, y))) 573 574 def lineTo(self, x, y): 575 self.segments.append((self.LINE_TO, (x, y))) 576 577 def quadTo(self, x1, y1, x2, y2): 578 self.segments.append((self.QUAD_TO, (x1, y1, x2, y2))) 579 580 def curveTo(self, x1, y1, x2, y2, x3, y3): 581 self.segments.append((self.CURVE_TO, (x1, y1, x2, y2, x3, y3))) 582 583 def close(self): 584 self.segments.append((self.CLOSE,)) 585 586 class SVGPoint: 587 588 "A point used to provide currentTranslate." 589 590 def __init__(self, x, y): 591 self.x = x 592 self.y = y 593 594 class SVGRect: 595 596 "A rectangle." 597 598 def __init__(self, x=0, y=0, width=0, height=0): 599 self.x, self.y, self.width, self.height = x, y, width, height 600 601 def __eq__(self, other): 602 return (self.x, self.y, self.width, self.height) == (other.x, other.y, other.width, other.height) 603 604 def __ne__(self, other): 605 return not (self == other) 606 607 def fromNode(self, node, name): 608 609 """ 610 Initialise this object from the trait on the 'node' having the given 611 'name'. 612 """ 613 614 value = node.getAttribute(name) 615 if value is None: 616 raise xml.dom.DOMException(xml.dom.NOT_SUPPORTED_ERR) 617 try: 618 values = map(float, value.split()) 619 self.x, self.y, self.width, self.height = values 620 except (IndexError, ValueError): 621 raise xml.dom.DOMException(xml.dom.TYPE_MISMATCH_ERR) 622 623 def toNode(self, node, name): 624 625 """ 626 Set the trait on the given 'node' using the given 'name' according to 627 this object's attributes. 628 """ 629 630 try: 631 values = map(str, [self.x, self.y, self.width, self.height]) 632 node.setAttribute(name, " ".join(values)) 633 except (IndexError, ValueError): 634 raise xml.dom.DOMException(xml.dom.TYPE_MISMATCH_ERR) 635 636 class SVGRGBColor: 637 638 "A colour." 639 640 def __init__(self, red, green, blue): 641 self.red, self.green, self.blue = red, green, blue 642 643 class TraitAccess: 644 645 """ 646 Access to traits stored on elements. 647 See: http://www.w3.org/TR/SVGMobile12/svgudom.html#svg__TraitAccess 648 """ 649 650 def getPathTrait(self, name): 651 path = SVGPath() 652 path.fromNode(self, name) 653 return path 654 655 def setPathTrait(self, name, path): 656 path.toNode(self, name) 657 658 def getRectTrait(self, name): 659 rect = SVGRect() 660 rect.fromNode(self, name) 661 return rect 662 663 def setRectTrait(self, name, rect): 664 rect.toNode(self, name) 665 666 def getMatrixTrait(self, name): 667 matrix = SVGMatrix() 668 matrix.fromNode(self, name) 669 return matrix 670 671 def setMatrixTrait(self, name, matrix): 672 matrix.toNode(self, name) 673 674 # Node classes. 675 676 class SVGNode(libxml2dom.Node): 677 678 "Convenience modifications to nodes specific to libxml2dom.svg." 679 680 def xpath(self, expr, variables=None, namespaces=None): 681 682 """ 683 Evaluate the given 'expr' using the optional 'variables' and 684 'namespaces'. If not otherwise specified, the "svg" prefix will be bound 685 to SVG_NAMESPACE as defined in this module. 686 """ 687 688 namespaces = namespaces or {} 689 if not namespaces.has_key("svg"): 690 namespaces["svg"] = SVG_NAMESPACE 691 return libxml2dom.Node.xpath(self, expr, variables, namespaces) 692 693 class SVGDocument(libxml2dom._Document, SVGNode, EventTarget, DocumentEvent): # NOTE: The latter is from DOM Level 3 Events. 694 695 "An SVG-specific document node." 696 697 def __init__(self, node, impl): 698 699 """ 700 Initialise the document with the given 'node', implementation 'impl', 701 and global (SVGGlobal) details. 702 """ 703 704 libxml2dom._Document.__init__(self, node, impl) 705 self.global_ = self.impl.get_global(self) # parent 706 707 class SVGElement(SVGNode, EventTarget, TraitAccess, ElementTraversal): # NOTE: SVGNode instead of Element. 708 709 "An SVG-specific element." 710 711 def __init__(self, *args, **kw): 712 SVGNode.__init__(self, *args, **kw) 713 714 def _id(self): 715 return self.getAttribute("id") 716 717 def _setId(self, value): 718 self.setAttribute("id", value) 719 720 id = property(_id, _setId) 721 722 class SVGLocatableElement(SVGElement, SVGLocatable): 723 724 "A locatable element." 725 726 pass 727 728 class SVGTimedElement(SVGElement): # smil::ElementTimeControl 729 730 "A timed element." 731 732 def __init__(self, *args): 733 734 "Initialise the element with the underlying 'args'." 735 736 SVGElement.__init__(self, *args) 737 self.document_time = 0 738 self.paused = 0 739 740 def _isPaused(self): 741 return self.paused 742 743 def pauseElement(self): 744 self.paused = 1 745 746 def resumeElement(self): 747 self.paused = 0 748 749 class SVGSVGElement(SVGLocatableElement, SVGTimedElement): 750 751 "An SVG-specific top-level element." 752 753 NAV_AUTO = 1 754 NAV_NEXT = 2 755 NAV_PREV = 3 756 NAV_UP = 4 757 NAV_UP_RIGHT = 5 758 NAV_RIGHT = 6 759 NAV_DOWN_RIGHT = 7 760 NAV_DOWN = 8 761 NAV_DOWN_LEFT = 9 762 NAV_LEFT = 10 763 NAV_UP_LEFT = 11 764 765 def __init__(self, *args): 766 767 "Initialise the element with the underlying 'args'." 768 769 SVGTimedElement.__init__(self, *args) 770 self.scale = 1 771 self.rotate = 0 772 self.translate = SVGPoint(0, 0) 773 774 def _currentScale(self): 775 return self.scale 776 777 def _currentRotate(self): 778 return self.rotate 779 780 def _currentTranslate(self): 781 return self.translate 782 783 def _viewport(self): 784 return self.getRectTrait("viewBox") 785 786 def getCurrentTime(self): 787 return self.document_time 788 789 def setCurrentTime(self, setCurrentTime): 790 self.document_time = setCurrentTime 791 792 def createSVGMatrixComponents(self, a, b, c, d, e, f): 793 return SVGMatrix(a, b, c, d, e, f) 794 795 def createSVGRect(self): 796 return SVGRect() 797 798 def createSVGPath(self): 799 return SVGPath() 800 801 def createSVGRGBColor(self, red, green, blue): 802 return SVGRGBColor(red, green, blue) 803 804 def moveFocus(self, motionType): 805 raise NotImplementedError, "moveFocus" 806 807 def setFocus(self, object): 808 raise NotImplementedError, "setFocus" 809 810 def getCurrentFocusedObject(self): 811 raise NotImplementedError, "getCurrentFocusedObject" 812 813 currentScale = property(_currentScale) 814 currentRotate = property(_currentRotate) 815 currentTranslate = property(_currentTranslate) 816 viewport = property(_viewport) 817 818 # Event handler initialisation. 819 820 def initialiseEvents(doc): 821 822 """ 823 See: http://www.w3.org/TR/SVGMobile12/svgudom.html#svg__EventListenerInitializer2 824 """ 825 826 for script in doc.xpath("//svg:script"): 827 doc.global_.initializeEventListeners(script) 828 for handler in doc.xpath("//svg:handler"): 829 listener = doc.global_.createEventListener(handler) 830 831 # NOTE: May need to have the event type understood and correctly parameterised. 832 833 handler.parentNode.addEventListener( 834 handler.getAttributeNS(libxml2dom.events.XML_EVENTS_NAMESPACE, "event"), 835 listener, 836 0 837 ) 838 839 # Utility functions. 840 841 createDocument = libxml2dom.createDocument 842 createDocumentType = libxml2dom.createDocumentType 843 844 def createSVGDocument(): 845 return default_impl.createSVGDocument() 846 847 def parse(stream_or_string, html=0, htmlencoding=None, impl=None): 848 doc = libxml2dom.parse(stream_or_string, html, htmlencoding, impl or default_impl) 849 initialiseEvents(doc) 850 return doc 851 852 def parseFile(filename, html=0, htmlencoding=None, impl=None): 853 doc = libxml2dom.parseFile(filename, html, htmlencoding, impl or default_impl) 854 initialiseEvents(doc) 855 return doc 856 857 def parseString(s, html=0, htmlencoding=None, impl=None): 858 doc = libxml2dom.parseString(s, html, htmlencoding, impl or default_impl) 859 initialiseEvents(doc) 860 return doc 861 862 def parseURI(uri, html=0, htmlencoding=None, impl=None): 863 doc = libxml2dom.parseURI(uri, html, htmlencoding, impl or default_impl) 864 initialiseEvents(doc) 865 return doc 866 867 # Single instance of the implementation. 868 869 default_impl = SVGImplementation() 870 871 # vim: tabstop=4 expandtab shiftwidth=4