2009-09-12 Chris Toshok <toshok@ximian.com>
[moon.git] / src / value.cpp
blob4a15af8f95f143f86df66aafcd0d5a81f7f343c2
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::Init ()
104 padding = 0;
105 memset (&u, 0, sizeof (u));
106 SetIsNull (true);
109 Value::Value()
111 k = Type::INVALID;
112 Init ();
115 Value::Value (const Value& v)
117 Copy (v);
120 Value::Value (Type::Kind k)
122 Init();
123 this->k = k;
126 Value::Value(bool z)
128 Init ();
129 k = Type::BOOL;
130 u.i32 = z;
131 SetIsNull (false);
134 Value::Value (double d)
136 Init ();
137 k = Type::DOUBLE;
138 u.d = d;
139 SetIsNull (false);
142 Value::Value (gint64 i, Type::Kind as)
144 Init ();
145 k = as;
146 u.i64 = i;
147 SetIsNull (false);
150 Value::Value (gint32 i)
152 Init ();
153 k = Type::INT32;
154 u.i32 = i;
155 SetIsNull (false);
159 Value::Value (guint32 i)
161 Init ();
162 k = Type::UINT32;
163 u.ui32 = i;
164 SetIsNull (false);
167 Value::Value (gunichar c, Type::Kind as)
169 Init ();
170 k = as;
171 u.c = c;
172 SetIsNull (false);
175 Value::Value (Color c)
177 Init ();
178 k = Type::COLOR;
179 u.color = g_new (Color, 1);
180 *u.color = Color (c);
181 SetIsNull (false);
184 Value::Value (EventObject* obj)
186 Init ();
187 if (obj == NULL) {
188 k = Type::EVENTOBJECT;
190 else {
191 if (!Type::IsSubclassOf (obj->GetObjectType (), Type::EVENTOBJECT)) {
192 g_warning ("creating invalid dependency object Value");
193 k = Type::INVALID;
194 u.dependency_object = NULL;
195 return;
197 k = obj->GetObjectType ();
198 LOG_VALUE (" ref Value [%p] %s\n", this, GetName());
199 obj->ref ();
200 SetIsNull (false);
202 u.dependency_object = obj;
205 Value::Value (FontFamily family)
207 Init ();
208 k = Type::FONTFAMILY;
209 u.fontfamily = g_new (FontFamily, 1);
210 u.fontfamily->source = g_strdup (family.source);
211 SetIsNull (false);
214 Value::Value (FontWeight weight)
216 Init ();
217 k = Type::FONTWEIGHT;
218 u.fontweight = g_new (FontWeight, 1);
219 u.fontweight->weight = weight.weight;
220 SetIsNull (false);
223 Value::Value (FontStretch stretch)
225 Init ();
226 k = Type::FONTSTRETCH;
227 u.fontstretch = g_new (FontStretch, 1);
228 u.fontstretch->stretch = stretch.stretch;
229 SetIsNull (false);
232 Value::Value (FontStyle style)
234 Init ();
235 k = Type::FONTSTYLE;
236 u.fontstyle = g_new (FontStyle, 1);
237 u.fontstyle->style = style.style;
238 SetIsNull (false);
241 Value::Value (FontSource source)
243 Init ();
244 k = Type::FONTSOURCE;
245 u.fontsource = g_new (FontSource, 1);
246 u.fontsource->stream = g_new (ManagedStreamCallbacks, 1);
247 memcpy (u.fontsource->stream, source.stream, sizeof (ManagedStreamCallbacks));
248 SetIsNull (false);
251 Value::Value (PropertyPath propertypath)
253 Init ();
254 k = Type::PROPERTYPATH;
255 u.propertypath = g_new (PropertyPath, 1);
256 u.propertypath->path = g_strdup (propertypath.path);
257 u.propertypath->expanded_path = g_strdup (propertypath.expanded_path);
258 u.propertypath->property = propertypath.property;
259 SetIsNull (false);
262 Value::Value (Type::Kind kind, void *npobj)
264 Init ();
265 k = kind;
266 u.managed_object = npobj;
267 SetIsNull (npobj == NULL);
270 Value::Value (Point pt)
272 Init ();
273 k = Type::POINT;
274 u.point = g_new (Point, 1);
275 *u.point = Point (pt);
276 SetIsNull (false);
279 Value::Value (Uri uri)
281 Init ();
282 k = Type::URI;
283 u.uri = g_new (Uri, 1);
284 Uri::Copy (&uri, u.uri);
285 SetIsNull (false);
288 Value::Value (Rect rect)
290 Init ();
291 k = Type::RECT;
292 u.rect = g_new (Rect, 1);
293 *u.rect = Rect (rect);
294 SetIsNull (false);
297 Value::Value (Size size)
299 Init ();
300 k = Type::SIZE;
301 u.size = g_new (Size, 1);
302 *u.size = Size (size);
303 SetIsNull (false);
306 Value::Value (RepeatBehavior repeat)
308 Init();
309 k = Type::REPEATBEHAVIOR;
310 u.repeat = g_new (RepeatBehavior, 1);
311 *u.repeat = RepeatBehavior (repeat);
312 SetIsNull (false);
315 Value::Value (Duration duration)
317 Init();
318 k = Type::DURATION;
319 u.duration = g_new (Duration, 1);
320 *u.duration = Duration (duration);
321 SetIsNull (false);
324 Value::Value (KeyTime keytime)
326 Init ();
327 k = Type::KEYTIME;
328 u.keytime = g_new (KeyTime, 1);
329 *u.keytime = KeyTime (keytime);
330 SetIsNull (false);
333 Value::Value (const char *s, bool take)
335 Init ();
336 k = Type::STRING;
338 u.s = take ? (char *) s : g_strdup (s);
339 SetIsNull (s == NULL);
342 Value::Value (GridLength grid_length)
344 Init ();
345 k = Type::GRIDLENGTH;
346 u.grid_length = g_new (GridLength, 1);
347 *u.grid_length = GridLength (grid_length);
348 SetIsNull (false);
351 Value::Value (Thickness thickness)
353 Init ();
354 k = Type::THICKNESS;
355 u.thickness = g_new (Thickness, 1);
356 *u.thickness = Thickness (thickness);
357 SetIsNull (false);
360 Value::Value (CornerRadius corner)
362 Init ();
363 k = Type::CORNERRADIUS;
364 u.corner = g_new (CornerRadius, 1);
365 *u.corner = CornerRadius (corner);
366 SetIsNull (false);
369 Value::Value (ManagedTypeInfo type_info)
371 Init ();
372 k = Type::MANAGEDTYPEINFO;
373 u.type_info = g_new (ManagedTypeInfo, 1);
374 *u.type_info = ManagedTypeInfo (type_info);
375 SetIsNull (false);
378 void
379 Value::Copy (const Value& v)
381 padding = v.padding;
382 k = v.k;
383 u = v.u;
385 SetIsNull (((Value&)v).GetIsNull());
387 /* make a copy of the string instead of just the pointer */
388 switch (k) {
389 case Type::STRING:
390 u.s = g_strdup (v.u.s);
391 break;
392 case Type::FONTFAMILY:
393 if (v.u.fontfamily) {
394 u.fontfamily = g_new (FontFamily, 1);
395 u.fontfamily->source = g_strdup (v.u.fontfamily->source);
397 break;
398 case Type::FONTSOURCE:
399 if (v.u.fontsource) {
400 u.fontsource = g_new (FontSource, 1);
401 u.fontsource->stream = g_new (ManagedStreamCallbacks, 1);
402 memcpy (u.fontsource->stream, v.u.fontsource->stream, sizeof (ManagedStreamCallbacks));
404 break;
405 case Type::FONTWEIGHT:
406 if (v.u.fontweight) {
407 u.fontweight = g_new (FontWeight, 1);
408 *u.fontweight = *v.u.fontweight;
410 break;
411 case Type::FONTSTRETCH:
412 if (v.u.fontstretch) {
413 u.fontstretch = g_new (FontStretch, 1);
414 *u.fontstretch = *v.u.fontstretch;
416 break;
417 case Type::FONTSTYLE:
418 if (v.u.fontstyle) {
419 u.fontstyle = g_new (FontStyle, 1);
420 *u.fontstyle = *v.u.fontstyle;
422 break;
423 case Type::PROPERTYPATH:
424 if (v.u.propertypath) {
425 u.propertypath = g_new (PropertyPath, 1);
426 u.propertypath->path = g_strdup (v.u.propertypath->path);
427 u.propertypath->expanded_path = g_strdup (v.u.propertypath->expanded_path);
428 u.propertypath->property = v.u.propertypath->property;
430 break;
431 case Type::COLOR:
432 if (v.u.color) {
433 u.color = g_new (Color, 1);
434 *u.color = *v.u.color;
436 break;
437 case Type::POINT:
438 if (v.u.point) {
439 u.point = g_new (Point, 1);
440 *u.point = *v.u.point;
442 break;
443 case Type::RECT:
444 if (v.u.rect) {
445 u.rect = g_new (Rect, 1);
446 *u.rect = *v.u.rect;
448 break;
449 case Type::SIZE:
450 if (v.u.size) {
451 u.size = g_new (Size, 1);
452 *u.size = *v.u.size;
454 break;
455 case Type::URI:
456 if (v.u.uri) {
457 u.uri = g_new (Uri, 1);
458 Uri::Copy (v.u.uri, u.uri);
459 } else {
460 u.uri = NULL;
462 break;
463 case Type::REPEATBEHAVIOR:
464 if (v.u.repeat) {
465 u.repeat = g_new (RepeatBehavior, 1);
466 *u.repeat = *v.u.repeat;
468 break;
469 case Type::DURATION:
470 if (v.u.duration) {
471 u.duration = g_new (Duration, 1);
472 *u.duration = *v.u.duration;
474 break;
475 case Type::KEYTIME:
476 if (v.u.keytime) {
477 u.keytime = g_new (KeyTime, 1);
478 *u.keytime = *v.u.keytime;
480 break;
481 case Type::GRIDLENGTH:
482 if (v.u.grid_length) {
483 u.grid_length = g_new (GridLength, 1);
484 *u.grid_length = *v.u.grid_length;
486 break;
487 case Type::THICKNESS:
488 if (v.u.thickness) {
489 u.thickness = g_new (Thickness, 1);
490 *u.thickness = *v.u.thickness;
492 break;
493 case Type::CORNERRADIUS:
494 if (v.u.corner) {
495 u.corner = g_new (CornerRadius, 1);
496 *u.corner = *v.u.corner;
498 break;
499 case Type::MANAGEDTYPEINFO:
500 if (v.u.type_info) {
501 u.type_info = g_new (ManagedTypeInfo, 1);
502 *u.type_info = *v.u.type_info;
504 break;
505 default:
506 if (Is (Type::EVENTOBJECT) && u.dependency_object) {
507 LOG_VALUE (" ref Value [%p] %s\n", this, GetName());
508 u.dependency_object->ref ();
510 break;
514 void
515 Value::FreeValue ()
517 switch (GetKind ()) {
518 case Type::STRING:
519 g_free (u.s);
520 break;
521 case Type::COLOR:
522 g_free (u.color);
523 break;
524 case Type::FONTFAMILY:
525 if (u.fontfamily) {
526 g_free (u.fontfamily->source);
527 g_free (u.fontfamily);
529 break;
530 case Type::FONTWEIGHT:
531 g_free (u.fontweight);
532 break;
533 case Type::FONTSTYLE:
534 g_free (u.fontstyle);
535 break;
536 case Type::FONTSTRETCH:
537 g_free (u.fontstretch);
538 break;
539 case Type::FONTSOURCE:
540 if (u.fontsource) {
541 g_free (u.fontsource->stream);
542 g_free (u.fontsource);
544 break;
545 case Type::PROPERTYPATH:
546 if (u.propertypath) {
547 g_free (u.propertypath->path);
548 g_free (u.propertypath->expanded_path);
549 g_free (u.propertypath);
551 break;
552 case Type::POINT:
553 g_free (u.point);
554 break;
555 case Type::RECT:
556 g_free (u.rect);
557 break;
558 case Type::SIZE:
559 g_free (u.size);
560 break;
561 case Type::URI:
562 if (u.uri) {
563 u.uri->Free ();
564 g_free (u.uri);
566 break;
567 case Type::REPEATBEHAVIOR:
568 g_free (u.repeat);
569 break;
570 case Type::DURATION:
571 g_free (u.duration);
572 break;
573 case Type::KEYTIME:
574 g_free (u.keytime);
575 break;
576 case Type::GRIDLENGTH:
577 g_free (u.grid_length);
578 break;
579 case Type::THICKNESS:
580 g_free (u.thickness);
581 break;
582 case Type::CORNERRADIUS:
583 g_free (u.corner);
584 break;
585 default:
586 if (Is (Type::EVENTOBJECT) && u.dependency_object) {
587 LOG_VALUE ("unref Value [%p] %s\n", this, GetName());
588 u.dependency_object->unref ();
593 char *
594 Value::ToString ()
596 GString *str = g_string_new ("");
598 switch (k) {
599 case Type::DOUBLE:
600 g_string_append_printf (str, "{ %f }", u.d);
601 break;
602 case Type::STRING:
603 g_string_append (str, u.s);
604 break;
605 case Type::COLOR:
606 g_string_append_printf (str, "{%g/%g/%g/%g}", u.color->r, u.color->g, u.color->b, u.color->a);
607 break;
608 case Type::POINT:
609 g_string_append_printf (str, "{ %g, %g }", (u.point)->x, (u.point)->y);
610 break;
611 case Type::SIZE:
612 g_string_append_printf (str, "{ %g, %g }", (u.size)->width, (u.size)->height);
613 break;
614 case Type::RECT:
615 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);
616 break;
617 case Type::REPEATBEHAVIOR:
618 if (u.repeat->IsForever ())
619 g_string_append (str, "{repeat=forever}");
620 else if ((u.repeat)->HasDuration ())
621 g_string_append_printf (str, "{repeat=duration}");
622 else if ((u.repeat)->HasCount ())
623 g_string_append_printf (str, "{repeat=count %g}", (u.repeat)->GetCount ());
624 break;
625 case Type::THICKNESS:
626 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);
627 break;
628 case Type::DURATION:
629 g_string_append_printf (str, "{duration/TODO}");
630 break;
631 case Type::KEYTIME:
632 g_string_append_printf (str, "{keytime/TODO}");
633 break;
634 case Type::GRIDLENGTH:
635 g_string_append_printf (str, "{gridlength value:%.2f type:%d}", u.grid_length->val, u.grid_length->type);
636 break;
637 default:
638 if (Is (Type::EVENTOBJECT) && u.dependency_object)
639 g_string_append_printf (str, "[%s <%s>]", u.dependency_object->GetTypeName (), Is (Type::DEPENDENCY_OBJECT) ? AsDependencyObject ()->GetName () : "no name");
640 else
641 g_string_append_printf (str, "UnknownType");
642 break;
645 return g_string_free (str, FALSE);
648 bool
649 Value::operator!= (const Value &v) const
651 return !(*this == v);
654 bool
655 Value::operator== (const Value &v) const
657 if (k != v.k)
658 return false;
660 if (padding != v.padding)
661 return false;
663 switch (k) {
664 case Type::STRING:
665 if (u.s == NULL){
666 return v.u.s == NULL;
667 } else if (v.u.s == NULL)
668 return FALSE;
670 return !strcmp (u.s, v.u.s);
671 case Type::FONTFAMILY:
672 return *u.fontfamily == *v.u.fontfamily;
673 case Type::FONTWEIGHT:
674 return *u.fontweight == *v.u.fontweight;
675 case Type::FONTSTYLE:
676 return *u.fontstyle == *v.u.fontstyle;
677 case Type::FONTSTRETCH:
678 return *u.fontstretch == *v.u.fontstretch;
679 case Type::FONTSOURCE:
680 if (u.fontsource && v.u.fontsource)
681 return u.fontsource->stream->handle == v.u.fontsource->stream->handle;
682 return u.fontsource == v.u.fontsource;
683 case Type::PROPERTYPATH:
684 return *u.propertypath == *v.u.propertypath;
685 case Type::COLOR:
686 return !memcmp (u.color, v.u.color, sizeof (Color));
687 case Type::POINT:
688 return !memcmp (u.point, v.u.point, sizeof (Point));
689 case Type::RECT:
690 return !memcmp (u.rect, v.u.rect, sizeof (Rect));
691 case Type::SIZE:
692 return !memcmp (u.size, v.u.size, sizeof (Size));
693 case Type::REPEATBEHAVIOR:
694 // memcmp can't be used since the struct contains unassigned padding value
695 return *u.repeat == *v.u.repeat;
696 case Type::DURATION:
697 // memcmp can't be used since the struct contains unassigned padding value
698 return *u.duration == *v.u.duration;
699 case Type::KEYTIME:
700 // memcmp can't be used since the struct contains unassigned padding value
701 return *u.keytime == *v.u.keytime;
702 case Type::GRIDLENGTH:
703 return !memcmp (u.grid_length, v.u.grid_length, sizeof (GridLength));
704 case Type::THICKNESS:
705 return !memcmp (u.thickness, v.u.thickness, sizeof (Thickness));
706 case Type::CORNERRADIUS:
707 return !memcmp (u.corner, v.u.corner, sizeof (CornerRadius));
708 case Type::MANAGEDTYPEINFO:
709 return !memcmp (u.type_info, v.u.type_info, sizeof (ManagedTypeInfo));
710 case Type::URI:
711 if (!u.uri)
712 return !v.u.uri;
713 if (!v.u.uri)
714 return false;
715 return *u.uri == *v.u.uri;
716 case Type::MANAGED: {
717 // If we avoid the cast to 64bit uint, i don't know how to implement this sanity check.
718 //g_return_val_if_fail (a == (a & 0xFFFFFFFF) && b == (b & 0xFFFFFFFF), false);
719 guint32 a = GPOINTER_TO_INT (u.managed_object);
720 guint32 b = GPOINTER_TO_INT (v.u.managed_object);
721 return mono_gchandle_get_target (a) == mono_gchandle_get_target (b);
724 default:
725 return !memcmp (&u, &v.u, sizeof (u));
728 return true;
731 Value&
732 Value::operator= (const Value& other)
734 if (this != &other)
735 Copy (other);
736 return *this;
740 // This is invoked by managed code to free the contents of the value
742 void
743 value_free_value (Value* value)
745 value->FreeValue ();
748 void
749 value_free_value2 (Value *value)
751 value_free_value (value);
754 Value::~Value ()
756 FreeValue ();
759 #if DEBUG
760 char *
761 Value::GetName ()
763 GString *str = g_string_new ("");
765 switch (k) {
766 case Type::DOUBLE:
767 g_string_append_printf (str, "DOUBLE");
768 break;
769 case Type::STRING:
770 g_string_append_printf (str, "STRING");
771 break;
772 case Type::COLOR:
773 g_string_append_printf (str, "COLOR");
774 break;
775 case Type::POINT:
776 g_string_append_printf (str, "POINT");
777 break;
778 case Type::SIZE:
779 g_string_append_printf (str, "SIZE");
780 break;
781 case Type::RECT:
782 g_string_append_printf (str, "RECT");
783 break;
784 case Type::REPEATBEHAVIOR:
785 g_string_append_printf (str, "REPEATBEHAVIOR");
786 break;
787 case Type::THICKNESS:
788 g_string_append_printf (str, "THICKNESS");
789 break;
790 case Type::DURATION:
791 g_string_append_printf (str, "DURATION");
792 break;
793 case Type::KEYTIME:
794 g_string_append_printf (str, "KEYTIME");
795 break;
796 case Type::GRIDLENGTH:
797 g_string_append_printf (str, "GRIDLENGTH");
798 break;
799 default:
800 if (u.dependency_object)
801 g_string_append_printf (str, "[%s] [%p] %d", u.dependency_object->GetTypeName (), u.dependency_object, u.dependency_object->GetRefCount ());
802 else
803 g_string_append_printf (str, "UnknownType");
804 break;
807 return g_string_free (str, FALSE);
809 #endif