1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * value.cpp: Implementation of for Value.
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
27 #include "animation.h"
31 #include "cornerradius.h"
32 #include "mono/metadata/object.h"
33 #include "fontsource.h"
34 #include "transform.h"
37 #define INCLUDED_MONO_HEADERS 1
38 #include "deployment.h"
39 #include "managedtypeinfo.h"
42 * Value implementation
45 static const int NullFlag
= 1;
48 Value::CreateUnrefPtr (EventObject
* dob
)
50 Value
*result
= new Value (dob
);
51 LOG_VALUE ("unref Value [%p] %s\n", result
, result
->GetName());
58 Value::CreateUnref (EventObject
* dob
)
61 LOG_VALUE ("unref Value [%p] %s\n", &result
, result
.GetName());
67 Value::Clone (Value
*v
, Types
*types
)
73 types
= Deployment::GetCurrent()->GetTypes();
75 if (!v
->GetIsNull () && types
->IsSubclassOf (v
->k
, Type::DEPENDENCY_OBJECT
)) {
76 return new Value (v
->AsDependencyObject()->Clone (types
));
79 return new Value (*v
);
92 return (padding
& NullFlag
) == NullFlag
;
96 Value::SetIsNull (bool isNull
)
101 padding
&= ~NullFlag
;
108 memset (&u
, 0, sizeof (u
));
118 Value::Value (const Value
& v
)
123 Value::Value (Type::Kind k
)
137 Value::Value (double d
)
145 Value::Value (gint64 i
, Type::Kind as
)
153 Value::Value (gint32 i
)
162 Value::Value (guint32 i
)
170 Value::Value (gunichar c
, Type::Kind as
)
178 Value::Value (Color c
)
182 u
.color
= g_new (Color
, 1);
183 *u
.color
= Color (c
);
187 Value::Value (EventObject
* obj
)
191 k
= Type::EVENTOBJECT
;
194 if (!Type::IsSubclassOf (obj
->GetDeployment (), obj
->GetObjectType (), Type::EVENTOBJECT
)) {
195 g_warning ("creating invalid dependency object Value");
197 u
.dependency_object
= NULL
;
200 k
= obj
->GetObjectType ();
201 LOG_VALUE (" ref Value [%p] %s\n", this, GetName());
205 u
.dependency_object
= obj
;
208 Value::Value (FontFamily family
)
211 k
= Type::FONTFAMILY
;
212 u
.fontfamily
= g_new (FontFamily
, 1);
213 u
.fontfamily
->source
= g_strdup (family
.source
);
217 Value::Value (FontWeight weight
)
220 k
= Type::FONTWEIGHT
;
221 u
.fontweight
= g_new (FontWeight
, 1);
222 u
.fontweight
->weight
= weight
.weight
;
226 Value::Value (FontStretch stretch
)
229 k
= Type::FONTSTRETCH
;
230 u
.fontstretch
= g_new (FontStretch
, 1);
231 u
.fontstretch
->stretch
= stretch
.stretch
;
235 Value::Value (FontStyle style
)
239 u
.fontstyle
= g_new (FontStyle
, 1);
240 u
.fontstyle
->style
= style
.style
;
244 Value::Value (FontSource source
)
247 k
= Type::FONTSOURCE
;
248 u
.fontsource
= g_new (FontSource
, 1);
249 u
.fontsource
->stream
= g_new (ManagedStreamCallbacks
, 1);
250 memcpy (u
.fontsource
->stream
, source
.stream
, sizeof (ManagedStreamCallbacks
));
254 Value::Value (PropertyPath propertypath
)
257 k
= Type::PROPERTYPATH
;
258 u
.propertypath
= g_new (PropertyPath
, 1);
259 u
.propertypath
->path
= g_strdup (propertypath
.path
);
260 u
.propertypath
->expanded_path
= g_strdup (propertypath
.expanded_path
);
261 u
.propertypath
->property
= propertypath
.property
;
265 Value::Value (Type::Kind kind
, void *npobj
)
269 u
.managed_object
= npobj
;
270 SetIsNull (npobj
== NULL
);
273 Value::Value (Point pt
)
277 u
.point
= g_new (Point
, 1);
278 *u
.point
= Point (pt
);
282 Value::Value (Uri uri
)
286 u
.uri
= g_new (Uri
, 1);
287 Uri::Copy (&uri
, u
.uri
);
291 Value::Value (Rect rect
)
295 u
.rect
= g_new (Rect
, 1);
296 *u
.rect
= Rect (rect
);
300 Value::Value (Size size
)
304 u
.size
= g_new (Size
, 1);
305 *u
.size
= Size (size
);
309 Value::Value (RepeatBehavior repeat
)
312 k
= Type::REPEATBEHAVIOR
;
313 u
.repeat
= g_new (RepeatBehavior
, 1);
314 *u
.repeat
= RepeatBehavior (repeat
);
318 Value::Value (Duration duration
)
322 u
.duration
= g_new (Duration
, 1);
323 *u
.duration
= Duration (duration
);
327 Value::Value (KeyTime keytime
)
331 u
.keytime
= g_new (KeyTime
, 1);
332 *u
.keytime
= KeyTime (keytime
);
336 Value::Value (const char *s
, bool take
)
341 u
.s
= take
? (char *) s
: g_strdup (s
);
342 SetIsNull (s
== NULL
);
345 Value::Value (GridLength grid_length
)
348 k
= Type::GRIDLENGTH
;
349 u
.grid_length
= g_new (GridLength
, 1);
350 *u
.grid_length
= GridLength (grid_length
);
354 Value::Value (Thickness thickness
)
358 u
.thickness
= g_new (Thickness
, 1);
359 *u
.thickness
= Thickness (thickness
);
363 Value::Value (CornerRadius corner
)
366 k
= Type::CORNERRADIUS
;
367 u
.corner
= g_new (CornerRadius
, 1);
368 *u
.corner
= CornerRadius (corner
);
372 Value::Value (ManagedTypeInfo type_info
)
375 k
= Type::MANAGEDTYPEINFO
;
376 u
.type_info
= g_new0 (ManagedTypeInfo
, 1);
377 *u
.type_info
= ManagedTypeInfo (type_info
);
382 Value::Copy (const Value
& v
)
388 SetIsNull (((Value
&)v
).GetIsNull());
390 /* make a copy of the string instead of just the pointer */
393 u
.s
= g_strdup (v
.u
.s
);
395 case Type::FONTFAMILY
:
396 if (v
.u
.fontfamily
) {
397 u
.fontfamily
= g_new (FontFamily
, 1);
398 u
.fontfamily
->source
= g_strdup (v
.u
.fontfamily
->source
);
401 case Type::FONTSOURCE
:
402 if (v
.u
.fontsource
) {
403 u
.fontsource
= g_new (FontSource
, 1);
404 u
.fontsource
->stream
= g_new (ManagedStreamCallbacks
, 1);
405 memcpy (u
.fontsource
->stream
, v
.u
.fontsource
->stream
, sizeof (ManagedStreamCallbacks
));
408 case Type::FONTWEIGHT
:
409 if (v
.u
.fontweight
) {
410 u
.fontweight
= g_new (FontWeight
, 1);
411 *u
.fontweight
= *v
.u
.fontweight
;
414 case Type::FONTSTRETCH
:
415 if (v
.u
.fontstretch
) {
416 u
.fontstretch
= g_new (FontStretch
, 1);
417 *u
.fontstretch
= *v
.u
.fontstretch
;
420 case Type::FONTSTYLE
:
422 u
.fontstyle
= g_new (FontStyle
, 1);
423 *u
.fontstyle
= *v
.u
.fontstyle
;
426 case Type::PROPERTYPATH
:
427 if (v
.u
.propertypath
) {
428 u
.propertypath
= g_new (PropertyPath
, 1);
429 u
.propertypath
->path
= g_strdup (v
.u
.propertypath
->path
);
430 u
.propertypath
->expanded_path
= g_strdup (v
.u
.propertypath
->expanded_path
);
431 u
.propertypath
->property
= v
.u
.propertypath
->property
;
436 u
.color
= g_new (Color
, 1);
437 *u
.color
= *v
.u
.color
;
442 u
.point
= g_new (Point
, 1);
443 *u
.point
= *v
.u
.point
;
448 u
.rect
= g_new (Rect
, 1);
454 u
.size
= g_new (Size
, 1);
460 u
.uri
= g_new (Uri
, 1);
461 Uri::Copy (v
.u
.uri
, u
.uri
);
466 case Type::REPEATBEHAVIOR
:
468 u
.repeat
= g_new (RepeatBehavior
, 1);
469 *u
.repeat
= *v
.u
.repeat
;
474 u
.duration
= g_new (Duration
, 1);
475 *u
.duration
= *v
.u
.duration
;
480 u
.keytime
= g_new (KeyTime
, 1);
481 *u
.keytime
= *v
.u
.keytime
;
484 case Type::GRIDLENGTH
:
485 if (v
.u
.grid_length
) {
486 u
.grid_length
= g_new (GridLength
, 1);
487 *u
.grid_length
= *v
.u
.grid_length
;
490 case Type::THICKNESS
:
492 u
.thickness
= g_new (Thickness
, 1);
493 *u
.thickness
= *v
.u
.thickness
;
496 case Type::CORNERRADIUS
:
498 u
.corner
= g_new (CornerRadius
, 1);
499 *u
.corner
= *v
.u
.corner
;
502 case Type::MANAGEDTYPEINFO
:
504 u
.type_info
= g_new0 (ManagedTypeInfo
, 1);
505 *u
.type_info
= *v
.u
.type_info
;
509 if (Is (Deployment::GetCurrent (), Type::EVENTOBJECT
) && u
.dependency_object
) {
510 LOG_VALUE (" ref Value [%p] %s\n", this, GetName());
511 u
.dependency_object
->ref ();
520 switch (GetKind ()) {
527 case Type::FONTFAMILY
:
529 g_free (u
.fontfamily
->source
);
530 g_free (u
.fontfamily
);
533 case Type::FONTWEIGHT
:
534 g_free (u
.fontweight
);
536 case Type::FONTSTYLE
:
537 g_free (u
.fontstyle
);
539 case Type::FONTSTRETCH
:
540 g_free (u
.fontstretch
);
542 case Type::FONTSOURCE
:
544 g_free (u
.fontsource
->stream
);
545 g_free (u
.fontsource
);
548 case Type::PROPERTYPATH
:
549 if (u
.propertypath
) {
550 g_free (u
.propertypath
->path
);
551 g_free (u
.propertypath
->expanded_path
);
552 g_free (u
.propertypath
);
570 case Type::REPEATBEHAVIOR
:
579 case Type::GRIDLENGTH
:
580 g_free (u
.grid_length
);
582 case Type::THICKNESS
:
583 g_free (u
.thickness
);
585 case Type::CORNERRADIUS
:
588 case Type::MANAGEDTYPEINFO
:
589 ManagedTypeInfo::Free (u
.type_info
);
592 if (Is (Deployment::GetCurrent (), Type::EVENTOBJECT
) && u
.dependency_object
) {
593 LOG_VALUE ("unref Value [%p] %s\n", this, GetName());
594 u
.dependency_object
->unref ();
602 GString
*str
= g_string_new ("");
606 g_string_append_printf (str
, "{ %f }", u
.d
);
609 g_string_append (str
, u
.s
);
612 g_string_append_printf (str
, "{%g/%g/%g/%g}", u
.color
->r
, u
.color
->g
, u
.color
->b
, u
.color
->a
);
615 g_string_append_printf (str
, "{ %g, %g }", (u
.point
)->x
, (u
.point
)->y
);
618 g_string_append_printf (str
, "{ %g, %g }", (u
.size
)->width
, (u
.size
)->height
);
621 g_string_append_printf (str
, "{ x=%g, y=%g, w=%g, h=%g }", (u
.rect
)->x
, (u
.rect
)->y
, (u
.rect
)->width
, (u
.rect
)->height
);
623 case Type::REPEATBEHAVIOR
:
624 if (u
.repeat
->IsForever ())
625 g_string_append (str
, "{repeat=forever}");
626 else if ((u
.repeat
)->HasDuration ())
627 g_string_append_printf (str
, "{repeat=duration}");
628 else if ((u
.repeat
)->HasCount ())
629 g_string_append_printf (str
, "{repeat=count %g}", (u
.repeat
)->GetCount ());
631 case Type::THICKNESS
:
632 g_string_append_printf (str
, "{ l=%g, t=%g, r=%g, b=%g }", (u
.thickness
)->left
, (u
.thickness
)->top
, (u
.thickness
)->right
, (u
.thickness
)->bottom
);
635 g_string_append_printf (str
, "{duration/TODO}");
638 g_string_append_printf (str
, "{keytime/TODO}");
640 case Type::GRIDLENGTH
:
641 g_string_append_printf (str
, "{gridlength value:%.2f type:%d}", u
.grid_length
->val
, u
.grid_length
->type
);
644 if (Is (Deployment::GetCurrent (), Type::EVENTOBJECT
) && u
.dependency_object
)
645 g_string_append_printf (str
, "[%s <%s>]", u
.dependency_object
->GetTypeName (), Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT
) ? AsDependencyObject ()->GetName () : "no name");
647 g_string_append_printf (str
, "UnknownType");
651 return g_string_free (str
, FALSE
);
655 Value::operator!= (const Value
&v
) const
657 return !(*this == v
);
661 Value::operator== (const Value
&v
) const
666 if (padding
!= v
.padding
)
672 return v
.u
.s
== NULL
;
673 } else if (v
.u
.s
== NULL
)
676 return !strcmp (u
.s
, v
.u
.s
);
677 /* don't use memcmp for comparing structures, structures may have uninitialized padding,
678 * which would cause random behaviour */
679 case Type::FONTFAMILY
:
680 return *u
.fontfamily
== *v
.u
.fontfamily
;
681 case Type::FONTWEIGHT
:
682 return *u
.fontweight
== *v
.u
.fontweight
;
683 case Type::FONTSTYLE
:
684 return *u
.fontstyle
== *v
.u
.fontstyle
;
685 case Type::FONTSTRETCH
:
686 return *u
.fontstretch
== *v
.u
.fontstretch
;
687 case Type::FONTSOURCE
:
688 if (u
.fontsource
&& v
.u
.fontsource
)
689 return u
.fontsource
->stream
->handle
== v
.u
.fontsource
->stream
->handle
;
690 return u
.fontsource
== v
.u
.fontsource
;
691 case Type::PROPERTYPATH
:
692 return *u
.propertypath
== *v
.u
.propertypath
;
694 return *u
.color
== *v
.u
.color
;
696 return *u
.point
== *v
.u
.point
;
698 return *u
.rect
== *v
.u
.rect
;
700 return *u
.size
== *v
.u
.size
;
701 case Type::REPEATBEHAVIOR
:
702 return *u
.repeat
== *v
.u
.repeat
;
704 return *u
.duration
== *v
.u
.duration
;
706 return *u
.keytime
== *v
.u
.keytime
;
707 case Type::GRIDLENGTH
:
708 return *u
.grid_length
== *v
.u
.grid_length
;
709 case Type::THICKNESS
:
710 return *u
.thickness
== *v
.u
.thickness
;
711 case Type::CORNERRADIUS
:
712 return *u
.corner
== *v
.u
.corner
;
713 case Type::MANAGEDTYPEINFO
:
714 return *u
.type_info
== *v
.u
.type_info
;
720 return *u
.uri
== *v
.u
.uri
;
722 return fabs (u
.d
- v
.u
.d
) < DBL_EPSILON
;
724 return fabs (u
.f
- v
.u
.f
) < FLT_EPSILON
;
725 case Type::MANAGED
: {
726 // If we avoid the cast to 64bit uint, i don't know how to implement this sanity check.
727 //g_return_val_if_fail (a == (a & 0xFFFFFFFF) && b == (b & 0xFFFFFFFF), false);
728 guint32 a
= GPOINTER_TO_INT (u
.managed_object
);
729 guint32 b
= GPOINTER_TO_INT (v
.u
.managed_object
);
730 return mono_gchandle_get_target (a
) == mono_gchandle_get_target (b
);
734 return !memcmp (&u
, &v
.u
, sizeof (u
));
741 Value::operator= (const Value
& other
)
749 // This is invoked by managed code to free the contents of the value
752 value_free_value (Value
* value
)
758 value_free_value2 (Value
*value
)
760 value_free_value (value
);
772 GString
*str
= g_string_new ("");
776 g_string_append_printf (str
, "DOUBLE");
779 g_string_append_printf (str
, "STRING");
782 g_string_append_printf (str
, "COLOR");
785 g_string_append_printf (str
, "POINT");
788 g_string_append_printf (str
, "SIZE");
791 g_string_append_printf (str
, "RECT");
793 case Type::REPEATBEHAVIOR
:
794 g_string_append_printf (str
, "REPEATBEHAVIOR");
796 case Type::THICKNESS
:
797 g_string_append_printf (str
, "THICKNESS");
800 g_string_append_printf (str
, "DURATION");
803 g_string_append_printf (str
, "KEYTIME");
805 case Type::GRIDLENGTH
:
806 g_string_append_printf (str
, "GRIDLENGTH");
809 if (u
.dependency_object
)
810 g_string_append_printf (str
, "[%s] [%p] %d", u
.dependency_object
->GetTypeName (), u
.dependency_object
, u
.dependency_object
->GetRefCount ());
812 g_string_append_printf (str
, "UnknownType");
816 return g_string_free (str
, FALSE
);