1 | using System;
|
---|
2 | using System.Xml;
|
---|
3 | using System.Timers;
|
---|
4 | using System.Collections.Generic;
|
---|
5 |
|
---|
6 | namespace SharpVectors.Dom.Svg
|
---|
7 | {
|
---|
8 | /// <summary>
|
---|
9 | /// A key interface definition is the SVGSVGElement interface, which is the interface that corresponds to the 'svg' element. This interface contains various miscellaneous commonly-used utility methods, such as matrix operations and the ability to control the time of redraw on visual rendering devices.
|
---|
10 | /// SVGSVGElement extends ViewCSS and DocumentCSS to provide access to the computed values of properties and the override style sheet as described in DOM2.
|
---|
11 | /// </summary>
|
---|
12 | public sealed class SvgSvgElement : SvgTransformableElement, ISvgSvgElement
|
---|
13 | {
|
---|
14 | #region Private Fields
|
---|
15 |
|
---|
16 | private SvgTests svgTests;
|
---|
17 | private ISvgAnimatedLength x;
|
---|
18 | private ISvgAnimatedLength height;
|
---|
19 |
|
---|
20 | #endregion
|
---|
21 |
|
---|
22 | #region Constructors
|
---|
23 |
|
---|
24 | internal SvgSvgElement(string prefix, string localname, string ns, SvgDocument doc)
|
---|
25 | : base(prefix, localname, ns, doc)
|
---|
26 | {
|
---|
27 | svgExternalResourcesRequired = new SvgExternalResourcesRequired(this);
|
---|
28 | svgFitToViewBox = new SvgFitToViewBox(this);
|
---|
29 | svgTests = new SvgTests(this);
|
---|
30 | currentTranslate = new SvgPoint(0, 0);
|
---|
31 | }
|
---|
32 |
|
---|
33 | #endregion
|
---|
34 |
|
---|
35 | #region Public Properties
|
---|
36 |
|
---|
37 | public bool IsOuterMost
|
---|
38 | {
|
---|
39 | get
|
---|
40 | {
|
---|
41 | return (this.ParentNode is SvgDocument);
|
---|
42 | }
|
---|
43 | }
|
---|
44 |
|
---|
45 | #endregion
|
---|
46 |
|
---|
47 | #region Public Methods
|
---|
48 |
|
---|
49 | public void Resize()
|
---|
50 | {
|
---|
51 | // TODO: Invalidate! Fire SVGResize
|
---|
52 | x = null;
|
---|
53 | y = null;
|
---|
54 | width = null;
|
---|
55 | height = null;
|
---|
56 | currentView = null;
|
---|
57 | cachedViewBoxTransform = null;
|
---|
58 | viewport = null;
|
---|
59 | svgFitToViewBox = null;
|
---|
60 | svgFitToViewBox = new SvgFitToViewBox(this);
|
---|
61 | if (this == OwnerDocument.RootElement)
|
---|
62 | {
|
---|
63 | // TODO
|
---|
64 | }
|
---|
65 | else
|
---|
66 | {
|
---|
67 | (OwnerDocument.RootElement as SvgSvgElement).Resize();
|
---|
68 | }
|
---|
69 | }
|
---|
70 |
|
---|
71 | #endregion
|
---|
72 |
|
---|
73 | #region ISvgElement Members
|
---|
74 |
|
---|
75 | /// <summary>
|
---|
76 | /// Gets a value providing a hint on the rendering defined by this element.
|
---|
77 | /// </summary>
|
---|
78 | /// <value>
|
---|
79 | /// An enumeration of the <see cref="SvgRenderingHint"/> specifying the rendering hint.
|
---|
80 | /// This will always return <see cref="SvgRenderingHint.Containment"/>
|
---|
81 | /// </value>
|
---|
82 | public override SvgRenderingHint RenderingHint
|
---|
83 | {
|
---|
84 | get
|
---|
85 | {
|
---|
86 | return SvgRenderingHint.Containment;
|
---|
87 | }
|
---|
88 | }
|
---|
89 |
|
---|
90 | #endregion
|
---|
91 |
|
---|
92 | #region ISvgZoomAndPan Members
|
---|
93 |
|
---|
94 | public SvgZoomAndPanType ZoomAndPan
|
---|
95 | {
|
---|
96 | get
|
---|
97 | {
|
---|
98 | return CurrentView.ZoomAndPan;
|
---|
99 | }
|
---|
100 | set
|
---|
101 | {
|
---|
102 | }
|
---|
103 | }
|
---|
104 |
|
---|
105 | #endregion
|
---|
106 |
|
---|
107 | #region ISvgSvgElement Members
|
---|
108 |
|
---|
109 | /// <summary>
|
---|
110 | /// Corresponds to attribute x on the given 'svg' element.
|
---|
111 | /// </summary>
|
---|
112 | public ISvgAnimatedLength X
|
---|
113 | {
|
---|
114 | get
|
---|
115 | {
|
---|
116 | if (x == null)
|
---|
117 | {
|
---|
118 | x = new SvgAnimatedLength(this, "x", SvgLengthDirection.Horizontal, "0px");
|
---|
119 | }
|
---|
120 | return x;
|
---|
121 | }
|
---|
122 | }
|
---|
123 |
|
---|
124 | private ISvgAnimatedLength y;
|
---|
125 | /// <summary>
|
---|
126 | /// Corresponds to attribute y on the given 'svg' element.
|
---|
127 | /// </summary>
|
---|
128 | public ISvgAnimatedLength Y
|
---|
129 | {
|
---|
130 | get
|
---|
131 | {
|
---|
132 | if (y == null)
|
---|
133 | {
|
---|
134 | y = new SvgAnimatedLength(this, "y", SvgLengthDirection.Vertical, "0px");
|
---|
135 | }
|
---|
136 | return y;
|
---|
137 | }
|
---|
138 | }
|
---|
139 |
|
---|
140 | private string widthAsString
|
---|
141 | {
|
---|
142 | get
|
---|
143 | {
|
---|
144 | SvgWindow ownerWindow = (SvgWindow)((SvgDocument)OwnerDocument).Window;
|
---|
145 | if (ownerWindow.ParentWindow == null)
|
---|
146 | {
|
---|
147 | return GetAttribute("width").Trim();
|
---|
148 | }
|
---|
149 | else
|
---|
150 | {
|
---|
151 | return String.Empty;
|
---|
152 | }
|
---|
153 | }
|
---|
154 | }
|
---|
155 |
|
---|
156 | private ISvgAnimatedLength width;
|
---|
157 | /// <summary>
|
---|
158 | /// Corresponds to attribute width on the given 'svg' element.
|
---|
159 | /// </summary>
|
---|
160 | public ISvgAnimatedLength Width
|
---|
161 | {
|
---|
162 | get
|
---|
163 | {
|
---|
164 | if (width == null)
|
---|
165 | {
|
---|
166 | width = new SvgAnimatedLength(this, "width", SvgLengthDirection.Horizontal, widthAsString, "100%");
|
---|
167 | }
|
---|
168 | return width;
|
---|
169 | }
|
---|
170 | }
|
---|
171 |
|
---|
172 | private string heightAsString
|
---|
173 | {
|
---|
174 | get
|
---|
175 | {
|
---|
176 | SvgWindow ownerWindow = (SvgWindow)((SvgDocument)OwnerDocument).Window;
|
---|
177 | if (ownerWindow.ParentWindow == null)
|
---|
178 | {
|
---|
179 | return GetAttribute("height").Trim();
|
---|
180 | }
|
---|
181 | else
|
---|
182 | {
|
---|
183 | return "";
|
---|
184 | }
|
---|
185 | }
|
---|
186 | }
|
---|
187 |
|
---|
188 | /// <summary>
|
---|
189 | /// Corresponds to attribute height on the given 'svg' element.
|
---|
190 | /// </summary>
|
---|
191 | public ISvgAnimatedLength Height
|
---|
192 | {
|
---|
193 | get
|
---|
194 | {
|
---|
195 | if (height == null)
|
---|
196 | {
|
---|
197 | height = new SvgAnimatedLength(this, "height", SvgLengthDirection.Vertical, heightAsString, "100%");
|
---|
198 | }
|
---|
199 | return height;
|
---|
200 | }
|
---|
201 | }
|
---|
202 |
|
---|
203 | /// <summary>
|
---|
204 | /// Corresponds to attribute contentScriptType on the given 'svg' element
|
---|
205 | /// </summary>
|
---|
206 | /// <exception cref="DomException">NO_MODIFICATION_ALLOWED_ERR: Raised on an attempt to change the value of a readonly attribute.</exception>
|
---|
207 | public string ContentScriptType
|
---|
208 | {
|
---|
209 | get
|
---|
210 | {
|
---|
211 | return GetAttribute("contentScriptType");
|
---|
212 | }
|
---|
213 | set
|
---|
214 | {
|
---|
215 | SetAttribute("contentScriptType", value);
|
---|
216 | }
|
---|
217 | }
|
---|
218 |
|
---|
219 | /// <summary>
|
---|
220 | /// Corresponds to attribute contentStyleType on the given 'svg' element.
|
---|
221 | /// </summary>
|
---|
222 | /// <exception cref="DomException">NO_MODIFICATION_ALLOWED_ERR: Raised on an attempt to change the value of a readonly attribute.</exception>
|
---|
223 | public string ContentStyleType
|
---|
224 | {
|
---|
225 | get
|
---|
226 | {
|
---|
227 | return GetAttribute("contentStyleType");
|
---|
228 | }
|
---|
229 | set
|
---|
230 | {
|
---|
231 | SetAttribute("contentStyleType", value);
|
---|
232 | }
|
---|
233 | }
|
---|
234 |
|
---|
235 |
|
---|
236 | private double getViewportProp(string propertyName, string inValue, double calcParentVP,
|
---|
237 | double defaultValue, SvgLengthDirection dir)
|
---|
238 | {
|
---|
239 | double ret;
|
---|
240 | inValue = inValue.Trim();
|
---|
241 |
|
---|
242 | if (inValue.Length > 0)
|
---|
243 | {
|
---|
244 | if (inValue.EndsWith("%"))
|
---|
245 | {
|
---|
246 | double perc = SvgNumber.ParseNumber(inValue.Substring(0, inValue.Length - 1)) / 100;
|
---|
247 | ret = calcParentVP * perc;
|
---|
248 | }
|
---|
249 | else
|
---|
250 | {
|
---|
251 | ret = new SvgLength(this, propertyName, dir, inValue, String.Empty).Value;
|
---|
252 | }
|
---|
253 | }
|
---|
254 | else ret = defaultValue;
|
---|
255 |
|
---|
256 | return ret;
|
---|
257 | }
|
---|
258 |
|
---|
259 | private ISvgRect viewport;
|
---|
260 | /// <summary>
|
---|
261 | /// The position and size of the viewport (implicit or explicit) that corresponds to this 'svg' element. When the user agent is actually rendering the content, then the position and size values represent the actual values when rendering. The position and size values are unitless values in the coordinate system of the parent element. If no parent element exists (i.e., 'svg' element represents the root of the document tree), if this SVG document is embedded as part of another document (e.g., via the HTML 'object' element), then the position and size are unitless values in the coordinate system of the parent document. (If the parent uses CSS or XSL layout, then unitless values represent pixel units for the current CSS or XSL viewport, as described in the CSS2 specification.) If the parent element does not have a coordinate system, then the user agent should provide reasonable default values for this attribute.
|
---|
262 | /// The object itself and its contents are both readonly.
|
---|
263 | /// </summary>
|
---|
264 | public ISvgRect Viewport
|
---|
265 | {
|
---|
266 | get
|
---|
267 | {
|
---|
268 | if (viewport == null)
|
---|
269 | {
|
---|
270 | double calcParentVPWidth = (ViewportElement == null) ?
|
---|
271 | OwnerDocument.Window.InnerWidth : ((ISvgFitToViewBox)ViewportElement).ViewBox.AnimVal.Width;
|
---|
272 |
|
---|
273 | double calcParentVPHeight = (ViewportElement == null) ?
|
---|
274 | OwnerDocument.Window.InnerHeight : ((ISvgFitToViewBox)ViewportElement).ViewBox.AnimVal.Height;
|
---|
275 |
|
---|
276 | double x = getViewportProp("x", GetAttribute("x"), calcParentVPWidth, 0, SvgLengthDirection.Horizontal);
|
---|
277 | double y = getViewportProp("y", GetAttribute("y"), calcParentVPHeight, 0, SvgLengthDirection.Vertical);
|
---|
278 | double width = getViewportProp("width", widthAsString, calcParentVPWidth, OwnerDocument.Window.InnerWidth, SvgLengthDirection.Horizontal);
|
---|
279 | double height = getViewportProp("height", heightAsString, calcParentVPHeight, OwnerDocument.Window.InnerHeight, SvgLengthDirection.Vertical);
|
---|
280 |
|
---|
281 | viewport = new SvgRect(x, y, width, height);
|
---|
282 | }
|
---|
283 | return viewport;
|
---|
284 | }
|
---|
285 | }
|
---|
286 |
|
---|
287 | /// <summary>
|
---|
288 | /// Size of a pixel units (as defined by CSS2) along the x-axis of the viewport, which represents a unit somewhere in the range of 70dpi to 120dpi, and, on systems that support this, might actually match the characteristics of the target medium. On systems where it is impossible to know the size of a pixel, a suitable default pixel size is provided.
|
---|
289 | /// </summary>
|
---|
290 | public float PixelUnitToMillimeterX
|
---|
291 | {
|
---|
292 | get
|
---|
293 | {
|
---|
294 | throw new NotImplementedException();
|
---|
295 | }
|
---|
296 | set
|
---|
297 | {
|
---|
298 | throw new NotImplementedException();
|
---|
299 | }
|
---|
300 | }
|
---|
301 |
|
---|
302 | /// <summary>
|
---|
303 | /// Corresponding size of a pixel unit along the y-axis of the viewport.
|
---|
304 | /// </summary>
|
---|
305 | public float PixelUnitToMillimeterY
|
---|
306 | {
|
---|
307 | get
|
---|
308 | {
|
---|
309 | throw new NotImplementedException();
|
---|
310 | }
|
---|
311 | set
|
---|
312 | {
|
---|
313 | throw new NotImplementedException();
|
---|
314 | }
|
---|
315 | }
|
---|
316 |
|
---|
317 | /// <summary>
|
---|
318 | /// User interface (UI) events in DOM Level 2 indicate the screen positions at which the given UI event occurred. When the user agent actually knows the physical size of a "screen unit", this attribute will express that information; otherwise, user agents will provide a suitable default value such as .28mm.
|
---|
319 | /// </summary>
|
---|
320 | public float ScreenPixelToMillimeterX
|
---|
321 | {
|
---|
322 | get
|
---|
323 | {
|
---|
324 | throw new NotImplementedException();
|
---|
325 | }
|
---|
326 | set
|
---|
327 | {
|
---|
328 | throw new NotImplementedException();
|
---|
329 | }
|
---|
330 | }
|
---|
331 |
|
---|
332 | /// <summary>
|
---|
333 | /// Corresponding size of a screen pixel along the y-axis of the viewport.
|
---|
334 | /// </summary>
|
---|
335 | public float ScreenPixelToMillimeterY
|
---|
336 | {
|
---|
337 | get
|
---|
338 | {
|
---|
339 | throw new NotImplementedException();
|
---|
340 | }
|
---|
341 | set
|
---|
342 | {
|
---|
343 | throw new NotImplementedException();
|
---|
344 | }
|
---|
345 | }
|
---|
346 |
|
---|
347 | /// <summary>
|
---|
348 | /// The initial view (i.e., before magnification and panning) of the current innermost SVG
|
---|
349 | /// document fragment can be either the "standard" view (i.e., based on attributes on
|
---|
350 | /// the 'svg' element such as fitBoxToViewport) or to a "custom" view (i.e., a hyperlink
|
---|
351 | /// into a particular 'view' or other element - see Linking into SVG content: URI
|
---|
352 | /// fragments and SVG views). If the initial view is the "standard" view, then this
|
---|
353 | /// attribute is false. If the initial view is a "custom" view, then this attribute is
|
---|
354 | /// true.
|
---|
355 | /// </summary>
|
---|
356 | /// <exception cref="DomException">NO_MODIFICATION_ALLOWED_ERR: Raised on an attempt to change the value of a readonly attribute.</exception>
|
---|
357 | public bool UseCurrentView
|
---|
358 | {
|
---|
359 | get
|
---|
360 | {
|
---|
361 | throw new NotImplementedException();
|
---|
362 | }
|
---|
363 | set
|
---|
364 | {
|
---|
365 | throw new NotImplementedException();
|
---|
366 | }
|
---|
367 | }
|
---|
368 |
|
---|
369 | /// <summary>
|
---|
370 | /// The definition of the initial view (i.e., before magnification and panning) of the current innermost SVG document fragment. The meaning depends on the situation:
|
---|
371 | /// * If the initial view was a "standard" view, then:
|
---|
372 | /// o the values for viewBox, preserveAspectRatio and zoomAndPan within currentView will match the values for the corresponding DOM attributes that are on SVGSVGElement directly
|
---|
373 | /// o the values for transform and viewTarget within currentView will be null
|
---|
374 | /// * If the initial view was a link into a 'view' element, then:
|
---|
375 | /// o the values for viewBox, preserveAspectRatio and zoomAndPan within currentView will correspond to the corresponding attributes for the given 'view' element
|
---|
376 | /// o the values for transform and viewTarget within currentView will be null
|
---|
377 | /// * If the initial view was a link into another element (i.e., other than a 'view'), then:
|
---|
378 | /// o the values for viewBox, preserveAspectRatio and zoomAndPan within currentView will match the values for the corresponding DOM attributes that are on SVGSVGElement directly for the closest ancestor 'svg' element
|
---|
379 | /// o the values for transform within currentView will be null
|
---|
380 | /// o the viewTarget within currentView will represent the target of the link
|
---|
381 | /// * If the initial view was a link into the SVG document fragment using an SVG view specification fragment identifier (i.e., #svgView(...)), then:
|
---|
382 | /// o the values for viewBox, preserveAspectRatio, zoomAndPan, transform and viewTarget within currentView will correspond to the values from the SVG view specification fragment identifier
|
---|
383 | /// The object itself and its contents are both readonly.
|
---|
384 | /// </summary>
|
---|
385 | private ISvgViewSpec currentView = null;
|
---|
386 | public ISvgViewSpec CurrentView
|
---|
387 | {
|
---|
388 | get
|
---|
389 | {
|
---|
390 | if (currentView == null)
|
---|
391 | currentView = new SvgViewSpec(this) as ISvgViewSpec;
|
---|
392 | // For now, we only return the "standard" view.
|
---|
393 | return currentView;
|
---|
394 | }
|
---|
395 | }
|
---|
396 |
|
---|
397 | private float currentScale = 1;
|
---|
398 | /// <summary>
|
---|
399 | /// This attribute indicates the current scale factor relative to the initial view to take into account user magnification and panning operations, as described under Magnification and panning. DOM attributes currentScale and currentTranslate are equivalent to the 2x3 matrix [a b c d e f] = [currentScale 0 0 currentScale currentTranslate.x currentTranslate.y]. If "magnification" is enabled (i.e., zoomAndPan="magnify"), then the effect is as if an extra transformation were placed at the outermost level on the SVG document fragment (i.e., outside the outermost 'svg' element).
|
---|
400 | /// </summary>
|
---|
401 | /// <exception cref="DomException">NO_MODIFICATION_ALLOWED_ERR: Raised on an attempt to change the value of a readonly attribute</exception>
|
---|
402 | public float CurrentScale
|
---|
403 | {
|
---|
404 | get
|
---|
405 | {
|
---|
406 | if (this == OwnerDocument.RootElement)
|
---|
407 | return currentScale;
|
---|
408 | else
|
---|
409 | return OwnerDocument.RootElement.CurrentScale;
|
---|
410 | }
|
---|
411 | set
|
---|
412 | {
|
---|
413 | if (this == OwnerDocument.RootElement)
|
---|
414 | {
|
---|
415 | // TODO: Invalidate! Fire OnZoom
|
---|
416 | currentView = null;
|
---|
417 | currentScale = value;
|
---|
418 | cachedViewBoxTransform = null;
|
---|
419 | viewport = null;
|
---|
420 | width = null;
|
---|
421 | height = null;
|
---|
422 | x = null;
|
---|
423 | y = null;
|
---|
424 | svgFitToViewBox = new SvgFitToViewBox(this);
|
---|
425 | }
|
---|
426 | else
|
---|
427 | OwnerDocument.RootElement.CurrentScale = value;
|
---|
428 | }
|
---|
429 | }
|
---|
430 |
|
---|
431 |
|
---|
432 | private ISvgMatrix cachedViewBoxTransform = null;
|
---|
433 | /// <summary>
|
---|
434 | /// This function is super useful, calculates out the transformation matrix
|
---|
435 | /// (i.e., scale and translate) of the viewport to user space.
|
---|
436 | /// </summary>
|
---|
437 | /// <returns>A Matrix which has the translate and scale portions set.</returns>
|
---|
438 | public ISvgMatrix ViewBoxTransform
|
---|
439 | {
|
---|
440 | // TODO: This needs to be cached... need to handle changes to
|
---|
441 | // parent width or height or viewbox changes (in the case of percents)
|
---|
442 | // x,y,width,height,viewBox,preserveAspectRatio changes
|
---|
443 | get
|
---|
444 | {
|
---|
445 | if (cachedViewBoxTransform == null)
|
---|
446 | {
|
---|
447 | ISvgMatrix matrix = CreateSvgMatrix();
|
---|
448 |
|
---|
449 | SvgDocument doc = (SvgDocument)OwnerDocument;
|
---|
450 | double x = 0;
|
---|
451 | double y = 0;
|
---|
452 | double w = 0;
|
---|
453 | double h = 0;
|
---|
454 |
|
---|
455 | double attrWidth = Width.AnimVal.Value;
|
---|
456 | double attrHeight = Height.AnimVal.Value;
|
---|
457 | if (this != doc.RootElement)
|
---|
458 | {
|
---|
459 | // X and Y on the root <svg> have no meaning
|
---|
460 | matrix = matrix.Translate(X.AnimVal.Value, Y.AnimVal.Value);
|
---|
461 | }
|
---|
462 |
|
---|
463 | // Apply the viewBox viewport
|
---|
464 | if (HasAttribute("viewBox"))
|
---|
465 | {
|
---|
466 | ISvgRect r = CurrentView.ViewBox.AnimVal;
|
---|
467 | x += -r.X;
|
---|
468 | y += -r.Y;
|
---|
469 | w = r.Width;
|
---|
470 | h = r.Height;
|
---|
471 | if (w < 0 || h < 0)
|
---|
472 | throw new SvgException(SvgExceptionType.SvgInvalidValueErr, "Negative values are not permitted for viewbox width or height");
|
---|
473 | }
|
---|
474 | else
|
---|
475 | {
|
---|
476 | // This will result in a 1/1 scale.
|
---|
477 | w = attrWidth;
|
---|
478 | h = attrHeight;
|
---|
479 | }
|
---|
480 |
|
---|
481 | double x_ratio = attrWidth / w;
|
---|
482 | double y_ratio = attrHeight / h;
|
---|
483 |
|
---|
484 | ISvgPreserveAspectRatio par = CurrentView.PreserveAspectRatio.AnimVal;
|
---|
485 | if (par.Align == SvgPreserveAspectRatioType.None)
|
---|
486 | {
|
---|
487 | matrix = matrix.ScaleNonUniform(x_ratio, y_ratio);
|
---|
488 | }
|
---|
489 | else
|
---|
490 | {
|
---|
491 |
|
---|
492 | // uniform scaling
|
---|
493 | if (par.MeetOrSlice == SvgMeetOrSlice.Meet)
|
---|
494 | x_ratio = Math.Min(x_ratio, y_ratio);
|
---|
495 | else
|
---|
496 | x_ratio = Math.Max(x_ratio, y_ratio);
|
---|
497 |
|
---|
498 | double x_trans = 0;
|
---|
499 | double x_diff = attrWidth - (x_ratio * w);
|
---|
500 | double y_trans = 0;
|
---|
501 | double y_diff = attrHeight - (x_ratio * h);
|
---|
502 |
|
---|
503 | if (par.Align == SvgPreserveAspectRatioType.XMidYMax ||
|
---|
504 | par.Align == SvgPreserveAspectRatioType.XMidYMid ||
|
---|
505 | par.Align == SvgPreserveAspectRatioType.XMidYMin)
|
---|
506 | {
|
---|
507 | // align to the Middle X
|
---|
508 | x_trans = x_diff / 2;
|
---|
509 | }
|
---|
510 | else if (par.Align == SvgPreserveAspectRatioType.XMaxYMax ||
|
---|
511 | par.Align == SvgPreserveAspectRatioType.XMaxYMid ||
|
---|
512 | par.Align == SvgPreserveAspectRatioType.XMaxYMin)
|
---|
513 | {
|
---|
514 | // align to the right X
|
---|
515 | x_trans = x_diff;
|
---|
516 | }
|
---|
517 |
|
---|
518 | if (par.Align == SvgPreserveAspectRatioType.XMaxYMid ||
|
---|
519 | par.Align == SvgPreserveAspectRatioType.XMidYMid ||
|
---|
520 | par.Align == SvgPreserveAspectRatioType.XMinYMid)
|
---|
521 | {
|
---|
522 | // align to the middle Y
|
---|
523 | y_trans = y_diff / 2;
|
---|
524 | }
|
---|
525 | else if (par.Align == SvgPreserveAspectRatioType.XMaxYMax ||
|
---|
526 | par.Align == SvgPreserveAspectRatioType.XMidYMax ||
|
---|
527 | par.Align == SvgPreserveAspectRatioType.XMinYMax)
|
---|
528 | {
|
---|
529 | // align to the bottom Y
|
---|
530 | y_trans = y_diff;
|
---|
531 | }
|
---|
532 |
|
---|
533 | matrix = matrix.Translate(x_trans, y_trans);
|
---|
534 | matrix = matrix.Scale(x_ratio);
|
---|
535 | }
|
---|
536 | // Translate for min-x and min-y
|
---|
537 | matrix = matrix.Translate(x, y);
|
---|
538 |
|
---|
539 | // Handle currentSranslate and currentScale
|
---|
540 | if (this == OwnerDocument.RootElement)
|
---|
541 | {
|
---|
542 | matrix = matrix.Translate(this.currentTranslate.X, this.currentTranslate.Y);
|
---|
543 | matrix = matrix.Scale(this.currentScale);
|
---|
544 | }
|
---|
545 |
|
---|
546 | // Set the cache
|
---|
547 | cachedViewBoxTransform = matrix;
|
---|
548 | }
|
---|
549 | return cachedViewBoxTransform;
|
---|
550 | }
|
---|
551 | }
|
---|
552 |
|
---|
553 |
|
---|
554 | private ISvgPoint currentTranslate;
|
---|
555 | /// <summary>
|
---|
556 | /// The corresponding translation factor that takes into account user "magnification".
|
---|
557 | /// </summary>
|
---|
558 | public ISvgPoint CurrentTranslate
|
---|
559 | {
|
---|
560 | get
|
---|
561 | {
|
---|
562 | if (this == OwnerDocument.RootElement)
|
---|
563 | {
|
---|
564 | if (currentTranslate == null)
|
---|
565 | {
|
---|
566 | currentTranslate = CreateSvgPoint();
|
---|
567 | }
|
---|
568 | return currentTranslate;
|
---|
569 | }
|
---|
570 | else
|
---|
571 | return OwnerDocument.RootElement.CurrentTranslate;
|
---|
572 | }
|
---|
573 | }
|
---|
574 |
|
---|
575 | private List<Timer> redrawTimers = new List<Timer>();
|
---|
576 |
|
---|
577 | public void RedrawTimerElapsed(object source, ElapsedEventArgs args)
|
---|
578 | {
|
---|
579 | UnsuspendRedraw(((Timer)source).GetHashCode());
|
---|
580 | }
|
---|
581 |
|
---|
582 | /// <summary>
|
---|
583 | /// Takes a time-out value which indicates that redraw shall not occur until: (a) the
|
---|
584 | /// corresponding unsuspendRedraw(suspend_handle_id) call has been made, (b) an
|
---|
585 | /// unsuspendRedrawAll() call has been made, or (c) its timer has timed out. In
|
---|
586 | /// environments that do not support interactivity (e.g., print media), then redraw shall
|
---|
587 | /// not be suspended. suspend_handle_id = suspendRedraw(max_wait_milliseconds) and
|
---|
588 | /// unsuspendRedraw(suspend_handle_id) must be packaged as balanced pairs. When you
|
---|
589 | /// want to suspend redraw actions as a collection of SVG DOM changes occur, then
|
---|
590 | /// precede the changes to the SVG DOM with a method call similar to
|
---|
591 | /// suspend_handle_id = suspendRedraw(max_wait_milliseconds) and follow the changes with
|
---|
592 | /// a method call similar to unsuspendRedraw(suspend_handle_id). Note that multiple
|
---|
593 | /// suspendRedraw calls can be used at once and that each such method call is treated
|
---|
594 | /// independently of the other suspendRedraw method calls.
|
---|
595 | /// </summary>
|
---|
596 | /// <param name="max_wait_milliseconds">The amount of time in milliseconds to hold off
|
---|
597 | /// before redrawing the device. Values greater than 60 seconds will be truncated
|
---|
598 | /// down to 60 seconds.</param>
|
---|
599 | /// <returns>A number which acts as a unique identifier for the given suspendRedraw() call. This value must be passed as the parameter to the corresponding unsuspendRedraw() method call.</returns>
|
---|
600 | public int SuspendRedraw(int maxWaitMilliseconds)
|
---|
601 | {
|
---|
602 | if (maxWaitMilliseconds > 60000)
|
---|
603 | maxWaitMilliseconds = 60000;
|
---|
604 | Timer t = new Timer(maxWaitMilliseconds);
|
---|
605 | t.AutoReset = false;
|
---|
606 | t.Elapsed += new ElapsedEventHandler(this.RedrawTimerElapsed);
|
---|
607 | t.Enabled = true;
|
---|
608 | redrawTimers.Add(t);
|
---|
609 | return t.GetHashCode();
|
---|
610 | }
|
---|
611 |
|
---|
612 | /// <summary>
|
---|
613 | /// Cancels a specified suspendRedraw() by providing a unique suspend_handle_id.
|
---|
614 | /// </summary>
|
---|
615 | /// <param name="suspend_handle_id">A number which acts as a unique identifier for the desired suspendRedraw() call. The number supplied must be a value returned from a previous call to suspendRedraw()</param>
|
---|
616 | /// <exception cref="DomException">This method will raise a DOMException with value NOT_FOUND_ERR if an invalid value (i.e., no such suspend_handle_id is active) for suspend_handle_id is provided.</exception>
|
---|
617 | public void UnsuspendRedraw(int suspendHandleId)
|
---|
618 | {
|
---|
619 | Timer timer = null;
|
---|
620 | foreach (Timer t in redrawTimers)
|
---|
621 | {
|
---|
622 | if (t.GetHashCode() == suspendHandleId)
|
---|
623 | {
|
---|
624 | timer = t;
|
---|
625 | break;
|
---|
626 | }
|
---|
627 | }
|
---|
628 | if (timer == null)
|
---|
629 | throw new DomException(DomExceptionType.NotFoundErr, "Invalid handle submitted to unsuspendRedraw");
|
---|
630 |
|
---|
631 | timer.Enabled = false;
|
---|
632 | redrawTimers.Remove(timer);
|
---|
633 | if (OwnerDocument.Window.Renderer.InvalidRect != SvgRectF.Empty)
|
---|
634 | OwnerDocument.Window.Renderer.Render((ISvgDocument)OwnerDocument);
|
---|
635 |
|
---|
636 | }
|
---|
637 |
|
---|
638 | /// <summary>
|
---|
639 | /// Cancels all currently active suspendRedraw() method calls. This method is most
|
---|
640 | /// useful
|
---|
641 | /// at the very end of a set of SVG DOM calls to ensure that all pending suspendRedraw()
|
---|
642 | /// method calls have been cancelled.
|
---|
643 | /// </summary>
|
---|
644 | public void UnsuspendRedrawAll()
|
---|
645 | {
|
---|
646 | foreach (Timer t in redrawTimers)
|
---|
647 | {
|
---|
648 | t.Enabled = false;
|
---|
649 | }
|
---|
650 | redrawTimers.Clear();
|
---|
651 | if (OwnerDocument.Window.Renderer.InvalidRect != SvgRectF.Empty)
|
---|
652 | OwnerDocument.Window.Renderer.Render((ISvgDocument)OwnerDocument);
|
---|
653 | }
|
---|
654 |
|
---|
655 | /// <summary>
|
---|
656 | /// In rendering environments supporting interactivity, forces the user agent to
|
---|
657 | /// immediately redraw all regions of the viewport that require updating.
|
---|
658 | /// </summary>
|
---|
659 | public void ForceRedraw()
|
---|
660 | {
|
---|
661 | OwnerDocument.Window.Renderer.InvalidRect = SvgRectF.Empty;
|
---|
662 | OwnerDocument.Window.Renderer.Render((ISvgDocument)OwnerDocument);
|
---|
663 | }
|
---|
664 |
|
---|
665 | /// <summary>
|
---|
666 | /// Suspends (i.e., pauses) all currently running animations that are defined within the
|
---|
667 | /// SVG document fragment corresponding to this 'svg' element, causing the animation clock
|
---|
668 | /// corresponding to this document fragment to stand still until it is unpaused.
|
---|
669 | /// </summary>
|
---|
670 | public void PauseAnimations()
|
---|
671 | {
|
---|
672 | throw new NotImplementedException();
|
---|
673 | }
|
---|
674 |
|
---|
675 | /// <summary>
|
---|
676 | /// Unsuspends (i.e., unpauses) currently running animations that are defined within the
|
---|
677 | /// SVG document fragment, causing the animation clock to continue from the time at which
|
---|
678 | /// it was suspended.
|
---|
679 | /// </summary>
|
---|
680 | public void UnpauseAnimations()
|
---|
681 | {
|
---|
682 | throw new NotImplementedException();
|
---|
683 | }
|
---|
684 |
|
---|
685 | /// <summary>
|
---|
686 | /// Returns true if this SVG document fragment is in a paused state
|
---|
687 | /// </summary>
|
---|
688 | /// <returns>Boolean indicating whether this SVG document fragment is in a paused
|
---|
689 | /// state.</returns>
|
---|
690 | public bool AnimationsPaused()
|
---|
691 | {
|
---|
692 | throw new NotImplementedException();
|
---|
693 | }
|
---|
694 |
|
---|
695 |
|
---|
696 | /// <summary>
|
---|
697 | /// The current time in seconds relative to the start time for the current SVG document
|
---|
698 | /// fragment.
|
---|
699 | /// </summary>
|
---|
700 | public float CurrentTime
|
---|
701 | {
|
---|
702 | get
|
---|
703 | {
|
---|
704 | throw new NotImplementedException();
|
---|
705 | }
|
---|
706 | set
|
---|
707 | {
|
---|
708 | throw new NotImplementedException();
|
---|
709 | }
|
---|
710 | }
|
---|
711 |
|
---|
712 | /// <summary>
|
---|
713 | /// Returns the list of graphics elements whose rendered content intersects the supplied
|
---|
714 | /// rectangle, honoring the 'pointer-events' property value on each candidate graphics
|
---|
715 | /// element.
|
---|
716 | /// </summary>
|
---|
717 | /// <param name="rect">The test rectangle. The values are in the initial coordinate
|
---|
718 | /// system for the current 'svg' element.</param>
|
---|
719 | /// <param name="referenceElement">If not null, then only return elements whose drawing
|
---|
720 | /// order has them below the given reference element.</param>
|
---|
721 | /// <returns>A list of Elements whose content intersects the supplied rectangle.</returns>
|
---|
722 | public XmlNodeList GetIntersectionList(ISvgRect rect, ISvgElement referenceElement)
|
---|
723 | {
|
---|
724 | throw new NotImplementedException();
|
---|
725 | }
|
---|
726 |
|
---|
727 | /// <summary>
|
---|
728 | /// Returns the list of graphics elements whose rendered content is entirely contained
|
---|
729 | /// within the supplied rectangle, honoring the 'pointer-events' property value on each
|
---|
730 | /// candidate graphics element.
|
---|
731 | /// </summary>
|
---|
732 | /// <param name="rect">The test rectangle. The values are in the initial coordinate system
|
---|
733 | /// for the current 'svg' element.</param>
|
---|
734 | /// <param name="referenceElement">If not null, then only return elements whose drawing
|
---|
735 | /// order has them below the given reference element.</param>
|
---|
736 | /// <returns>A list of Elements whose content is enclosed by the supplied
|
---|
737 | /// rectangle.</returns>
|
---|
738 | public XmlNodeList GetEnclosureList(ISvgRect rect, ISvgElement referenceElement)
|
---|
739 | {
|
---|
740 | throw new NotImplementedException();
|
---|
741 | }
|
---|
742 |
|
---|
743 | /// <summary>
|
---|
744 | /// Returns true if the rendered content of the given element intersects the supplied
|
---|
745 | /// rectangle, honoring the 'pointer-events' property value on each candidate graphics
|
---|
746 | /// element.
|
---|
747 | /// </summary>
|
---|
748 | /// <param name="element">The element on which to perform the given test.</param>
|
---|
749 | /// <param name="rect">The test rectangle. The values are in the initial coordinate system
|
---|
750 | /// for the current 'svg' element.</param>
|
---|
751 | /// <returns>True or false, depending on whether the given element intersects the supplied
|
---|
752 | /// rectangle.</returns>
|
---|
753 | public bool CheckIntersection(ISvgElement element, ISvgRect rect)
|
---|
754 | {
|
---|
755 | throw new NotImplementedException();
|
---|
756 | }
|
---|
757 |
|
---|
758 | /// <summary>
|
---|
759 | /// Returns true if the rendered content of the given element is entirely contained within
|
---|
760 | /// the supplied rectangle, honoring the 'pointer-events' property value on each candidate
|
---|
761 | /// graphics element.
|
---|
762 | /// </summary>
|
---|
763 | /// <param name="element">The element on which to perform the given test</param>
|
---|
764 | /// <param name="rect">The test rectangle. The values are in the initial coordinate system
|
---|
765 | /// for the current 'svg' element.</param>
|
---|
766 | /// <returns>True or false, depending on whether the given element is enclosed by the
|
---|
767 | /// supplied rectangle.</returns>
|
---|
768 | public bool CheckEnclosure(ISvgElement element, ISvgRect rect)
|
---|
769 | {
|
---|
770 | throw new NotImplementedException();
|
---|
771 | }
|
---|
772 |
|
---|
773 | /// <summary>
|
---|
774 | /// Unselects any selected objects, including any selections of text strings and type-in
|
---|
775 | /// bars.
|
---|
776 | /// </summary>
|
---|
777 | public void DeselectAll()
|
---|
778 | {
|
---|
779 | throw new NotImplementedException();
|
---|
780 | }
|
---|
781 |
|
---|
782 | /// <summary>
|
---|
783 | /// Creates an SVGNumber object outside of any document trees. The object is initialized
|
---|
784 | /// to a value of zero.
|
---|
785 | /// </summary>
|
---|
786 | /// <returns>An SVGNumber object.</returns>
|
---|
787 | public ISvgNumber CreateSvgNumber()
|
---|
788 | {
|
---|
789 | return new SvgNumber(0F);
|
---|
790 | }
|
---|
791 |
|
---|
792 | /// <summary>
|
---|
793 | /// Creates an SVGLength object outside of any document trees. The object is initialized
|
---|
794 | /// to the value of 0 user units.
|
---|
795 | /// </summary>
|
---|
796 | /// <returns>An SVGLength object.</returns>
|
---|
797 | public ISvgLength CreateSvgLength()
|
---|
798 | {
|
---|
799 | return new SvgLength(null, string.Empty, SvgLengthSource.String, SvgLengthDirection.Horizontal, "0");
|
---|
800 | }
|
---|
801 |
|
---|
802 | /// <summary>
|
---|
803 | /// Creates an SVGAngle object outside of any document trees. The object is initialized to
|
---|
804 | /// the value 0 degrees (unitless).
|
---|
805 | /// </summary>
|
---|
806 | /// <returns>An SVGAngle object.</returns>
|
---|
807 | public ISvgAngle CreateSvgAngle()
|
---|
808 | {
|
---|
809 | return new SvgAngle("0", "0", false);
|
---|
810 | }
|
---|
811 |
|
---|
812 | /// <summary>
|
---|
813 | /// Creates an SVGPoint object outside of any document trees. The object is initialized to
|
---|
814 | /// the point (0,0) in the user coordinate system.
|
---|
815 | /// </summary>
|
---|
816 | /// <returns>An SVGPoint object.</returns>
|
---|
817 | public ISvgPoint CreateSvgPoint()
|
---|
818 | {
|
---|
819 | return new SvgPoint(0, 0);
|
---|
820 | }
|
---|
821 |
|
---|
822 | /// <summary>
|
---|
823 | /// Creates an SVGMatrix object outside of any document trees. The object is initialized
|
---|
824 | /// to the identity matrix.
|
---|
825 | /// </summary>
|
---|
826 | /// <returns>An SVGMatrix object.</returns>
|
---|
827 | public ISvgMatrix CreateSvgMatrix()
|
---|
828 | {
|
---|
829 | return new SvgMatrix();
|
---|
830 | }
|
---|
831 |
|
---|
832 | /// <summary>
|
---|
833 | /// Creates an SVGRect object outside of any document trees. The object is initialized
|
---|
834 | /// such that all values are set to 0 user units.
|
---|
835 | /// </summary>
|
---|
836 | /// <returns>An SVGRect object.</returns>
|
---|
837 | public ISvgRect CreateSvgRect()
|
---|
838 | {
|
---|
839 | return new SvgRect(0, 0, 0, 0);
|
---|
840 | }
|
---|
841 |
|
---|
842 | /// <summary>
|
---|
843 | /// Creates an SVGTransform object outside of any document trees. The object is initialized
|
---|
844 | /// to an identity matrix transform (SVG_TRANSFORM_MATRIX).
|
---|
845 | /// </summary>
|
---|
846 | /// <returns>An SVGTransform object.</returns>
|
---|
847 | public ISvgTransform CreateSvgTransform()
|
---|
848 | {
|
---|
849 | return new SvgTransform();
|
---|
850 | }
|
---|
851 |
|
---|
852 | /// <summary>
|
---|
853 | /// Creates an SVGTransform object outside of any document trees. The object is
|
---|
854 | /// initialized to the given matrix transform (i.e., SVG_TRANSFORM_MATRIX).
|
---|
855 | /// </summary>
|
---|
856 | /// <param name="matrix">The transform matrix.</param>
|
---|
857 | /// <returns>An SVGTransform object.</returns>
|
---|
858 | public ISvgTransform CreateSvgTransformFromMatrix(ISvgMatrix matrix)
|
---|
859 | {
|
---|
860 | return new SvgTransform(matrix);
|
---|
861 | }
|
---|
862 |
|
---|
863 | /// <summary>
|
---|
864 | /// Searches this SVG document fragment (i.e., the search is restricted to a subset of the
|
---|
865 | /// document tree) for an Element whose id is given by elementId. If an Element is found,
|
---|
866 | /// that Element is returned. If no such element exists, returns null. Behavior is not
|
---|
867 | /// defined if more than one element has this id.
|
---|
868 | /// </summary>
|
---|
869 | /// <param name="elementId">The unique id value for an element.</param>
|
---|
870 | /// <returns>The matching element.</returns>
|
---|
871 | public XmlElement GetElementById(string elementId)
|
---|
872 | {
|
---|
873 | return this.GetElementById(elementId);
|
---|
874 | }
|
---|
875 |
|
---|
876 | #endregion
|
---|
877 |
|
---|
878 | #region ISvgFitToViewBox Members
|
---|
879 | private SvgFitToViewBox svgFitToViewBox;
|
---|
880 | public ISvgAnimatedRect ViewBox
|
---|
881 | {
|
---|
882 | get
|
---|
883 | {
|
---|
884 | return svgFitToViewBox.ViewBox;
|
---|
885 | }
|
---|
886 | }
|
---|
887 |
|
---|
888 | public ISvgAnimatedPreserveAspectRatio PreserveAspectRatio
|
---|
889 | {
|
---|
890 | get
|
---|
891 | {
|
---|
892 | return svgFitToViewBox.PreserveAspectRatio;
|
---|
893 | }
|
---|
894 | }
|
---|
895 | #endregion
|
---|
896 |
|
---|
897 | #region ISvgExternalResourcesRequired Members
|
---|
898 |
|
---|
899 | private SvgExternalResourcesRequired svgExternalResourcesRequired;
|
---|
900 | public ISvgAnimatedBoolean ExternalResourcesRequired
|
---|
901 | {
|
---|
902 | get
|
---|
903 | {
|
---|
904 | return svgExternalResourcesRequired.ExternalResourcesRequired;
|
---|
905 | }
|
---|
906 | }
|
---|
907 |
|
---|
908 | #endregion
|
---|
909 |
|
---|
910 | #region ISvgTests Members
|
---|
911 |
|
---|
912 | public ISvgStringList RequiredFeatures
|
---|
913 | {
|
---|
914 | get { return svgTests.RequiredFeatures; }
|
---|
915 | }
|
---|
916 |
|
---|
917 | public ISvgStringList RequiredExtensions
|
---|
918 | {
|
---|
919 | get { return svgTests.RequiredExtensions; }
|
---|
920 | }
|
---|
921 |
|
---|
922 | public ISvgStringList SystemLanguage
|
---|
923 | {
|
---|
924 | get { return svgTests.SystemLanguage; }
|
---|
925 | }
|
---|
926 |
|
---|
927 | public bool HasExtension(string extension)
|
---|
928 | {
|
---|
929 | return svgTests.HasExtension(extension);
|
---|
930 | }
|
---|
931 |
|
---|
932 | #endregion
|
---|
933 |
|
---|
934 | #region Update handling
|
---|
935 |
|
---|
936 | public override void HandleAttributeChange(XmlAttribute attribute)
|
---|
937 | {
|
---|
938 | if (attribute.NamespaceURI.Length == 0)
|
---|
939 | {
|
---|
940 | switch (attribute.LocalName)
|
---|
941 | {
|
---|
942 | case "x":
|
---|
943 | case "y":
|
---|
944 | case "width":
|
---|
945 | case "height":
|
---|
946 | case "viewBox":
|
---|
947 | case "preserveAspectRatio":
|
---|
948 | Resize();
|
---|
949 | break;
|
---|
950 | }
|
---|
951 |
|
---|
952 | base.HandleAttributeChange(attribute);
|
---|
953 | }
|
---|
954 | }
|
---|
955 |
|
---|
956 | #endregion
|
---|
957 | }
|
---|
958 | }
|
---|