stub out the Projection classes as well as duplicating the disgusting hack used for...
[moon.git] / class / System.Windows / Mono / Value.cs
blobfb509d4197d698a2458d82c37e7cd23a12a70005
1 //
2 // Value.cs: represents the unmanaged Value structure from runtime.cpp
3 //
4 // Contact:
5 // Moonlight List (moonlight-list@lists.ximian.com)
6 //
7 // Copyright 2007 Novell, Inc.
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 using System;
29 using System.Windows;
30 using System.Windows.Data;
31 using System.Windows.Input;
32 using System.Windows.Markup;
33 using System.Windows.Media;
34 using System.Windows.Media3D;
35 using System.Windows.Documents;
36 using System.Windows.Media.Animation;
37 using System.Runtime.InteropServices;
38 using System.Reflection;
40 namespace Mono {
42 internal struct UnmanagedFontFamily {
43 public IntPtr source;
46 internal struct UnmanagedFontWeight {
47 public FontWeightKind weight;
50 internal struct UnmanagedFontStyle {
51 public FontStyleKind style;
54 internal struct UnmanagedFontStretch {
55 public FontStretchKind stretch;
58 internal struct UnmanagedFontSource {
59 public IntPtr stream;
62 internal struct UnmanagedStreamCallbacks {
63 public IntPtr handle;
64 public IntPtr CanSeek;
65 public IntPtr CanRead;
66 public IntPtr Length;
67 public IntPtr Position;
68 public IntPtr Read;
69 public IntPtr Write;
70 public IntPtr Seek;
71 public IntPtr Close;
74 [StructLayout(LayoutKind.Sequential)]
75 internal struct UnmanagedPropertyPath {
76 public IntPtr pathString;
77 public IntPtr expandedPathString;
78 public IntPtr property;
81 internal struct UnmanagedColor {
82 public double r;
83 public double g;
84 public double b;
85 public double a;
87 public Color ToColor ()
89 return Color.FromArgb ((byte)(255 * a), (byte)(255 * r), (byte)(255 * g), (byte)(255 * b));
93 internal struct UnmanagedUri {
94 public bool isAbsolute;
95 public IntPtr scheme;
96 public IntPtr user;
97 public IntPtr auth;
98 public IntPtr passwd;
99 public IntPtr host;
100 public int port;
101 public IntPtr path;
102 public IntPtr _params;
103 public IntPtr query;
104 public IntPtr fragment;
105 public IntPtr originalString;
107 public unsafe static IntPtr FromUri (Uri managed_uri)
109 IntPtr uri = Marshal.AllocHGlobal (sizeof (UnmanagedUri));
111 UnmanagedUri *uuri = (UnmanagedUri*)uri;
112 uuri->scheme = IntPtr.Zero;
113 uuri->user = IntPtr.Zero;
114 uuri->auth = IntPtr.Zero;
115 uuri->passwd = IntPtr.Zero;
116 uuri->host = IntPtr.Zero;
117 uuri->path = IntPtr.Zero;
118 uuri->_params = IntPtr.Zero;
119 uuri->query = IntPtr.Zero;
120 uuri->fragment = IntPtr.Zero;
121 uuri->originalString = IntPtr.Zero;
123 NativeMethods.uri_parse (uri, managed_uri.OriginalString, false);
125 uuri->isAbsolute = managed_uri.IsAbsoluteUri;
127 return uri;
131 [StructLayout(LayoutKind.Sequential)]
132 internal struct ManagedTypeInfo {
133 public IntPtr assembly_name;
134 public IntPtr full_name;
137 [StructLayout(LayoutKind.Explicit)]
138 internal struct ValUnion {
139 [FieldOffset(0)] public float f;
140 [FieldOffset(0)] public double d;
141 [FieldOffset(0)] public long i64;
142 [FieldOffset(0)] public ulong ui64;
143 [FieldOffset(0)] public int i32;
144 [FieldOffset(0)] public uint ui32;
145 [FieldOffset(0)] public IntPtr p;
148 internal struct Value {
149 // Note: Keep these flags in sync with the native version
150 const int NullFlag = 1;
152 public Kind k;
153 public int bitfield;
154 public ValUnion u;
156 public bool IsNull {
157 get { return (bitfield & NullFlag) == NullFlag; }
158 set {
159 if (value)
160 bitfield |= NullFlag;
161 else
162 bitfield &= ~NullFlag;
166 public static Value Empty {
167 get { return new Value (); }
170 static bool slow_codepath_error_shown = false;
172 public static unsafe object ToObject (Type type, Value* value)
174 if (value == null || value->IsNull) {
175 return null;
177 switch (value->k) {
178 case Kind.INVALID:
179 return null;
181 case Kind.DEPENDENCYPROPERTY:
182 return DependencyProperty.Lookup (value->u.p);
184 case Kind.BOOL:
185 return value->u.i32 != 0;
187 case Kind.DOUBLE:
188 return value->u.d;
190 case Kind.FLOAT:
191 return value->u.f;
193 case Kind.UINT64:
194 return value->u.ui64;
196 case Kind.INT64:
197 return value->u.i64;
199 case Kind.TIMESPAN:
200 return new TimeSpan (value->u.i64);
202 case Kind.INT32:
203 // marshall back to the .NET type that we simply serialised as int for unmanaged usage
204 int i32 = value->u.i32;
205 if (type == typeof (System.Windows.Input.Cursor))
206 return Cursors.FromEnum ((CursorType)i32);
207 else if (type == typeof (TextDecorationCollection))
208 return (i32 == (int) TextDecorationKind.Underline) ? TextDecorations.Underline : null;
209 else if (type != null && type.IsEnum)
210 return Enum.ToObject (type, i32);
211 else
212 return i32;
214 case Kind.CHAR:
215 return (char) value->u.ui32;
217 case Kind.SURFACE:
218 return NativeDependencyObjectHelper.FromIntPtr (value->u.p);
220 case Kind.MANAGED:
221 IntPtr managed_object = value->u.p;
222 GCHandle handle = GCHandle.FromIntPtr (managed_object);
223 return handle.Target;
225 case Kind.STRING: {
226 string str = Marshal.PtrToStringAuto (value->u.p);
227 if (type == null)
228 return str;
230 // marshall back to the .NET type that we simply serialised as 'string' for unmanaged usage
231 if (type == typeof (System.Windows.Markup.XmlLanguage))
232 return XmlLanguage.GetLanguage (str);
233 else
234 return str;
237 case Kind.URI: {
238 UnmanagedUri *uri = (UnmanagedUri*)value->u.p;
239 return uri->originalString == IntPtr.Zero
240 ? new Uri("", UriKind.Relative)
241 : new Uri (Marshal.PtrToStringAuto (uri->originalString),
242 uri->isAbsolute ? UriKind.Absolute : UriKind.Relative);
245 case Kind.XMLLANGUAGE: {
246 string str = Marshal.PtrToStringAuto (value->u.p);
247 return XmlLanguage.GetLanguage (str);
250 case Kind.FONTFAMILY: {
251 UnmanagedFontFamily *family = (UnmanagedFontFamily*)value->u.p;
252 return new FontFamily (family == null ? null : Marshal.PtrToStringAuto (family->source));
255 case Kind.FONTSTRETCH: {
256 UnmanagedFontStretch *stretch = (UnmanagedFontStretch*)value->u.p;
257 return new FontStretch (stretch == null ? FontStretchKind.Normal : stretch->stretch);
260 case Kind.FONTSTYLE: {
261 UnmanagedFontStyle *style = (UnmanagedFontStyle*)value->u.p;
262 return new FontStyle (style == null ? FontStyleKind.Normal : style->style);
265 case Kind.FONTWEIGHT: {
266 UnmanagedFontWeight *weight = (UnmanagedFontWeight*)value->u.p;
267 return new FontWeight (weight == null ? FontWeightKind.Normal : weight->weight);
270 case Kind.FONTSOURCE: {
271 UnmanagedFontSource *source = (UnmanagedFontSource *) value->u.p;
272 ManagedStreamCallbacks callbacks;
273 StreamWrapper wrapper;
275 callbacks = (ManagedStreamCallbacks) Marshal.PtrToStructure (source->stream, typeof (ManagedStreamCallbacks));
277 wrapper = (StreamWrapper) GCHandle.FromIntPtr (callbacks.handle).Target;
279 return new FontSource (wrapper.stream);
282 case Kind.PROPERTYPATH: {
283 UnmanagedPropertyPath *propertypath = (UnmanagedPropertyPath *) value->u.p;
284 if (propertypath == null)
285 return new PropertyPath (null);
286 if (propertypath->property != IntPtr.Zero)
287 return null;
288 return new PropertyPath (Marshal.PtrToStringAuto (propertypath->pathString));
291 case Kind.POINT: {
292 Point *point = (Point*)value->u.p;
293 return (point == null) ? new Point (0,0) : *point;
296 case Kind.RECT: {
297 Rect *rect = (Rect*)value->u.p;
298 return (rect == null) ? new Rect (0,0,0,0) : *rect;
301 case Kind.SIZE: {
302 Size *size = (Size*)value->u.p;
303 return (size == null) ? new Size (0,0) : *size;
306 case Kind.CORNERRADIUS: {
307 CornerRadius *corner = (CornerRadius*)value->u.p;
308 return (corner == null) ? new CornerRadius (0) : *corner;
311 case Kind.THICKNESS: {
312 Thickness *thickness = (Thickness*)value->u.p;
313 return (thickness == null) ? new Thickness (0) : *thickness;
316 case Kind.COLOR: {
317 UnmanagedColor *color = (UnmanagedColor*)value->u.p;
318 if (color == null)
319 return new Color ();
320 return color->ToColor ();
323 case Kind.MATRIX:
324 case Kind.UNMANAGEDMATRIX: {
325 return new Matrix (value->u.p);
328 case Kind.MATRIX3D:
329 case Kind.UNMANAGEDMATRIX3D: {
330 return new Matrix3D (value->u.p);
333 case Kind.DURATION: {
334 Duration* duration = (Duration*)value->u.p;
335 return (duration == null) ? Duration.Automatic : *duration;
338 case Kind.KEYTIME: {
339 KeyTime* keytime = (KeyTime*)value->u.p;
340 return (keytime == null) ? KeyTime.FromTimeSpan (TimeSpan.Zero) : *keytime;
343 case Kind.GRIDLENGTH: {
344 GridLength* gridlength = (GridLength*)value->u.p;
345 return (gridlength == null) ? new GridLength () : *gridlength;
348 case Kind.REPEATBEHAVIOR: {
349 RepeatBehavior *repeat = (RepeatBehavior*)value->u.p;
350 return (repeat == null) ? new RepeatBehavior () : *repeat;
353 case Kind.MEDIAATTRIBUTE_COLLECTION: {
354 MediaAttributeCollection attrs = (MediaAttributeCollection) NativeDependencyObjectHelper.Lookup (value->k, value->u.p);
355 return attrs.AsDictionary ();
358 case Kind.MANAGEDTYPEINFO: {
359 ManagedTypeInfo *type_info = (ManagedTypeInfo *) value->u.p;
361 if (type_info == null)
362 return null;
364 string assembly_name = Marshal.PtrToStringAuto (type_info->assembly_name);
365 string full_name = Marshal.PtrToStringAuto (type_info->full_name);
367 Assembly asm = Application.GetAssembly (assembly_name);
368 if (asm != null)
369 return asm.GetType (full_name);
371 return null;
375 if (!slow_codepath_error_shown){
376 Report.Warning ("DependencyObject type testing now using a very slow code path");
377 slow_codepath_error_shown = true;
380 if (NativeMethods.type_is_dependency_object (value->k)){
381 // Old fast test: if (value->k > Kind.DEPENDENCY_OBJECT){
383 if (value->u.p == IntPtr.Zero)
384 return null;
386 return NativeDependencyObjectHelper.Lookup (value->k, value->u.p);
389 throw new Exception (String.Format ("Do not know how to convert {0} {1}", value->k, (int) value->k));
392 public static unsafe object ToObject (Type type, IntPtr value)
394 return ToObject (type, (Value *) value);
397 public static Value FromObject (object v)
399 return FromObject (v, false);
403 // How do we support "null" values, should the caller take care of that?
405 public static Value FromObject (object v, bool box_value_types)
407 Value value = new Value ();
409 unsafe {
410 // get rid of this case right away.
411 if (box_value_types && v.GetType().IsValueType) {
412 //Console.WriteLine ("Boxing a value of type {0}:", v.GetType());
414 GCHandle handle = GCHandle.Alloc (v);
415 value.k = Kind.MANAGED;
416 value.u.p = GCHandle.ToIntPtr (handle);
417 return value;
420 if (v is IEasingFunction && !(v is EasingFunctionBase))
421 v = new EasingFunctionWrapper (v as IEasingFunction);
423 if (v is INativeDependencyObjectWrapper) {
424 INativeDependencyObjectWrapper dov = (INativeDependencyObjectWrapper) v;
426 if (dov.NativeHandle == IntPtr.Zero)
427 throw new Exception (String.Format (
428 "Object {0} has not set its native property", dov.GetType()));
430 NativeMethods.event_object_ref (dov.NativeHandle);
432 value.k = dov.GetKind ();
433 value.u.p = dov.NativeHandle;
435 } else if (v is DependencyProperty) {
436 value.k = Kind.DEPENDENCYPROPERTY;
437 value.u.p = ((DependencyProperty)v).Native;
439 else if (v is int || (v.GetType ().IsEnum && Enum.GetUnderlyingType (v.GetType()) == typeof(int))) {
440 value.k = Kind.INT32;
441 value.u.i32 = (int) v;
443 else if (v is bool) {
444 value.k = Kind.BOOL;
445 value.u.i32 = ((bool) v) ? 1 : 0;
447 else if (v is double) {
448 value.k = Kind.DOUBLE;
449 value.u.d = (double) v;
451 else if (v is float) {
452 value.k = Kind.FLOAT;
453 value.u.f = (float) v;
455 else if (v is long) {
456 value.k = Kind.INT64;
457 value.u.i64 = (long) v;
459 else if (v is TimeSpan) {
460 TimeSpan ts = (TimeSpan) v;
461 value.k = Kind.TIMESPAN;
462 value.u.i64 = ts.Ticks;
464 else if (v is ulong) {
465 value.k = Kind.UINT64;
466 value.u.ui64 = (ulong) v;
468 else if (v is uint) {
469 value.k = Kind.UINT32;
470 value.u.ui32 = (uint) v;
472 else if (v is char) {
473 value.k = Kind.CHAR;
474 value.u.ui32 = (uint) (char) v;
476 else if (v is string) {
477 value.k = Kind.STRING;
479 value.u.p = StringToIntPtr ((string) v);
481 else if (v is Rect) {
482 Rect rect = (Rect) v;
483 value.k = Kind.RECT;
484 value.u.p = Marshal.AllocHGlobal (sizeof (Rect));
485 Marshal.StructureToPtr (rect, value.u.p, false); // Unmanaged and managed structure layout is equal.
487 else if (v is Size) {
488 Size size = (Size) v;
489 value.k = Kind.SIZE;
490 value.u.p = Marshal.AllocHGlobal (sizeof (Size));
491 Marshal.StructureToPtr (size, value.u.p, false); // Unmanaged and managed structure layout is equal.
493 else if (v is CornerRadius) {
494 CornerRadius corner = (CornerRadius) v;
495 value.k = Kind.CORNERRADIUS;
496 value.u.p = Marshal.AllocHGlobal (sizeof (CornerRadius));
497 Marshal.StructureToPtr (corner, value.u.p, false); // Unmanaged and managed structure layout is equal.
499 else if (v is Point) {
500 Point pnt = (Point) v;
501 value.k = Kind.POINT;
502 value.u.p = Marshal.AllocHGlobal (sizeof (Point));
503 Marshal.StructureToPtr (pnt, value.u.p, false); // Unmanaged and managed structure layout is equal.
505 else if (v is Thickness) {
506 Thickness thickness = (Thickness)v;
507 value.k = Kind.THICKNESS;
508 value.u.p = Marshal.AllocHGlobal (sizeof (Thickness));
509 Marshal.StructureToPtr (thickness, value.u.p, false); // Unmanaged and managed structure layout is equal.
511 else if (v is Color) {
512 Color c = (Color) v;
513 value.k = Kind.COLOR;
514 value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedColor));
515 UnmanagedColor* color = (UnmanagedColor*) value.u.p;
516 color->r = c.R / 255.0f;
517 color->g = c.G / 255.0f;
518 color->b = c.B / 255.0f;
519 color->a = c.A / 255.0f;
521 else if (v is Matrix) {
522 // hack around the fact that managed Matrix is a struct while unmanaged Matrix is a DO
523 // i.e. the unmanaged and managed structure layouts ARE NOT equal
524 return FromObject (new UnmanagedMatrix ((Matrix) v), box_value_types);
526 else if (v is Duration) {
527 Duration d = (Duration) v;
528 value.k = Kind.DURATION;
529 value.u.p = Marshal.AllocHGlobal (sizeof (Duration));
530 Marshal.StructureToPtr (d, value.u.p, false); // Unmanaged and managed structure layout is equal.
532 else if (v is KeyTime) {
533 KeyTime k = (KeyTime) v;
534 value.k = Kind.KEYTIME;
535 value.u.p = Marshal.AllocHGlobal (sizeof (KeyTime));
536 Marshal.StructureToPtr (k, value.u.p, false); // Unmanaged and managed structure layout is equal.
538 else if (v is RepeatBehavior) {
539 RepeatBehavior d = (RepeatBehavior) v;
540 value.k = Kind.REPEATBEHAVIOR;
541 value.u.p = Marshal.AllocHGlobal (sizeof (RepeatBehavior));
542 Marshal.StructureToPtr (d, value.u.p, false); // Unmanaged and managed structure layout is equal.
544 else if (v is FontFamily) {
545 FontFamily family = (FontFamily) v;
546 value.k = Kind.FONTFAMILY;
547 value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedFontFamily));
548 Marshal.StructureToPtr (family, value.u.p, false); // Unmanaged and managed structure layout is equal.
551 else if (v is FontSource) {
552 FontSource source = (FontSource) v;
554 value.k = Kind.FONTSOURCE;
556 if (source.wrapper != null) {
557 value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedFontSource));
558 UnmanagedFontSource *ufs = (UnmanagedFontSource *) value.u.p;
559 ManagedStreamCallbacks callbacks = source.wrapper.GetCallbacks ();
560 ufs->stream = Marshal.AllocHGlobal (sizeof (UnmanagedStreamCallbacks));
561 Marshal.StructureToPtr (callbacks, ufs->stream, false);
562 } else {
563 value.IsNull = true;
567 else if (v is PropertyPath) {
568 PropertyPath propertypath = (PropertyPath) v;
569 value.k = Kind.PROPERTYPATH;
570 value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedPropertyPath));
572 UnmanagedPropertyPath *upp = (UnmanagedPropertyPath *) value.u.p;
573 upp->property = propertypath.NativeDP;
574 if (upp->property == IntPtr.Zero)
575 upp->pathString = StringToIntPtr (propertypath.Path);
576 else
577 upp->pathString = IntPtr.Zero;
578 upp->expandedPathString = IntPtr.Zero;
580 else if (v is Uri) {
581 Uri uri = (Uri) v;
583 value.k = Kind.URI;
584 value.u.p = UnmanagedUri.FromUri (uri);
586 else if (v is XmlLanguage) {
587 XmlLanguage lang = (XmlLanguage) v;
589 value.k = Kind.STRING;
591 value.u.p = StringToIntPtr (lang.IetfLanguageTag);
593 else if (v is Cursor) {
594 Cursor c = (Cursor) v;
596 value.k = Kind.INT32;
598 value.u.i32 = (int)c.cursor;
600 else if (v is GridLength) {
601 GridLength gl = (GridLength) v;
602 value.k = Kind.GRIDLENGTH;
603 value.u.p = Marshal.AllocHGlobal (sizeof (GridLength));
604 Marshal.StructureToPtr (gl, value.u.p, false); // Unmanaged and managed structure layout is equal.
606 else if (v is FontStretch) {
607 FontStretch stretch = (FontStretch) v;
608 value.k = Kind.FONTSTRETCH;
609 value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedFontStretch));
610 Marshal.StructureToPtr (stretch, value.u.p, false); // Unmanaged and managed structure layout is equal.
612 else if (v is FontStyle) {
613 FontStyle style = (FontStyle) v;
614 value.k = Kind.FONTSTYLE;
615 value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedFontStyle));
616 Marshal.StructureToPtr (style, value.u.p, false); // Unmanaged and managed structure layout is equal.
618 else if (v is FontWeight) {
619 FontWeight weight = (FontWeight) v;
620 value.k = Kind.FONTWEIGHT;
621 value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedFontWeight));
622 Marshal.StructureToPtr (weight, value.u.p, false); // Unmanaged and managed structure layout is equal.
624 else if (v is PixelFormat) {
625 // FIXME we need to make an unmanaged PixelFormat struct and
626 // marshal it like the FontStretch/Style/Weight structs above.
627 value.k = Kind.INT32;
628 value.u.i32 = v.GetHashCode ();
630 else if (v is TextDecorationCollection) {
631 value.k = Kind.INT32;
632 value.u.i32 = (int) (v as TextDecorationCollection).Kind;
634 else if (v is Type) {
635 Type t = v as Type;
636 ManagedTypeInfo mti = new ManagedTypeInfo ();
638 mti.assembly_name = StringToIntPtr (t.Assembly.GetName ().Name);
639 mti.full_name = StringToIntPtr (t.FullName);
641 value.k = Kind.MANAGEDTYPEINFO;
642 value.u.p = Marshal.AllocHGlobal (sizeof (ManagedTypeInfo));
643 Marshal.StructureToPtr (mti, value.u.p, false);
645 else {
646 //Console.WriteLine ("Do not know how to encode {0} yet, boxing it", v.GetType ());
648 // TODO: We probably need to marshal types that can animate as the
649 // corresponding type (Point, Double, Color, etc).
650 // TODO: We need to store the GCHandle somewhere so that we can free it,
651 // or register a callback on the surface for the unmanaged code to call.
652 GCHandle handle = GCHandle.Alloc (v);
653 value.k = Kind.MANAGED;
654 value.u.p = GCHandle.ToIntPtr (handle);
657 return value;
660 public static IntPtr StringToIntPtr (string str)
662 if (str == null)
663 return IntPtr.Zero;
665 byte [] bytes = System.Text.Encoding.UTF8.GetBytes (str);
666 IntPtr result = Marshal.AllocHGlobal (bytes.Length + 1);
667 Marshal.Copy (bytes, 0, result, bytes.Length);
668 Marshal.WriteByte (result, bytes.Length, 0);
670 return result;