add the 2.1-bootstrap dir to MONO_PATH when running smcs
[moon.git] / src / value.cpp
blob9584dde3e0b5757c77fe6fa4d202aa0b3fd99c16
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * value.cpp: Implementation of for Value.
5 * Contact:
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.
14 #include <config.h>
16 #include <cairo.h>
18 #include <string.h>
19 #include <stdlib.h>
21 #include "value.h"
22 #include "rect.h"
23 #include "size.h"
24 #include "uri.h"
25 #include "color.h"
26 #include "clock.h"
27 #include "animation.h"
28 #include "control.h"
29 #include "point.h"
30 #include "grid.h"
31 #include "cornerradius.h"
32 #include "mono/metadata/object.h"
33 #include "fontsource.h"
34 #include "transform.h"
35 #include "utils.h"
36 #include "debug.h"
38 /**
39 * Value implementation
42 static const int NullFlag = 1;
44 Value*
45 Value::CreateUnrefPtr (EventObject* dob)
47 Value *result = new Value (dob);
48 LOG_VALUE ("unref Value [%p] %s\n", result, result->GetName());
49 if (dob)
50 dob->unref ();
51 return result;
54 Value
55 Value::CreateUnref (EventObject* dob)
57 Value result (dob);
58 LOG_VALUE ("unref Value [%p] %s\n", &result, result.GetName());
59 dob->unref ();
60 return result;
63 Value*
64 Value::Clone (Value *v, Types *types)
66 if (!v)
67 return NULL;
69 if (!types)
70 types = Deployment::GetCurrent()->GetTypes();
72 if (types->IsSubclassOf (v->k, Type::DEPENDENCY_OBJECT)) {
73 return new Value (v->AsDependencyObject()->Clone (types));
75 else {
76 return new Value (*v);
80 Type::Kind
81 Value::GetKind ()
83 return k;
86 bool
87 Value::GetIsNull ()
89 return (padding & NullFlag) == NullFlag;
92 void
93 Value::SetIsNull (bool isNull)
95 if (isNull)
96 padding |= NullFlag;
97 else
98 padding &= ~NullFlag;
101 void
102 Value::Set (double value)
104 u.d = value;
107 void
108 Value::Init ()
110 padding = 0;
111 memset (&u, 0, sizeof (u));
112 SetIsNull (true);
115 Value::Value()
117 k = Type::INVALID;
118 Init ();
121 Value::Value (const Value& v)
123 Copy (v);
126 Value::Value (Type::Kind k)
128 Init();
129 this->k = k;
132 Value::Value(bool z)
134 Init ();
135 k = Type::BOOL;
136 u.i32 = z;
137 SetIsNull (false);
140 Value::Value (double d)
142 Init ();
143 k = Type::DOUBLE;
144 u.d = d;
145 SetIsNull (false);
148 Value::Value (gint64 i, Type::Kind as)
150 Init ();
151 k = as;
152 u.i64 = i;
153 SetIsNull (false);
156 Value::Value (gint32 i)
158 Init ();
159 k = Type::INT32;
160 u.i32 = i;
161 SetIsNull (false);
165 Value::Value (guint32 i)
167 Init ();
168 k = Type::UINT32;
169 u.ui32 = i;
170 SetIsNull (false);
173 Value::Value (gunichar c, Type::Kind as)
175 Init ();
176 k = as;
177 u.c = c;
178 SetIsNull (false);
181 Value::Value (Color c)
183 Init ();
184 k = Type::COLOR;
185 u.color = g_new (Color, 1);
186 *u.color = Color (c);
187 SetIsNull (false);
190 Value::Value (EventObject* obj)
192 Init ();
193 if (obj == NULL) {
194 k = Type::EVENTOBJECT;
196 else {
197 if (!Type::IsSubclassOf (obj->GetObjectType (), Type::EVENTOBJECT)) {
198 g_warning ("creating invalid dependency object Value");
199 k = Type::INVALID;
200 u.dependency_object = NULL;
201 return;
203 k = obj->GetObjectType ();
204 LOG_VALUE (" ref Value [%p] %s\n", this, GetName());
205 obj->ref ();
206 SetIsNull (false);
208 u.dependency_object = obj;
211 Value::Value (FontFamily family)
213 Init ();
214 k = Type::FONTFAMILY;
215 u.fontfamily = g_new (FontFamily, 1);
216 u.fontfamily->source = g_strdup (family.source);
217 SetIsNull (false);
220 Value::Value (FontWeight weight)
222 Init ();
223 k = Type::FONTWEIGHT;
224 u.fontweight = g_new (FontWeight, 1);
225 u.fontweight->weight = weight.weight;
226 SetIsNull (false);
229 Value::Value (FontStretch stretch)
231 Init ();
232 k = Type::FONTSTRETCH;
233 u.fontstretch = g_new (FontStretch, 1);
234 u.fontstretch->stretch = stretch.stretch;
235 SetIsNull (false);
238 Value::Value (FontStyle style)
240 Init ();
241 k = Type::FONTSTYLE;
242 u.fontstyle = g_new (FontStyle, 1);
243 u.fontstyle->style = style.style;
244 SetIsNull (false);
247 Value::Value (FontSource source)
249 Init ();
250 k = Type::FONTSOURCE;
251 u.fontsource = g_new (FontSource, 1);
252 u.fontsource->stream = g_new (ManagedStreamCallbacks, 1);
253 memcpy (u.fontsource->stream, source.stream, sizeof (ManagedStreamCallbacks));
254 SetIsNull (false);
257 Value::Value (PropertyPath propertypath)
259 Init ();
260 k = Type::PROPERTYPATH;
261 u.propertypath = g_new (PropertyPath, 1);
262 u.propertypath->path = g_strdup (propertypath.path);
263 u.propertypath->expanded_path = g_strdup (propertypath.expanded_path);
264 u.propertypath->property = propertypath.property;
265 SetIsNull (false);
268 Value::Value (Type::Kind kind, void *npobj)
270 Init ();
271 k = kind;
272 u.managed_object = npobj;
273 SetIsNull (npobj == NULL);
276 Value::Value (Point pt)
278 Init ();
279 k = Type::POINT;
280 u.point = g_new (Point, 1);
281 *u.point = Point (pt);
282 SetIsNull (false);
285 Value::Value (Uri uri)
287 Init ();
288 k = Type::URI;
289 u.uri = g_new (Uri, 1);
290 Uri::Copy (&uri, u.uri);
291 SetIsNull (false);
294 Value::Value (Rect rect)
296 Init ();
297 k = Type::RECT;
298 u.rect = g_new (Rect, 1);
299 *u.rect = Rect (rect);
300 SetIsNull (false);
303 Value::Value (Size size)
305 Init ();
306 k = Type::SIZE;
307 u.size = g_new (Size, 1);
308 *u.size = Size (size);
309 SetIsNull (false);
312 Value::Value (RepeatBehavior repeat)
314 Init();
315 k = Type::REPEATBEHAVIOR;
316 u.repeat = g_new (RepeatBehavior, 1);
317 *u.repeat = RepeatBehavior (repeat);
318 SetIsNull (false);
321 Value::Value (Duration duration)
323 Init();
324 k = Type::DURATION;
325 u.duration = g_new (Duration, 1);
326 *u.duration = Duration (duration);
327 SetIsNull (false);
330 Value::Value (KeyTime keytime)
332 Init ();
333 k = Type::KEYTIME;
334 u.keytime = g_new (KeyTime, 1);
335 *u.keytime = KeyTime (keytime);
336 SetIsNull (false);
339 Value::Value (const char *s, bool take)
341 Init ();
342 k = Type::STRING;
344 u.s = take ? (char *) s : g_strdup (s);
345 SetIsNull (s == NULL);
348 Value::Value (GridLength grid_length)
350 Init ();
351 k = Type::GRIDLENGTH;
352 u.grid_length = g_new (GridLength, 1);
353 *u.grid_length = GridLength (grid_length);
354 SetIsNull (false);
357 Value::Value (Thickness thickness)
359 Init ();
360 k = Type::THICKNESS;
361 u.thickness = g_new (Thickness, 1);
362 *u.thickness = Thickness (thickness);
363 SetIsNull (false);
366 Value::Value (CornerRadius corner)
368 Init ();
369 k = Type::CORNERRADIUS;
370 u.corner = g_new (CornerRadius, 1);
371 *u.corner = CornerRadius (corner);
372 SetIsNull (false);
375 Value::Value (ManagedTypeInfo type_info)
377 Init ();
378 k = Type::MANAGEDTYPEINFO;
379 u.type_info = g_new (ManagedTypeInfo, 1);
380 *u.type_info = ManagedTypeInfo (type_info);
381 SetIsNull (false);
384 void
385 Value::Copy (const Value& v)
387 padding = v.padding;
388 k = v.k;
389 u = v.u;
391 SetIsNull (((Value&)v).GetIsNull());
393 /* make a copy of the string instead of just the pointer */
394 switch (k) {
395 case Type::STRING:
396 u.s = g_strdup (v.u.s);
397 break;
398 case Type::FONTFAMILY:
399 if (v.u.fontfamily) {
400 u.fontfamily = g_new (FontFamily, 1);
401 u.fontfamily->source = g_strdup (v.u.fontfamily->source);
403 break;
404 case Type::FONTSOURCE:
405 if (v.u.fontsource) {
406 u.fontsource = g_new (FontSource, 1);
407 u.fontsource->stream = g_new (ManagedStreamCallbacks, 1);
408 memcpy (u.fontsource->stream, v.u.fontsource->stream, sizeof (ManagedStreamCallbacks));
410 break;
411 case Type::FONTWEIGHT:
412 if (v.u.fontweight) {
413 u.fontweight = g_new (FontWeight, 1);
414 *u.fontweight = *v.u.fontweight;
416 break;
417 case Type::FONTSTRETCH:
418 if (v.u.fontstretch) {
419 u.fontstretch = g_new (FontStretch, 1);
420 *u.fontstretch = *v.u.fontstretch;
422 break;
423 case Type::FONTSTYLE:
424 if (v.u.fontstyle) {
425 u.fontstyle = g_new (FontStyle, 1);
426 *u.fontstyle = *v.u.fontstyle;
428 break;
429 case Type::PROPERTYPATH:
430 if (v.u.propertypath) {
431 u.propertypath = g_new (PropertyPath, 1);
432 u.propertypath->path = g_strdup (v.u.propertypath->path);
433 u.propertypath->expanded_path = g_strdup (v.u.propertypath->expanded_path);
434 u.propertypath->property = v.u.propertypath->property;
436 break;
437 case Type::COLOR:
438 if (v.u.color) {
439 u.color = g_new (Color, 1);
440 *u.color = *v.u.color;
442 break;
443 case Type::POINT:
444 if (v.u.point) {
445 u.point = g_new (Point, 1);
446 *u.point = *v.u.point;
448 break;
449 case Type::RECT:
450 if (v.u.rect) {
451 u.rect = g_new (Rect, 1);
452 *u.rect = *v.u.rect;
454 break;
455 case Type::SIZE:
456 if (v.u.size) {
457 u.size = g_new (Size, 1);
458 *u.size = *v.u.size;
460 break;
461 case Type::URI:
462 if (v.u.uri) {
463 u.uri = g_new (Uri, 1);
464 Uri::Copy (v.u.uri, u.uri);
465 } else {
466 u.uri = NULL;
468 break;
469 case Type::REPEATBEHAVIOR:
470 if (v.u.repeat) {
471 u.repeat = g_new (RepeatBehavior, 1);
472 *u.repeat = *v.u.repeat;
474 break;
475 case Type::DURATION:
476 if (v.u.duration) {
477 u.duration = g_new (Duration, 1);
478 *u.duration = *v.u.duration;
480 break;
481 case Type::KEYTIME:
482 if (v.u.keytime) {
483 u.keytime = g_new (KeyTime, 1);
484 *u.keytime = *v.u.keytime;
486 break;
487 case Type::GRIDLENGTH:
488 if (v.u.grid_length) {
489 u.grid_length = g_new (GridLength, 1);
490 *u.grid_length = *v.u.grid_length;
492 break;
493 case Type::THICKNESS:
494 if (v.u.thickness) {
495 u.thickness = g_new (Thickness, 1);
496 *u.thickness = *v.u.thickness;
498 break;
499 case Type::CORNERRADIUS:
500 if (v.u.corner) {
501 u.corner = g_new (CornerRadius, 1);
502 *u.corner = *v.u.corner;
504 break;
505 case Type::MANAGEDTYPEINFO:
506 if (v.u.type_info) {
507 u.type_info = g_new (ManagedTypeInfo, 1);
508 *u.type_info = *v.u.type_info;
510 break;
511 default:
512 if (Is (Type::EVENTOBJECT) && u.dependency_object) {
513 LOG_VALUE (" ref Value [%p] %s\n", this, GetName());
514 u.dependency_object->ref ();
516 break;
520 void
521 Value::FreeValue ()
523 switch (GetKind ()) {
524 case Type::STRING:
525 g_free (u.s);
526 break;
527 case Type::COLOR:
528 g_free (u.color);
529 break;
530 case Type::FONTFAMILY:
531 if (u.fontfamily) {
532 g_free (u.fontfamily->source);
533 g_free (u.fontfamily);
535 break;
536 case Type::FONTWEIGHT:
537 g_free (u.fontweight);
538 break;
539 case Type::FONTSTYLE:
540 g_free (u.fontstyle);
541 break;
542 case Type::FONTSTRETCH:
543 g_free (u.fontstretch);
544 break;
545 case Type::FONTSOURCE:
546 if (u.fontsource) {
547 g_free (u.fontsource->stream);
548 g_free (u.fontsource);
550 break;
551 case Type::PROPERTYPATH:
552 if (u.propertypath) {
553 g_free (u.propertypath->path);
554 g_free (u.propertypath->expanded_path);
555 g_free (u.propertypath);
557 break;
558 case Type::POINT:
559 g_free (u.point);
560 break;
561 case Type::RECT:
562 g_free (u.rect);
563 break;
564 case Type::SIZE:
565 g_free (u.size);
566 break;
567 case Type::URI:
568 if (u.uri) {
569 u.uri->Free ();
570 g_free (u.uri);
572 break;
573 case Type::REPEATBEHAVIOR:
574 g_free (u.repeat);
575 break;
576 case Type::DURATION:
577 g_free (u.duration);
578 break;
579 case Type::KEYTIME:
580 g_free (u.keytime);
581 break;
582 case Type::GRIDLENGTH:
583 g_free (u.grid_length);
584 break;
585 case Type::THICKNESS:
586 g_free (u.thickness);
587 break;
588 case Type::CORNERRADIUS:
589 g_free (u.corner);
590 break;
591 default:
592 if (Is (Type::EVENTOBJECT) && u.dependency_object) {
593 LOG_VALUE ("unref Value [%p] %s\n", this, GetName());
594 u.dependency_object->unref ();
599 char *
600 Value::ToString ()
602 GString *str = g_string_new ("");
604 switch (k) {
605 case Type::DOUBLE:
606 g_string_append_printf (str, "{ %f }", u.d);
607 break;
608 case Type::STRING:
609 g_string_append (str, u.s);
610 break;
611 case Type::COLOR:
612 g_string_append_printf (str, "{%g/%g/%g/%g}", u.color->r, u.color->g, u.color->b, u.color->a);
613 break;
614 case Type::POINT:
615 g_string_append_printf (str, "{ %g, %g }", (u.point)->x, (u.point)->y);
616 break;
617 case Type::SIZE:
618 g_string_append_printf (str, "{ %g, %g }", (u.size)->width, (u.size)->height);
619 break;
620 case Type::RECT:
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);
622 break;
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 ());
630 break;
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);
633 break;
634 case Type::DURATION:
635 g_string_append_printf (str, "{duration/TODO}");
636 break;
637 case Type::KEYTIME:
638 g_string_append_printf (str, "{keytime/TODO}");
639 break;
640 case Type::GRIDLENGTH:
641 g_string_append_printf (str, "{gridlength value:%.2f type:%d}", u.grid_length->val, u.grid_length->type);
642 break;
643 default:
644 if (Is (Type::EVENTOBJECT) && u.dependency_object)
645 g_string_append_printf (str, "[%s <%s>]", u.dependency_object->GetTypeName (), Is (Type::DEPENDENCY_OBJECT) ? AsDependencyObject ()->GetName () : "no name");
646 else
647 g_string_append_printf (str, "UnknownType");
648 break;
651 return g_string_free (str, FALSE);
654 bool
655 Value::operator!= (const Value &v) const
657 return !(*this == v);
660 bool
661 Value::operator== (const Value &v) const
663 if (k != v.k)
664 return false;
666 if (padding != v.padding)
667 return false;
669 switch (k) {
670 case Type::STRING:
671 if (u.s == NULL){
672 return v.u.s == NULL;
673 } else if (v.u.s == NULL)
674 return FALSE;
676 return !strcmp (u.s, v.u.s);
677 case Type::FONTFAMILY:
678 return *u.fontfamily == *v.u.fontfamily;
679 case Type::FONTWEIGHT:
680 return *u.fontweight == *v.u.fontweight;
681 case Type::FONTSTYLE:
682 return *u.fontstyle == *v.u.fontstyle;
683 case Type::FONTSTRETCH:
684 return *u.fontstretch == *v.u.fontstretch;
685 case Type::FONTSOURCE:
686 if (u.fontsource && v.u.fontsource)
687 return u.fontsource->stream->handle == v.u.fontsource->stream->handle;
688 return u.fontsource == v.u.fontsource;
689 case Type::PROPERTYPATH:
690 return *u.propertypath == *v.u.propertypath;
691 case Type::COLOR:
692 return !memcmp (u.color, v.u.color, sizeof (Color));
693 case Type::POINT:
694 return !memcmp (u.point, v.u.point, sizeof (Point));
695 case Type::RECT:
696 return !memcmp (u.rect, v.u.rect, sizeof (Rect));
697 case Type::SIZE:
698 return !memcmp (u.size, v.u.size, sizeof (Size));
699 case Type::REPEATBEHAVIOR:
700 // memcmp can't be used since the struct contains unassigned padding value
701 return *u.repeat == *v.u.repeat;
702 case Type::DURATION:
703 // memcmp can't be used since the struct contains unassigned padding value
704 return *u.duration == *v.u.duration;
705 case Type::KEYTIME:
706 // memcmp can't be used since the struct contains unassigned padding value
707 return *u.keytime == *v.u.keytime;
708 case Type::GRIDLENGTH:
709 return !memcmp (u.grid_length, v.u.grid_length, sizeof (GridLength));
710 case Type::THICKNESS:
711 return !memcmp (u.thickness, v.u.thickness, sizeof (Thickness));
712 case Type::CORNERRADIUS:
713 return !memcmp (u.corner, v.u.corner, sizeof (CornerRadius));
714 case Type::MANAGEDTYPEINFO:
715 return !memcmp (u.type_info, v.u.type_info, sizeof (ManagedTypeInfo));
716 case Type::URI:
717 if (!u.uri)
718 return !v.u.uri;
719 if (!v.u.uri)
720 return false;
721 return *u.uri == *v.u.uri;
722 case Type::MANAGED: {
723 // If we avoid the cast to 64bit uint, i don't know how to implement this sanity check.
724 //g_return_val_if_fail (a == (a & 0xFFFFFFFF) && b == (b & 0xFFFFFFFF), false);
725 guint32 a = GPOINTER_TO_INT (u.managed_object);
726 guint32 b = GPOINTER_TO_INT (v.u.managed_object);
727 return mono_gchandle_get_target (a) == mono_gchandle_get_target (b);
730 default:
731 return !memcmp (&u, &v.u, sizeof (u));
734 return true;
737 Value&
738 Value::operator= (const Value& other)
740 if (this != &other)
741 Copy (other);
742 return *this;
746 // This is invoked by managed code to free the contents of the value
748 void
749 value_free_value (Value* value)
751 value->FreeValue ();
754 void
755 value_free_value2 (Value *value)
757 value_free_value (value);
760 Value::~Value ()
762 FreeValue ();
765 #if DEBUG
766 char *
767 Value::GetName ()
769 GString *str = g_string_new ("");
771 switch (k) {
772 case Type::DOUBLE:
773 g_string_append_printf (str, "DOUBLE");
774 break;
775 case Type::STRING:
776 g_string_append_printf (str, "STRING");
777 break;
778 case Type::COLOR:
779 g_string_append_printf (str, "COLOR");
780 break;
781 case Type::POINT:
782 g_string_append_printf (str, "POINT");
783 break;
784 case Type::SIZE:
785 g_string_append_printf (str, "SIZE");
786 break;
787 case Type::RECT:
788 g_string_append_printf (str, "RECT");
789 break;
790 case Type::REPEATBEHAVIOR:
791 g_string_append_printf (str, "REPEATBEHAVIOR");
792 break;
793 case Type::THICKNESS:
794 g_string_append_printf (str, "THICKNESS");
795 break;
796 case Type::DURATION:
797 g_string_append_printf (str, "DURATION");
798 break;
799 case Type::KEYTIME:
800 g_string_append_printf (str, "KEYTIME");
801 break;
802 case Type::GRIDLENGTH:
803 g_string_append_printf (str, "GRIDLENGTH");
804 break;
805 default:
806 if (u.dependency_object)
807 g_string_append_printf (str, "[%s] [%p] %d", u.dependency_object->GetTypeName (), u.dependency_object, u.dependency_object->GetRefCount ());
808 else
809 g_string_append_printf (str, "UnknownType");
810 break;
813 return g_string_free (str, FALSE);
815 #endif