View Javadoc

1   /**********************************************
2    * Copyright (C) 2010 Lukas Laag
3    * This file is part of lib-gwt-svg.
4    * 
5    * libgwtsvg is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU Lesser General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    * 
10   * libgwtsvg is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU Lesser General Public License for more details.
14   * 
15   * You should have received a copy of the GNU Lesser General Public License
16   * along with libgwtsvg.  If not, see http://www.gnu.org/licenses/
17   **********************************************/
18  /*
19   * Copyright (c) 2004 World Wide Web Consortium,
20   *
21   * (Massachusetts Institute of Technology, European Research Consortium for
22   * Informatics and Mathematics, Keio University). All Rights Reserved. This
23   * work is distributed under the W3C(r) Software License [1] in the hope that
24   * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
25   * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26   *
27   * [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
28   */
29  package org.vectomatic.dom.svg;
30  
31  import org.vectomatic.dom.svg.impl.DOMEventBus;
32  import org.vectomatic.dom.svg.utils.DOMHelper;
33  import org.w3c.dom.DOMException;
34  
35  import com.google.gwt.core.client.JavaScriptException;
36  import com.google.gwt.core.client.JavaScriptObject;
37  import com.google.gwt.dom.client.Document;
38  import com.google.gwt.dom.client.NativeEvent;
39  import com.google.gwt.dom.client.Node;
40  import com.google.gwt.event.dom.client.DomEvent;
41  import com.google.gwt.event.shared.EventBus;
42  import com.google.gwt.event.shared.EventHandler;
43  import com.google.gwt.event.shared.GwtEvent;
44  import com.google.gwt.event.shared.HandlerRegistration;
45  import com.google.gwt.event.shared.HasHandlers;
46  import com.google.gwt.event.shared.UmbrellaException;
47  import com.google.gwt.user.client.Element;
48  
49  /**
50   * Wrapper class for DOM Node. Wrapper classes decorate native
51   * DOM objects with java-like capabilities: capability to implement
52   * interfaces, notably event handler interfaces.
53   * @author laaglu
54   * @author Michael Allan
55   */
56  public class OMNode implements HasHandlers {
57  	/**
58  	 * The DOM native overlay type wrapped by this object
59  	 */
60  	protected final Node ot;
61  	/**
62  	 * The event bus shared by all SVG objects
63  	 */
64  	static protected EventBus eventBus = new DOMEventBus();
65  
66  	/**
67  	 * Constructor
68  	 * @param node The node to wrap
69  	 */
70  	protected OMNode(Node node) {
71  		assert getWrapper(node) == null : "node was already wrapped";
72  		setWrapper(node, this);
73  		this.ot = node;
74  	}
75  	
76  	/**
77  	 * Sets the __wrapper property of the node.
78  	 */
79  	private static native void setWrapper(Node node, OMNode wrapper) /*-{
80      	node.__wrapper = wrapper;
81  	}-*/;
82  	
83  	/**
84  	 * Returns the __wrapper property of the node.
85  	 */
86  	private static native OMNode getWrapper(Node node) /*-{ 
87  		return node.__wrapper; 
88  	}-*/;
89  	
90  	/**
91  	 * Cleanup method for wrapper objects which are
92  	 * not needed by the application any more. It
93  	 * breaks the back-reference the native DOM object
94  	 * maintains on this wrapper type, in order to
95  	 * facilitate garbage collection. Use only if
96  	 * your code needs to run in a browser which is
97  	 * not equipped with an automatic DOM object-native 
98  	 * object cycle collector.
99  	 */
100 	public void cleanup() {
101 		setWrapper(ot, null);
102 	}
103 
104 	/**
105 	 * Returns the event bus shared by all SVG objects
106 	 * @return the event bus shared by all SVG objects
107 	 */
108 	public static EventBus getEventBus() {
109 		return eventBus;
110 	}
111     /**
112      * Fires the given event to the handlers listening to the event's type.
113      * <p>
114      * Any exceptions thrown by handlers will be bundled into a
115      * {@link UmbrellaException} and then re-thrown after all handlers have
116      * completed. An exception thrown by a handler will not prevent other handlers
117      * from executing.
118      * @param event the event
119      */
120 	public void fireEvent(GwtEvent<?> event) {
121 		revive(event);
122 		eventBus.fireEventFromSource(event, this);
123 	}
124 	/**
125 	 * Revive the event. GWT does it by taking advantage of the
126 	 * fact that HandlerManager has package access to GwtEvent.
127 	 * Here we use a JSNI call to bypass scope restrictions
128 	 */
129 	private static final native void revive(GwtEvent<?> event) /*-{
130 	  event.@com.google.gwt.event.shared.GwtEvent::revive()();
131 	}-*/;
132 	
133 	/**
134 	 * Dispatches the specified event to this node
135 	 * event handlers
136 	 * @param event The event to dispatch
137 	 */
138 	public void dispatch(NativeEvent event) {
139 		// This call wraps the native event into a DomEvent
140 		// and invokes fireEvent
141 	    DomEvent.fireNativeEvent(event, this, (Element)event.getCurrentEventTarget().cast());
142 	}
143 
144 	/**
145 	 * Adds a DOM handler to this node's list of handlers
146 	 * @param <H> The handler type
147 	 * @param handler The DOM handler
148 	 * @param type The event type
149 	 * @return {@link HandlerRegistration} used to remove this handler
150 	 */
151 	public final <H extends EventHandler> HandlerRegistration addDomHandler(
152 			final H handler, DomEvent.Type<H> type) {
153 		assert handler != null : "handler must not be null";
154 		assert type != null : "type must not be null";
155 		DOMHelper.bindEventListener((Element)ot.cast(), type.getName());
156 		return eventBus.addHandlerToSource(type, this, handler);
157 	}
158 
159 	/**
160 	 * Adds a handler to this node's list of handlers
161 	 * @param <H> The handler type
162 	 * @param handler The handler
163 	 * @param type The event type
164 	 * @return {@link HandlerRegistration} used to remove this handler
165 	 */
166 	public final <H extends EventHandler> HandlerRegistration addHandler(
167 			final H handler, GwtEvent.Type<H> type) {
168 		return eventBus.addHandlerToSource(type, this, handler);
169 	}
170 
171 	private static class Conversion<T extends OMNode> {
172 		static {
173 			initialize();
174 		}
175 		private static final native void initialize() /*-{
176 			if ($wnd.otToWrapper == null) {
177 		    	$wnd.otToWrapper = new Object();
178 		    }
179 			$wnd.otToWrapper["SVGAElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAElement::new(Lorg/vectomatic/dom/svg/impl/SVGAElement;)(elem); };
180 			$wnd.otToWrapper["SVGAltGlyphDefElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAltGlyphDefElement::new(Lorg/vectomatic/dom/svg/impl/SVGAltGlyphDefElement;)(elem); };
181 			$wnd.otToWrapper["SVGAltGlyphElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAltGlyphElement::new(Lorg/vectomatic/dom/svg/impl/SVGAltGlyphElement;)(elem); };
182 			$wnd.otToWrapper["SVGAltGlyphItemElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAltGlyphItemElement::new(Lorg/vectomatic/dom/svg/impl/SVGAltGlyphItemElement;)(elem); };
183 			$wnd.otToWrapper["SVGAnimateColorElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateColorElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateColorElement;)(elem); };
184 			$wnd.otToWrapper["SVGAnimateElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateElement;)(elem); };
185 			$wnd.otToWrapper["SVGAnimateMotionElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateMotionElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateMotionElement;)(elem); };
186 			$wnd.otToWrapper["SVGAnimateTransformElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateTransformElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateTransformElement;)(elem); };
187 			$wnd.otToWrapper["SVGCircleElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGCircleElement::new(Lorg/vectomatic/dom/svg/impl/SVGCircleElement;)(elem); };
188 			$wnd.otToWrapper["SVGClipPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGClipPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGClipPathElement;)(elem); };
189 			$wnd.otToWrapper["SVGColorProfileElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGColorProfileElement::new(Lorg/vectomatic/dom/svg/impl/SVGColorProfileElement;)(elem); };
190 			$wnd.otToWrapper["SVGCursorElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGCursorElement::new(Lorg/vectomatic/dom/svg/impl/SVGCursorElement;)(elem); };
191 			$wnd.otToWrapper["SVGDefsElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGDefsElement::new(Lorg/vectomatic/dom/svg/impl/SVGDefsElement;)(elem); };
192 			$wnd.otToWrapper["SVGDescElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGDescElement::new(Lorg/vectomatic/dom/svg/impl/SVGDescElement;)(elem); };
193 			$wnd.otToWrapper["SVGDocument"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGDocument::new(Lorg/vectomatic/dom/svg/impl/SVGDocument;)(elem); };
194 			$wnd.otToWrapper["SVGEllipseElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGEllipseElement::new(Lorg/vectomatic/dom/svg/impl/SVGEllipseElement;)(elem); };
195 			$wnd.otToWrapper["SVGFEBlendElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEBlendElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEBlendElement;)(elem); };
196 			$wnd.otToWrapper["SVGFEColorMatrixElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEColorMatrixElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEColorMatrixElement;)(elem); };
197 			$wnd.otToWrapper["SVGFEComponentTransferElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEComponentTransferElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEComponentTransferElement;)(elem); };
198 			$wnd.otToWrapper["SVGFECompositeElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFECompositeElement::new(Lorg/vectomatic/dom/svg/impl/SVGFECompositeElement;)(elem); };
199 			$wnd.otToWrapper["SVGFEConvolveMatrixElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEConvolveMatrixElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEConvolveMatrixElement;)(elem); };
200 			$wnd.otToWrapper["SVGFEDiffuseLightingElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEDiffuseLightingElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEDiffuseLightingElement;)(elem); };
201 			$wnd.otToWrapper["SVGFEDisplacementMapElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEDisplacementMapElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEDisplacementMapElement;)(elem); };
202 			$wnd.otToWrapper["SVGFEDistantLightElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEDistantLightElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEDistantLightElement;)(elem); };
203 			$wnd.otToWrapper["SVGFEFloodElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFloodElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFloodElement;)(elem); };
204 			$wnd.otToWrapper["SVGFEFuncAElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncAElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncAElement;)(elem); };
205 			$wnd.otToWrapper["SVGFEFuncBElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncBElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncBElement;)(elem); };
206 			$wnd.otToWrapper["SVGFEFuncGElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncGElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncGElement;)(elem); };
207 			$wnd.otToWrapper["SVGFEFuncRElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncRElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncRElement;)(elem); };
208 			$wnd.otToWrapper["SVGFEGaussianBlurElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEGaussianBlurElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEGaussianBlurElement;)(elem); };
209 			$wnd.otToWrapper["SVGFEImageElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEImageElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEImageElement;)(elem); };
210 			$wnd.otToWrapper["SVGFEMergeElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEMergeElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEMergeElement;)(elem); };
211 			$wnd.otToWrapper["SVGFEMergeNodeElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEMergeNodeElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEMergeNodeElement;)(elem); };
212 			$wnd.otToWrapper["SVGFEMorphologyElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEMorphologyElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEMorphologyElement;)(elem); };
213 			$wnd.otToWrapper["SVGFEOffsetElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEOffsetElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEOffsetElement;)(elem); };
214 			$wnd.otToWrapper["SVGFEPointLightElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEPointLightElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEPointLightElement;)(elem); };
215 			$wnd.otToWrapper["SVGFESpecularLightingElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFESpecularLightingElement::new(Lorg/vectomatic/dom/svg/impl/SVGFESpecularLightingElement;)(elem); };
216 			$wnd.otToWrapper["SVGFESpotLightElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFESpotLightElement::new(Lorg/vectomatic/dom/svg/impl/SVGFESpotLightElement;)(elem); };
217 			$wnd.otToWrapper["SVGFETileElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFETileElement::new(Lorg/vectomatic/dom/svg/impl/SVGFETileElement;)(elem); };
218 			$wnd.otToWrapper["SVGFETurbulenceElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFETurbulenceElement::new(Lorg/vectomatic/dom/svg/impl/SVGFETurbulenceElement;)(elem); };
219 			$wnd.otToWrapper["SVGFilterElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFilterElement::new(Lorg/vectomatic/dom/svg/impl/SVGFilterElement;)(elem); };
220 			$wnd.otToWrapper["SVGFontElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontElement;)(elem); };
221 			$wnd.otToWrapper["SVGFontFaceElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceElement;)(elem); };
222 			$wnd.otToWrapper["SVGFontFaceFormatElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceFormatElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceFormatElement;)(elem); };
223 			$wnd.otToWrapper["SVGFontFaceNameElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceNameElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceNameElement;)(elem); };
224 			$wnd.otToWrapper["SVGFontFaceSrcElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceSrcElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceSrcElement;)(elem); };
225 			$wnd.otToWrapper["SVGFontFaceUriElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceUriElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceUriElement;)(elem); };
226 			$wnd.otToWrapper["SVGForeignObjectElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGForeignObjectElement::new(Lorg/vectomatic/dom/svg/impl/SVGForeignObjectElement;)(elem); };
227 			$wnd.otToWrapper["SVGGElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGGElement::new(Lorg/vectomatic/dom/svg/impl/SVGGElement;)(elem); };
228 			$wnd.otToWrapper["SVGGlyphElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGGlyphElement::new(Lorg/vectomatic/dom/svg/impl/SVGGlyphElement;)(elem); };
229 			$wnd.otToWrapper["SVGGlyphRefElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGGlyphRefElement::new(Lorg/vectomatic/dom/svg/impl/SVGGlyphRefElement;)(elem); };
230 			$wnd.otToWrapper["SVGHKernElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGHKernElement::new(Lorg/vectomatic/dom/svg/impl/SVGHKernElement;)(elem); };
231 			$wnd.otToWrapper["SVGImageElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGImageElement::new(Lorg/vectomatic/dom/svg/impl/SVGImageElement;)(elem); };
232 			$wnd.otToWrapper["SVGLinearGradientElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGLinearGradientElement::new(Lorg/vectomatic/dom/svg/impl/SVGLinearGradientElement;)(elem); };
233 			$wnd.otToWrapper["SVGLineElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGLineElement::new(Lorg/vectomatic/dom/svg/impl/SVGLineElement;)(elem); };
234 			$wnd.otToWrapper["SVGMarkerElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMarkerElement::new(Lorg/vectomatic/dom/svg/impl/SVGMarkerElement;)(elem); };
235 			$wnd.otToWrapper["SVGMaskElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMaskElement::new(Lorg/vectomatic/dom/svg/impl/SVGMaskElement;)(elem); };
236 			$wnd.otToWrapper["SVGMetadataElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMetadataElement::new(Lorg/vectomatic/dom/svg/impl/SVGMetadataElement;)(elem); };
237 			$wnd.otToWrapper["SVGMissingGlyphElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMissingGlyphElement::new(Lorg/vectomatic/dom/svg/impl/SVGMissingGlyphElement;)(elem); };
238 			$wnd.otToWrapper["SVGMPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGMPathElement;)(elem); };
239 			$wnd.otToWrapper["SVGPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGPathElement;)(elem); };
240 			$wnd.otToWrapper["SVGPatternElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPatternElement::new(Lorg/vectomatic/dom/svg/impl/SVGPatternElement;)(elem); };
241 			$wnd.otToWrapper["SVGPolygonElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPolygonElement::new(Lorg/vectomatic/dom/svg/impl/SVGPolygonElement;)(elem); };
242 			$wnd.otToWrapper["SVGPolylineElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPolylineElement::new(Lorg/vectomatic/dom/svg/impl/SVGPolylineElement;)(elem); };
243 			$wnd.otToWrapper["SVGRadialGradientElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGRadialGradientElement::new(Lorg/vectomatic/dom/svg/impl/SVGRadialGradientElement;)(elem); };
244 			$wnd.otToWrapper["SVGRectElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGRectElement::new(Lorg/vectomatic/dom/svg/impl/SVGRectElement;)(elem); };
245 			$wnd.otToWrapper["SVGRectElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGRectElement::new(Lorg/vectomatic/dom/svg/impl/SVGRectElement;)(elem); };
246 			$wnd.otToWrapper["SVGScriptElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGScriptElement::new(Lorg/vectomatic/dom/svg/impl/SVGScriptElement;)(elem); };
247 			$wnd.otToWrapper["SVGSetElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSetElement::new(Lorg/vectomatic/dom/svg/impl/SVGSetElement;)(elem); };
248 			$wnd.otToWrapper["SVGStopElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGStopElement::new(Lorg/vectomatic/dom/svg/impl/SVGStopElement;)(elem); };
249 			$wnd.otToWrapper["SVGStyleElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGStyleElement::new(Lorg/vectomatic/dom/svg/impl/SVGStyleElement;)(elem); };
250 			$wnd.otToWrapper["SVGSVGElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSVGElement::new(Lorg/vectomatic/dom/svg/impl/SVGSVGElement;)(elem); };
251 			$wnd.otToWrapper["SVGSwitchElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSwitchElement::new(Lorg/vectomatic/dom/svg/impl/SVGSwitchElement;)(elem); };
252 			$wnd.otToWrapper["SVGSymbolElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSymbolElement::new(Lorg/vectomatic/dom/svg/impl/SVGSymbolElement;)(elem); };
253 			$wnd.otToWrapper["SVGTextElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTextElement::new(Lorg/vectomatic/dom/svg/impl/SVGTextElement;)(elem); };
254 			$wnd.otToWrapper["SVGTextPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTextPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGTextPathElement;)(elem); };
255 			$wnd.otToWrapper["SVGTitleElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTitleElement::new(Lorg/vectomatic/dom/svg/impl/SVGTitleElement;)(elem); };
256 			$wnd.otToWrapper["SVGTRefElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTRefElement::new(Lorg/vectomatic/dom/svg/impl/SVGTRefElement;)(elem); };
257 			$wnd.otToWrapper["SVGTSpanElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTSpanElement::new(Lorg/vectomatic/dom/svg/impl/SVGTSpanElement;)(elem); };
258 			$wnd.otToWrapper["SVGUseElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGUseElement::new(Lorg/vectomatic/dom/svg/impl/SVGUseElement;)(elem); };
259 			$wnd.otToWrapper["SVGViewElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGViewElement::new(Lorg/vectomatic/dom/svg/impl/SVGViewElement;)(elem); };
260 			$wnd.otToWrapper["SVGVKernElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGVKernElement::new(Lorg/vectomatic/dom/svg/impl/SVGVKernElement;)(elem); };
261 		}-*/;
262 		T result;
263 		Conversion(Node node) {
264 			convert(node);
265 		}
266 		private final native void convert(Node node) /*-{
267 			var wrapper = null;
268 			if (node != null) {
269 			    var type = @org.vectomatic.dom.svg.utils.DOMHelper::getType(Lcom/google/gwt/core/client/JavaScriptObject;)(node);
270 			    if (type) {
271 			    	var ctor = $wnd.otToWrapper[type];
272 			    	if (ctor != null) {
273 		    			wrapper = ctor(node);
274 			    	} else {
275 			    		if (node.nodeType == 1) {
276 			    			wrapper = @org.vectomatic.dom.svg.OMElement::new(Lcom/google/gwt/dom/client/Element;)(node);
277 			    		} else if (node.nodeType == 2) {
278 			    			wrapper = @org.vectomatic.dom.svg.OMAttr::new(Lorg/vectomatic/dom/svg/impl/Attr;)(node);
279 			    		} else if (node.nodeType == 3) {
280 			    			wrapper = @org.vectomatic.dom.svg.OMText::new(Lcom/google/gwt/dom/client/Text;)(node);
281 			    		} else if (node.nodeType == 9) {
282 							wrapper = @org.vectomatic.dom.svg.OMSVGDocument::new(Lorg/vectomatic/dom/svg/impl/SVGDocument;)(node);
283 			    		} else {
284 			    			wrapper = @org.vectomatic.dom.svg.OMNode::new(Lcom/google/gwt/dom/client/Node;)(node);
285 			    		}
286 			    	}
287 			    }
288 			}
289 	        this.@org.vectomatic.dom.svg.OMNode.Conversion::result = wrapper;
290 	    }-*/;
291 	}
292 	
293 	/**
294 	 * Returns the wrapper for the specified overlay type node, automatically constructing
295 	 * a new wrapper if the node was previously unwrapped.
296 	 * @param <T> the node type
297 	 * @param obj The overlay type node
298 	 * @return The node wrapper
299 	 */
300 	public static <T extends OMNode> T convert(Node obj) {
301 		// Misleading to parametize by T here, because we cannot guarantee type safety.
302 		// The explicit cast below is liable to failure, and so is the implicit cast in
303 		// Conversion.  Instead we might try overloading the convert methods, as with a
304 		// convert(Element) that safely casts to OMElement.  (Later)
305 		@SuppressWarnings("unchecked") T wrapper = (T)getWrapper(obj);
306 		if (wrapper == null) wrapper = new Conversion<T>(obj).result;
307 		return wrapper;
308 	}
309 	
310 	private static class ListConversion<T extends Iterable<? extends OMNode>> {
311 		static {
312 			initialize();
313 		}
314 		private static final native void initialize() /*-{
315 			if ($wnd.otToWrapper == null) {
316 		    	$wnd.otToWrapper = new Object();
317 		    }
318 			$wnd.otToWrapper["NodeList"] = function(elem) { return @org.vectomatic.dom.svg.OMNodeList::new(Lcom/google/gwt/dom/client/NodeList;)(elem); };
319 			$wnd.otToWrapper["SVGLengthList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGLengthList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
320 			$wnd.otToWrapper["SVGNumberList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGNumberList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
321 			$wnd.otToWrapper["SVGPathSegList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPathSegList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
322 			$wnd.otToWrapper["SVGPointList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPointList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
323 			$wnd.otToWrapper["SVGStringList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGStringList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
324 			$wnd.otToWrapper["SVGTransformList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTransformList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
325 		}-*/;
326 		T result;
327 		ListConversion(JavaScriptObject list) {
328 			convert(list);
329 		}
330 		private final native void convert(JavaScriptObject list) /*-{
331 			var wrapper = null;
332 		    var type = @org.vectomatic.dom.svg.utils.DOMHelper::getType(Lcom/google/gwt/core/client/JavaScriptObject;)(list);
333 		    if (type) {
334 		    	var ctor = $wnd.otToWrapper[type];
335 		    	if (ctor != null) {
336 	    			wrapper = ctor(list);
337 		    	}
338 		    }
339 	        this.@org.vectomatic.dom.svg.OMNode.ListConversion::result = wrapper;
340 	    }-*/;
341 	}
342 	
343 	/**
344 	 * Generates a wrapper around an overlay type list
345 	 * @param <T> the list type
346 	 * @param obj The overlay type list
347 	 * @return The list wrapper
348 	 */
349 	public static <T extends Iterable<? extends OMNode>> T convertList(JavaScriptObject obj) {
350 		return new ListConversion<T>(obj).result;
351 	}
352 
353 	/**
354 	 * Returns the wrapped node
355 	 * @return the wrapped node
356 	 */
357 	public Node getNode() {
358 		return ot;
359 	}
360 		
361 	// Implementation of the dom::Node W3C IDL interface
362     /**
363      * The name of this node, depending on its type.
364      * @return name of this node
365      */
366 	public final String getNodeName() {
367 		return ot.getNodeName();
368 	}
369 
370     /**
371      * The value of this node, depending on its type. 
372      * When it is defined to be <code>null</code>, setting it has no effect, 
373      * including if the node is read-only.
374      */
375 	public final String getNodeValue() {
376 		return ot.getNodeValue();
377 	}
378 
379     /**
380      * The value of this node, depending on its type; see the table above. 
381      * When it is defined to be <code>null</code>, setting it has no effect, 
382      * including if the node is read-only.
383      * @param value The node value
384      * @exception DOMException
385      *   NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly and if 
386      *   it is not defined to be <code>null</code>.
387      */
388 	public final void setNodeValue(String value) throws JavaScriptException {
389 		ot.setNodeValue(value);
390 	}
391 
392     /**
393      * A code representing the type of the underlying object.
394      * @return A code representing the type of the underlying object
395      */
396 	public final short getNodeType() {
397 		return ot.getNodeType();
398 	}
399 
400     /**
401      * The parent of this node. All nodes, except <code>OMAttr</code>, 
402      * <code>OMDocument</code> may have a parent. 
403      * However, if a node has just been created and not yet added to the 
404      * tree, or if it has been removed from the tree, this is 
405      * <code>null</code>.
406      * @return The parent of this node
407      */
408 	public final OMNode getParentNode() {
409 		Node parentNode = ot.getParentNode();
410 		return (parentNode != null) ? convert(parentNode) : null;
411 	}
412 	
413     /**
414      * A <code>OMNodeList</code> that contains all children of this node. If 
415      * there are no children, this is a <code>OMNodeList</code> containing no 
416      * nodes.
417      * @return A <code>OMNodeList</code> that contains all children of this node. If 
418      */
419 	public final <T extends OMNode> OMNodeList<T> getChildNodes() {
420 		return new OMNodeList<T>(ot.getChildNodes());
421 	}
422 
423     /**
424      * The first child of this node. If there is no such node, this returns 
425      * <code>null</code>.
426      * @return The first child of this node.
427      */
428 	public final OMNode getFirstChild() {
429 		Node firstChild = ot.getFirstChild();
430 		return (firstChild != null) ? convert(firstChild) : null;
431 	}
432 
433     /**
434      * The last child of this node. If there is no such node, this returns 
435      * <code>null</code>.
436      * @return The last child of this node. 
437      */
438 	public final OMNode getLastChild() {
439 		Node lastChild = ot.getLastChild();
440 		return (lastChild != null) ? convert(lastChild) : null;
441 	}
442 	
443 	/**
444      * Returns the local part of the qualified name of this node.
445      * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and 
446      * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 
447      * method, such as <code>Document.createElement()</code>, this is always 
448      * <code>null</code>.
449      * @return The local part of the qualified name of this node
450      */
451 	public final String getLocalName() {
452 		return DOMHelper.getLocalName(ot);
453 	}
454 
455     /**
456      * The node immediately preceding this node. If there is no such node, 
457      * this returns <code>null</code>.
458      * @return The node immediately preceding this node.
459      */
460 	public final OMNode getPreviousSibling() {
461 		Node previousSibling = ot.getPreviousSibling();
462 		return (previousSibling != null) ? convert(previousSibling) : null;
463 	}
464 
465 	/**
466      * The namespace URI of the specified node, or <code>null</code> if it is 
467      * unspecified (see ).
468      * <br>This is not a computed value that is the result of a namespace 
469      * lookup based on an examination of the namespace declarations in 
470      * scope. It is merely the namespace URI given at creation time.
471      * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and 
472      * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 
473      * method, such as <code>Document.createElement()</code>, this is always 
474      * <code>null</code>.
475      * <p ><b>Note:</b> Per the <em>Namespaces in XML</em> Specification [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
476      *  an attribute does not inherit its namespace from the element it is 
477      * attached to. If an attribute is not explicitly given a namespace, it 
478      * simply has no namespace.
479      * @return The namespace URI of this node
480      */
481 	public String getNamespaceURI() {
482 		return DOMHelper.getNamespaceURI(ot);
483 	}
484     /**
485      * The node immediately following this node. If there is no such node, 
486      * this returns <code>null</code>.
487      * @return The node immediately following this node.
488      */
489 	public final OMNode getNextSibling() {
490 		Node nextSibling = ot.getNextSibling();
491 		return (nextSibling != null) ? convert(nextSibling) : null;
492 	}
493 
494     /**
495      * The <code>OMDocument</code> object associated with this node. This is 
496      * also the <code>OMDocument</code> object used to create new nodes. When 
497      * this node is a <code>OMNode</code> 
498      * which is not used with any <code>OMDocument</code> yet, this is 
499      * <code>null</code>.
500      * @return The <code>OMDocument</code> object associated with this node.
501      */
502 	public final OMDocument getOwnerDocument() {
503 		Document document = ot.getOwnerDocument();
504 		return (document != null) ? (OMDocument)convert(document) : null;
505 	}
506 
507     /**
508      * Inserts the node <code>newChild</code> before the existing child node 
509      * <code>refChild</code>. If <code>refChild</code> is <code>null</code>, 
510      * insert <code>newChild</code> at the end of the list of children.
511      * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object, 
512      * all of its children are inserted, in the same order, before 
513      * <code>refChild</code>. If the <code>newChild</code> is already in the 
514      * tree, it is first removed.
515      * <p ><b>Note:</b>  Inserting a node before itself is implementation 
516      * dependent. 
517      * @param newChild The node to insert.
518      * @param refChild The reference node, i.e., the node before which the 
519      *   new node must be inserted.
520      * @return The node being inserted.
521      * @exception DOMException
522      *   HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not 
523      *   allow children of the type of the <code>newChild</code> node, or if 
524      *   the node to insert is one of this node's ancestors or this node 
525      *   itself, or if this node is of type <code>Document</code> and the 
526      *   DOM application attempts to insert a second 
527      *   <code>DocumentType</code> or <code>Element</code> node.
528      *   <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created 
529      *   from a different document than the one that created this node.
530      *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or 
531      *   if the parent of the node being inserted is readonly.
532      *   <br>NOT_FOUND_ERR: Raised if <code>refChild</code> is not a child of 
533      *   this node.
534      *   <br>NOT_SUPPORTED_ERR: if this node is of type <code>Document</code>, 
535      *   this exception might be raised if the DOM implementation doesn't 
536      *   support the insertion of a <code>DocumentType</code> or 
537      *   <code>Element</code> node.
538      */
539 	public final OMNode insertBefore(OMNode newChild, OMNode refChild) throws JavaScriptException {
540 		ot.insertBefore(newChild.ot, refChild != null ? refChild.ot : null);
541 		return newChild;
542 	}
543 
544     /**
545      * Replaces the child node <code>oldChild</code> with <code>newChild</code>
546      *  in the list of children, and returns the <code>oldChild</code> node.
547      * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object, 
548      * <code>oldChild</code> is replaced by all of the 
549      * <code>DocumentFragment</code> children, which are inserted in the 
550      * same order. If the <code>newChild</code> is already in the tree, it 
551      * is first removed.
552      * <p ><b>Note:</b>  Replacing a node with itself is implementation 
553      * dependent. 
554      * @param newChild The new node to put in the child list.
555      * @param oldChild The node being replaced in the list.
556      * @return The node replaced.
557      * @exception DOMException
558      *   HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not 
559      *   allow children of the type of the <code>newChild</code> node, or if 
560      *   the node to put in is one of this node's ancestors or this node 
561      *   itself, or if this node is of type <code>Document</code> and the 
562      *   result of the replacement operation would add a second 
563      *   <code>DocumentType</code> or <code>Element</code> on the 
564      *   <code>Document</code> node.
565      *   <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created 
566      *   from a different document than the one that created this node.
567      *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node or the parent of 
568      *   the new node is readonly.
569      *   <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of 
570      *   this node.
571      *   <br>NOT_SUPPORTED_ERR: if this node is of type <code>Document</code>, 
572      *   this exception might be raised if the DOM implementation doesn't 
573      *   support the replacement of the <code>DocumentType</code> child or 
574      *   <code>Element</code> child.
575      */
576 	public final OMNode replaceChild(OMNode newChild, OMNode oldChild) throws JavaScriptException {
577 		ot.replaceChild(newChild.ot, oldChild.ot);
578 		return oldChild;
579 	}
580 
581 	  /**
582      * Removes the child node indicated by <code>oldChild</code> from the list 
583      * of children, and returns it.
584      * @param oldChild The node being removed.
585      * @return The node removed.
586      * @exception DOMException
587      *   NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
588      *   <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of 
589      *   this node.
590      *   <br>NOT_SUPPORTED_ERR: if this node is of type <code>Document</code>, 
591      *   this exception might be raised if the DOM implementation doesn't 
592      *   support the removal of the <code>DocumentType</code> child or the 
593      *   <code>Element</code> child.
594      */
595 	public final OMNode removeChild(OMNode oldChild) throws JavaScriptException {
596 		ot.removeChild(oldChild.ot);
597 		return oldChild;
598 	}
599 
600     /**
601      * Adds the node <code>newChild</code> to the end of the list of children 
602      * of this node. If the <code>newChild</code> is already in the tree, it 
603      * is first removed.
604      * @param newChild The node to add.If it is a 
605      *   <code>DocumentFragment</code> object, the entire contents of the 
606      *   document fragment are moved into the child list of this node
607      * @return The node added.
608      * @exception DOMException
609      *   HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not 
610      *   allow children of the type of the <code>newChild</code> node, or if 
611      *   the node to append is one of this node's ancestors or this node 
612      *   itself, or if this node is of type <code>Document</code> and the 
613      *   DOM application attempts to append a second 
614      *   <code>DocumentType</code> or <code>Element</code> node.
615      *   <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created 
616      *   from a different document than the one that created this node.
617      *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or 
618      *   if the previous parent of the node being inserted is readonly.
619      *   <br>NOT_SUPPORTED_ERR: if the <code>newChild</code> node is a child 
620      *   of the <code>Document</code> node, this exception might be raised 
621      *   if the DOM implementation doesn't support the removal of the 
622      *   <code>DocumentType</code> child or <code>Element</code> child.
623      */
624 	public final OMNode appendChild(OMNode newChild) throws JavaScriptException {
625 		ot.appendChild(newChild.ot);
626 		return newChild;
627 	}
628 
629     /**
630      * Returns whether this node has any children.
631      * @return Returns <code>true</code> if this node has any children, 
632      *   <code>false</code> otherwise.
633      */
634 	public final boolean hasChildNodes() {
635 		return ot.hasChildNodes();
636 	}
637 
638     /**
639      * Returns a duplicate of this node, i.e., serves as a generic copy 
640      * constructor for nodes. The duplicate node has no parent (
641      * <code>parentNode</code> is <code>null</code>) and no user data. User 
642      * data associated to the imported node is not carried over. However, if 
643      * any <code>UserDataHandlers</code> has been specified along with the 
644      * associated data these handlers will be called with the appropriate 
645      * parameters before this method returns.
646      * <br>Cloning an <code>Element</code> copies all attributes and their 
647      * values, including those generated by the XML processor to represent 
648      * defaulted attributes, but this method does not copy any children it 
649      * contains unless it is a deep clone. This includes text contained in 
650      * an the <code>Element</code> since the text is contained in a child 
651      * <code>Text</code> node. Cloning an <code>Attr</code> directly, as 
652      * opposed to be cloned as part of an <code>Element</code> cloning 
653      * operation, returns a specified attribute (<code>specified</code> is 
654      * <code>true</code>). Cloning an <code>Attr</code> always clones its 
655      * children, since they represent its value, no matter whether this is a 
656      * deep clone or not. Cloning an <code>EntityReference</code> 
657      * automatically constructs its subtree if a corresponding 
658      * <code>Entity</code> is available, no matter whether this is a deep 
659      * clone or not. Cloning any other type of node simply returns a copy of 
660      * this node.
661      * <br>Note that cloning an immutable subtree results in a mutable copy, 
662      * but the children of an <code>EntityReference</code> clone are readonly
663      * . In addition, clones of unspecified <code>Attr</code> nodes are 
664      * specified. And, cloning <code>Document</code>, 
665      * <code>DocumentType</code>, <code>Entity</code>, and 
666      * <code>Notation</code> nodes is implementation dependent.
667      * @param deep If <code>true</code>, recursively clone the subtree under 
668      *   the specified node; if <code>false</code>, clone only the node 
669      *   itself (and its attributes, if it is an <code>Element</code>).
670      * @return The duplicate node.
671      */
672 	public final OMNode cloneNode(boolean deep) {
673 		return convert(ot.cloneNode(deep));
674 	}
675 
676     /**
677      *  Puts all <code>Text</code> nodes in the full depth of the sub-tree 
678      * underneath this <code>Node</code>, including attribute nodes, into a 
679      * "normal" form where only structure (e.g., elements, comments, 
680      * processing instructions, CDATA sections, and entity references) 
681      * separates <code>Text</code> nodes, i.e., there are neither adjacent 
682      * <code>Text</code> nodes nor empty <code>Text</code> nodes. This can 
683      * be used to ensure that the DOM view of a document is the same as if 
684      * it were saved and re-loaded, and is useful when operations (such as 
685      * XPointer [<a href='http://www.w3.org/TR/2003/REC-xptr-framework-20030325/'>XPointer</a>]
686      *  lookups) that depend on a particular document tree structure are to 
687      * be used. If the parameter "normalize-characters" of the 
688      * <code>DOMConfiguration</code> object attached to the 
689      * <code>Node.ownerDocument</code> is <code>true</code>, this method 
690      * will also fully normalize the characters of the <code>Text</code> 
691      * nodes. 
692      * <p ><b>Note:</b> In cases where the document contains 
693      * <code>CDATASections</code>, the normalize operation alone may not be 
694      * sufficient, since XPointers do not differentiate between 
695      * <code>Text</code> nodes and <code>CDATASection</code> nodes.
696      */
697 	public final void normalize() {
698 		DOMHelper.normalize(ot);
699 	}
700 	
701 	@Override
702 	public String toString() {
703 		return ot.toString();
704 	}
705 }