2009-12-03 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / value.cpp
blobdddd2a58ace6f504e46949cb63108f094b2c7321
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"
37 #define INCLUDED_MONO_HEADERS 1
38 #include "deployment.h"
39 #include "managedtypeinfo.h"
41 /**
42 * Value implementation
45 static const int NullFlag = 1;
47 Value*
48 Value::CreateUnrefPtr (EventObject* dob)
50 Value *result = new Value (dob);
51 LOG_VALUE ("unref Value [%p] %s\n", result, result->GetName());
52 if (dob)
53 dob->unref ();
54 return result;
57 Value
58 Value::CreateUnref (EventObject* dob)
60 Value result (dob);
61 LOG_VALUE ("unref Value [%p] %s\n", &result, result.GetName());
62 dob->unref ();
63 return result;
66 Value*
67 Value::Clone (Value *v, Types *types)
69 if (!v)
70 return NULL;
72 if (!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));
78 else {
79 return new Value (*v);
83 Type::Kind
84 Value::GetKind ()
86 return k;
89 bool
90 Value::GetIsNull ()
92 return (padding & NullFlag) == NullFlag;
95 void
96 Value::SetIsNull (bool isNull)
98 if (isNull)
99 padding |= NullFlag;
100 else
101 padding &= ~NullFlag;
104 void
105 Value::Init ()
107 padding = 0;
108 memset (&u, 0, sizeof (u));
109 SetIsNull (true);
112 Value::Value()
114 k = Type::INVALID;
115 Init ();
118 Value::Value (const Value& v)
120 Copy (v);
123 Value::Value (Type::Kind k)
125 Init();
126 this->k = k;
129 Value::Value(bool z)
131 Init ();
132 k = Type::BOOL;
133 u.i32 = z;
134 SetIsNull (false);
137 Value::Value (double d)
139 Init ();
140 k = Type::DOUBLE;
141 u.d = d;
142 SetIsNull (false);
145 Value::Value (gint64 i, Type::Kind as)
147 Init ();
148 k = as;
149 u.i64 = i;
150 SetIsNull (false);
153 Value::Value (gint32 i)
155 Init ();
156 k = Type::INT32;
157 u.i32 = i;
158 SetIsNull (false);
162 Value::Value (guint32 i)
164 Init ();
165 k = Type::UINT32;
166 u.ui32 = i;
167 SetIsNull (false);
170 Value::Value (gunichar c, Type::Kind as)
172 Init ();
173 k = as;
174 u.c = c;
175 SetIsNull (false);
178 Value::Value (Color c)
180 Init ();
181 k = Type::COLOR;
182 u.color = g_new (Color, 1);
183 *u.color = Color (c);
184 SetIsNull (false);
187 Value::Value (EventObject* obj)
189 Init ();
190 if (obj == NULL) {
191 k = Type::EVENTOBJECT;
193 else {
194 if (!Type::IsSubclassOf (obj->GetDeployment (), obj->GetObjectType (), Type::EVENTOBJECT)) {
195 g_warning ("creating invalid dependency object Value");
196 k = Type::INVALID;
197 u.dependency_object = NULL;
198 return;
200 k = obj->GetObjectType ();
201 LOG_VALUE (" ref Value [%p] %s\n", this, GetName());
202 obj->ref ();
203 SetIsNull (false);
205 u.dependency_object = obj;
208 Value::Value (FontFamily family)
210 Init ();
211 k = Type::FONTFAMILY;
212 u.fontfamily = g_new (FontFamily, 1);
213 u.fontfamily->source = g_strdup (family.source);
214 SetIsNull (false);
217 Value::Value (FontWeight weight)
219 Init ();
220 k = Type::FONTWEIGHT;
221 u.fontweight = g_new (FontWeight, 1);
222 u.fontweight->weight = weight.weight;
223 SetIsNull (false);
226 Value::Value (FontStretch stretch)
228 Init ();
229 k = Type::FONTSTRETCH;
230 u.fontstretch = g_new (FontStretch, 1);
231 u.fontstretch->stretch = stretch.stretch;
232 SetIsNull (false);
235 Value::Value (FontStyle style)
237 Init ();
238 k = Type::FONTSTYLE;
239 u.fontstyle = g_new (FontStyle, 1);
240 u.fontstyle->style = style.style;
241 SetIsNull (false);
244 Value::Value (FontSource source)
246 Init ();
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));
251 SetIsNull (false);
254 Value::Value (PropertyPath propertypath)
256 Init ();
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;
262 SetIsNull (false);
265 Value::Value (Type::Kind kind, void *npobj)
267 Init ();
268 k = kind;
269 u.managed_object = npobj;
270 SetIsNull (npobj == NULL);
273 Value::Value (Point pt)
275 Init ();
276 k = Type::POINT;
277 u.point = g_new (Point, 1);
278 *u.point = Point (pt);
279 SetIsNull (false);
282 Value::Value (Uri uri)
284 Init ();
285 k = Type::URI;
286 u.uri = g_new (Uri, 1);
287 Uri::Copy (&uri, u.uri);
288 SetIsNull (false);
291 Value::Value (Rect rect)
293 Init ();
294 k = Type::RECT;
295 u.rect = g_new (Rect, 1);
296 *u.rect = Rect (rect);
297 SetIsNull (false);
300 Value::Value (Size size)
302 Init ();
303 k = Type::SIZE;
304 u.size = g_new (Size, 1);
305 *u.size = Size (size);
306 SetIsNull (false);
309 Value::Value (RepeatBehavior repeat)
311 Init();
312 k = Type::REPEATBEHAVIOR;
313 u.repeat = g_new (RepeatBehavior, 1);
314 *u.repeat = RepeatBehavior (repeat);
315 SetIsNull (false);
318 Value::Value (Duration duration)
320 Init();
321 k = Type::DURATION;
322 u.duration = g_new (Duration, 1);
323 *u.duration = Duration (duration);
324 SetIsNull (false);
327 Value::Value (KeyTime keytime)
329 Init ();
330 k = Type::KEYTIME;
331 u.keytime = g_new (KeyTime, 1);
332 *u.keytime = KeyTime (keytime);
333 SetIsNull (false);
336 Value::Value (const char *s, bool take)
338 Init ();
339 k = Type::STRING;
341 u.s = take ? (char *) s : g_strdup (s);
342 SetIsNull (s == NULL);
345 Value::Value (GridLength grid_length)
347 Init ();
348 k = Type::GRIDLENGTH;
349 u.grid_length = g_new (GridLength, 1);
350 *u.grid_length = GridLength (grid_length);
351 SetIsNull (false);
354 Value::Value (Thickness thickness)
356 Init ();
357 k = Type::THICKNESS;
358 u.thickness = g_new (Thickness, 1);
359 *u.thickness = Thickness (thickness);
360 SetIsNull (false);
363 Value::Value (CornerRadius corner)
365 Init ();
366 k = Type::CORNERRADIUS;
367 u.corner = g_new (CornerRadius, 1);
368 *u.corner = CornerRadius (corner);
369 SetIsNull (false);
372 Value::Value (ManagedTypeInfo type_info)
374 Init ();
375 k = Type::MANAGEDTYPEINFO;
376 u.type_info = g_new0 (ManagedTypeInfo, 1);
377 *u.type_info = ManagedTypeInfo (type_info);
378 SetIsNull (false);
381 void
382 Value::Copy (const Value& v)
384 padding = v.padding;
385 k = v.k;
386 u = v.u;
388 SetIsNull (((Value&)v).GetIsNull());
390 /* make a copy of the string instead of just the pointer */
391 switch (k) {
392 case Type::STRING:
393 u.s = g_strdup (v.u.s);
394 break;
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);
400 break;
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));
407 break;
408 case Type::FONTWEIGHT:
409 if (v.u.fontweight) {
410 u.fontweight = g_new (FontWeight, 1);
411 *u.fontweight = *v.u.fontweight;
413 break;
414 case Type::FONTSTRETCH:
415 if (v.u.fontstretch) {
416 u.fontstretch = g_new (FontStretch, 1);
417 *u.fontstretch = *v.u.fontstretch;
419 break;
420 case Type::FONTSTYLE:
421 if (v.u.fontstyle) {
422 u.fontstyle = g_new (FontStyle, 1);
423 *u.fontstyle = *v.u.fontstyle;
425 break;
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;
433 break;
434 case Type::COLOR:
435 if (v.u.color) {
436 u.color = g_new (Color, 1);
437 *u.color = *v.u.color;
439 break;
440 case Type::POINT:
441 if (v.u.point) {
442 u.point = g_new (Point, 1);
443 *u.point = *v.u.point;
445 break;
446 case Type::RECT:
447 if (v.u.rect) {
448 u.rect = g_new (Rect, 1);
449 *u.rect = *v.u.rect;
451 break;
452 case Type::SIZE:
453 if (v.u.size) {
454 u.size = g_new (Size, 1);
455 *u.size = *v.u.size;
457 break;
458 case Type::URI:
459 if (v.u.uri) {
460 u.uri = g_new (Uri, 1);
461 Uri::Copy (v.u.uri, u.uri);
462 } else {
463 u.uri = NULL;
465 break;
466 case Type::REPEATBEHAVIOR:
467 if (v.u.repeat) {
468 u.repeat = g_new (RepeatBehavior, 1);
469 *u.repeat = *v.u.repeat;
471 break;
472 case Type::DURATION:
473 if (v.u.duration) {
474 u.duration = g_new (Duration, 1);
475 *u.duration = *v.u.duration;
477 break;
478 case Type::KEYTIME:
479 if (v.u.keytime) {
480 u.keytime = g_new (KeyTime, 1);
481 *u.keytime = *v.u.keytime;
483 break;
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;
489 break;
490 case Type::THICKNESS:
491 if (v.u.thickness) {
492 u.thickness = g_new (Thickness, 1);
493 *u.thickness = *v.u.thickness;
495 break;
496 case Type::CORNERRADIUS:
497 if (v.u.corner) {
498 u.corner = g_new (CornerRadius, 1);
499 *u.corner = *v.u.corner;
501 break;
502 case Type::MANAGEDTYPEINFO:
503 if (v.u.type_info) {
504 u.type_info = g_new0 (ManagedTypeInfo, 1);
505 *u.type_info = *v.u.type_info;
507 break;
508 default:
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 ();
513 break;
517 void
518 Value::FreeValue ()
520 switch (GetKind ()) {
521 case Type::STRING:
522 g_free (u.s);
523 break;
524 case Type::COLOR:
525 g_free (u.color);
526 break;
527 case Type::FONTFAMILY:
528 if (u.fontfamily) {
529 g_free (u.fontfamily->source);
530 g_free (u.fontfamily);
532 break;
533 case Type::FONTWEIGHT:
534 g_free (u.fontweight);
535 break;
536 case Type::FONTSTYLE:
537 g_free (u.fontstyle);
538 break;
539 case Type::FONTSTRETCH:
540 g_free (u.fontstretch);
541 break;
542 case Type::FONTSOURCE:
543 if (u.fontsource) {
544 g_free (u.fontsource->stream);
545 g_free (u.fontsource);
547 break;
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);
554 break;
555 case Type::POINT:
556 g_free (u.point);
557 break;
558 case Type::RECT:
559 g_free (u.rect);
560 break;
561 case Type::SIZE:
562 g_free (u.size);
563 break;
564 case Type::URI:
565 if (u.uri) {
566 u.uri->Free ();
567 g_free (u.uri);
569 break;
570 case Type::REPEATBEHAVIOR:
571 g_free (u.repeat);
572 break;
573 case Type::DURATION:
574 g_free (u.duration);
575 break;
576 case Type::KEYTIME:
577 g_free (u.keytime);
578 break;
579 case Type::GRIDLENGTH:
580 g_free (u.grid_length);
581 break;
582 case Type::THICKNESS:
583 g_free (u.thickness);
584 break;
585 case Type::CORNERRADIUS:
586 g_free (u.corner);
587 break;
588 case Type::MANAGEDTYPEINFO:
589 ManagedTypeInfo::Free (u.type_info);
590 break;
591 default:
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 ();
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 (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");
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 /* 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;
693 case Type::COLOR:
694 return *u.color == *v.u.color;
695 case Type::POINT:
696 return *u.point == *v.u.point;
697 case Type::RECT:
698 return *u.rect == *v.u.rect;
699 case Type::SIZE:
700 return *u.size == *v.u.size;
701 case Type::REPEATBEHAVIOR:
702 return *u.repeat == *v.u.repeat;
703 case Type::DURATION:
704 return *u.duration == *v.u.duration;
705 case Type::KEYTIME:
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;
715 case Type::URI:
716 if (!u.uri)
717 return !v.u.uri;
718 if (!v.u.uri)
719 return false;
720 return *u.uri == *v.u.uri;
721 case Type::DOUBLE:
722 return fabs (u.d - v.u.d) < DBL_EPSILON;
723 case Type::FLOAT:
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);
733 default:
734 return !memcmp (&u, &v.u, sizeof (u));
737 return true;
740 Value&
741 Value::operator= (const Value& other)
743 if (this != &other)
744 Copy (other);
745 return *this;
749 // This is invoked by managed code to free the contents of the value
751 void
752 value_free_value (Value* value)
754 value->FreeValue ();
757 void
758 value_free_value2 (Value *value)
760 value_free_value (value);
763 Value::~Value ()
765 FreeValue ();
768 #if DEBUG || LOGGING
769 char *
770 Value::GetName ()
772 GString *str = g_string_new ("");
774 switch (k) {
775 case Type::DOUBLE:
776 g_string_append_printf (str, "DOUBLE");
777 break;
778 case Type::STRING:
779 g_string_append_printf (str, "STRING");
780 break;
781 case Type::COLOR:
782 g_string_append_printf (str, "COLOR");
783 break;
784 case Type::POINT:
785 g_string_append_printf (str, "POINT");
786 break;
787 case Type::SIZE:
788 g_string_append_printf (str, "SIZE");
789 break;
790 case Type::RECT:
791 g_string_append_printf (str, "RECT");
792 break;
793 case Type::REPEATBEHAVIOR:
794 g_string_append_printf (str, "REPEATBEHAVIOR");
795 break;
796 case Type::THICKNESS:
797 g_string_append_printf (str, "THICKNESS");
798 break;
799 case Type::DURATION:
800 g_string_append_printf (str, "DURATION");
801 break;
802 case Type::KEYTIME:
803 g_string_append_printf (str, "KEYTIME");
804 break;
805 case Type::GRIDLENGTH:
806 g_string_append_printf (str, "GRIDLENGTH");
807 break;
808 default:
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 ());
811 else
812 g_string_append_printf (str, "UnknownType");
813 break;
816 return g_string_free (str, FALSE);
818 #endif