2009-12-07 Rolf Bjarne Kvinge <RKvinge@novell.com>
[moon.git] / src / xaml.cpp
blob7e00b1bd6ffab6a45ca7e8bfc5fa882e58c03eb8
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * xaml.cpp: xaml parser
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 <glib.h>
17 #include <string.h>
18 #include <malloc.h>
19 #include <stdlib.h>
20 #include <stdarg.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <errno.h>
25 #include <expat.h>
27 #include "xaml.h"
28 #include "error.h"
29 #include "shape.h"
30 #include "animation.h"
31 #include "bitmapimage.h"
32 #include "geometry.h"
33 #include "projection.h"
34 #include "textblock.h"
35 #include "glyphs.h"
36 #include "media.h"
37 #include "list.h"
38 #include "rect.h"
39 #include "point.h"
40 #include "canvas.h"
41 #include "color.h"
42 #include "namescope.h"
43 #include "stylus.h"
44 #include "runtime.h"
45 #include "utils.h"
46 #include "control.h"
47 #include "template.h"
48 #include "style.h"
49 #include "application.h"
50 #include "thickness.h"
51 #include "cornerradius.h"
52 #include "deployment.h"
53 #include "grid.h"
54 #include "deepzoomimagetilesource.h"
55 #include "managedtypeinfo.h"
56 #include "bitmapcache.h"
58 class XamlElementInfo;
59 class XamlElementInstance;
60 class XamlParserInfo;
61 class XamlNamespace;
62 class DefaultNamespace;
63 class XNamespace;
64 class XmlNamespace;
65 class PrimitiveNamespace;
66 class MCIgnorableNamespace;
67 class XamlElementInfoNative;
68 class XamlElementInstanceNative;
69 class XamlElementInstanceValueType;
70 class XamlElementInfoEnum;
71 class XamlElementInstanceEnum;
72 class XamlElementInfoManaged;
73 class XamlElementInstanceManaged;
74 class XamlElementInfoImportedManaged;
75 class XamlElementInstanceTemplate;
77 #define INTERNAL_IGNORABLE_ELEMENT "MoonlightInternalIgnorableElement"
79 #define IS_NULL_OR_EMPTY(str) (!str || (*str == 0))
81 static DefaultNamespace *default_namespace = NULL;
82 static XNamespace *x_namespace = NULL;
83 static XmlNamespace *xml_namespace = NULL;
85 static const char* default_namespace_names [] = {
86 "http://schemas.microsoft.com/winfx/2006/xaml/presentation",
87 "http://schemas.microsoft.com/client/2007",
88 "http://schemas.microsoft.com/xps/2005/06",
89 "http://schemas.microsoft.com/client/2007/deployment",
90 NULL
93 #define X_NAMESPACE_URI "http://schemas.microsoft.com/winfx/2006/xaml"
94 #define XML_NAMESPACE_URI "http://www.w3.org/XML/1998/namespace"
95 #define PRIMITIVE_NAMESPACE_URI "clr-namespace:System;assembly=mscorlib"
96 #define MC_IGNORABLE_NAMESPACE_URI "http://schemas.openxmlformats.org/markup-compatibility/2006"
99 static bool value_from_str_with_parser (XamlParserInfo *p, Type::Kind type, const char *prop_name, const char *str, Value **v, bool *v_set);
100 static bool dependency_object_set_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *property, XamlElementInstance *value, bool raise_errors);
101 static bool set_managed_attached_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *property, XamlElementInstance *value);
102 static void dependency_object_add_child (XamlParserInfo *p, XamlElementInstance *parent, XamlElementInstance *child, bool fail_if_no_prop);
103 static void dependency_object_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr);
104 static void value_type_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr);
105 static bool element_begins_buffering (Type::Kind kind);
106 static bool is_managed_kind (Type::Kind kind);
107 static bool kind_requires_managed_load (Type::Kind kind);
108 static bool is_legal_top_level_kind (Type::Kind kind);
109 static Value *lookup_resource_dictionary (ResourceDictionary *rd, const char *name, bool *exists);
110 static void parser_error (XamlParserInfo *p, const char *el, const char *attr, int error_code, const char *format, ...);
111 static gboolean namespace_for_prefix (gpointer key, gpointer value, gpointer user_data);
113 static XamlElementInfo *create_element_info_from_imported_managed_type (XamlParserInfo *p, const char *name, const char **attr, bool create);
114 static void destroy_created_namespace (gpointer data, gpointer user_data);
116 enum BufferMode {
117 BUFFER_MODE_TEMPLATE,
118 BUFFER_MODE_IGNORE
122 class XamlNamespace {
123 public:
124 const char *name;
125 bool is_ignored;
126 GSList *prefixes;
128 XamlNamespace ()
130 name = NULL;
131 prefixes = NULL;
132 is_ignored = false;
135 ~XamlNamespace ()
137 if (prefixes) {
138 GSList *w = prefixes;
140 while (w) {
141 char *p = (char *) w->data;
143 g_free (p);
144 w = w->next;
147 g_slist_free (prefixes);
148 prefixes = NULL;
152 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create) = 0;
153 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value) = 0;
156 virtual const char* GetUri () = 0;
158 void AddPrefix (const char *prefix)
160 prefixes = g_slist_append (prefixes, g_strdup (prefix));
163 bool HasPrefix (const char *prefix)
165 return g_slist_find_custom (prefixes, prefix, (GCompareFunc) strcmp) != NULL;
168 GSList* GetPrefixes ()
170 return prefixes;
174 void
175 add_namespace_data (gpointer key, gpointer value, gpointer user_data)
177 XamlNamespace *ns = (XamlNamespace *) value;
178 GHashTable *table = (GHashTable *) user_data;
180 if ((void *)ns != (void *)default_namespace) {
181 GSList *p = ns->GetPrefixes ();
183 while (p) {
184 g_hash_table_insert (table, g_strdup ((char *)p->data), g_strdup (ns->GetUri ()));
186 p = p->next;
191 void
192 add_namespace_to_ignorable (gpointer key, gpointer value, gpointer user_data)
194 char *prefix = (char *) key;
195 char *uri = (char *) value;
196 GString *str = (GString *) user_data;
198 g_string_append_printf (str, "xmlns:%s=\"%s\" ", prefix, uri);
201 class XamlContextInternal {
203 public:
204 Value *top_element;
205 FrameworkTemplate *template_parent;
206 GHashTable *imported_namespaces;
207 XamlLoaderCallbacks callbacks;
208 GSList *resources;
209 XamlContextInternal *parent_context;
211 DependencyObject *source;
213 XamlContextInternal (XamlLoaderCallbacks callbacks, Value *top_element, FrameworkTemplate *template_parent, GHashTable *namespaces, GSList *resources, XamlContextInternal *parent_context)
215 this->callbacks = callbacks;
216 this->top_element = new Value (*top_element);
217 this->template_parent = template_parent;
218 this->resources = resources;
219 this->parent_context = parent_context;
221 if (this->callbacks.create_gchandle)
222 this->callbacks.create_gchandle ();
223 imported_namespaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
224 g_hash_table_foreach (namespaces, add_namespace_data, imported_namespaces);
228 ~XamlContextInternal ()
230 if (imported_namespaces)
231 g_hash_table_destroy (imported_namespaces);
232 if (resources)
233 g_slist_free (resources);
234 delete top_element;
237 char *CreateIgnorableTagOpen ()
239 GString *str = g_string_new ("<" INTERNAL_IGNORABLE_ELEMENT " ");
240 g_hash_table_foreach (imported_namespaces, add_namespace_to_ignorable, str);
242 str = g_string_append (str, ">");
244 char *res = str->str;
245 g_string_free (str, false);
247 return res;
250 char *CreateIgnorableTagClose ()
252 return g_strdup ("</" INTERNAL_IGNORABLE_ELEMENT ">");
255 bool LookupNamedItem (const char* name, Value **v)
257 if (!resources)
258 return NULL;
260 bool exists = false;
261 GSList *walk = resources;
262 while (walk) {
263 DependencyObject *dob = (DependencyObject*)walk->data;
264 if (dob->Is (Type::RESOURCE_DICTIONARY))
265 *v = lookup_resource_dictionary ((ResourceDictionary *) walk->data, name, &exists);
266 else /* dob->Is (Type::FRAMEWORKELEMENT) */ {
267 ResourceDictionary *rd = dob->GetValue (UIElement::ResourcesProperty)->AsResourceDictionary();
268 *v = lookup_resource_dictionary (rd, name, &exists);
271 if (exists)
272 break;
273 walk = walk->next;
276 if (exists)
277 return exists;
278 else if (!parent_context)
279 return false;
281 return parent_context->LookupNamedItem (name, v);
284 void SetTemplateBindingSource (DependencyObject *source)
286 this->source = source;
289 DependencyObject* GetTemplateBindingSource ()
291 return source;
296 XamlContext::XamlContext (XamlContextInternal *internal)
298 this->internal = internal;
301 XamlContext::~XamlContext ()
303 delete internal;
306 void
307 XamlContext::SetTemplateBindingSource (DependencyObject *source)
309 internal->SetTemplateBindingSource (source);
312 DependencyObject*
313 XamlContext::GetTemplateBindingSource ()
315 return internal->GetTemplateBindingSource ();
318 class XamlElementInfo {
319 protected:
320 Type::Kind kind;
321 Type::Kind property_owner_kind;
322 bool cdata_verbatim;
324 public:
325 XamlElementInfo *parent;
326 const char *name;
327 const char *xmlns;
329 XamlElementInfo (const char *xmlns, const char *name, Type::Kind kind)
331 this->parent = NULL;
332 this->kind = kind;
333 this->name = name;
334 this->xmlns = xmlns;
335 this->cdata_verbatim = false;
337 this->property_owner_kind = Type::INVALID;
340 ~XamlElementInfo ()
344 virtual Type::Kind GetKind () { return kind; }
346 virtual void SetPropertyOwnerKind (Type::Kind value) { property_owner_kind = value; }
347 virtual Type::Kind GetPropertyOwnerKind () { return property_owner_kind; }
349 virtual const char *GetContentProperty (XamlParserInfo *p)
351 Type *t = Type::Find (Deployment::GetCurrent (), kind);
352 if (t)
353 return t->GetContentPropertyName ();
354 return NULL;
357 void SetIsCDataVerbatim (bool flag)
359 cdata_verbatim = flag;
362 bool IsCDataVerbatim ()
364 return cdata_verbatim;
367 virtual bool RequiresManagedSet () { return false; }
369 virtual XamlElementInstance *CreateElementInstance (XamlParserInfo *p) = 0;
370 virtual XamlElementInstance *CreateWrappedElementInstance (XamlParserInfo *p, Value *o) = 0;
371 virtual XamlElementInstance *CreatePropertyElementInstance (XamlParserInfo *p, const char *name) = 0;
375 struct DelayedProperty {
376 char *xmlns;
377 char *name;
378 Value *value;
380 DelayedProperty (const char *xmlns, const char *name, const Value *value)
382 this->xmlns = g_strdup (xmlns);
383 this->name = g_strdup (name);
384 this->value = new Value (*value);
387 ~DelayedProperty ()
389 g_free (xmlns);
390 g_free (name);
391 delete value;
395 static void
396 free_property_list (GSList *list)
398 GSList *walk = list;
400 while (walk) {
401 DelayedProperty *prop = (DelayedProperty *) walk->data;
403 delete prop;
404 walk = walk->next;
407 g_slist_free (list);
410 class XamlElementInstance : public List::Node {
412 protected:
413 DependencyObject *item;
414 Value *value;
415 bool cleanup_value;
416 GSList *delayed_properties;
418 public:
419 const char *element_name;
420 XamlElementInfo *info;
422 XamlElementInstance *parent;
423 List *children;
425 enum ElementType {
426 ELEMENT,
427 PROPERTY,
428 INVALID
431 int element_type;
432 bool requires_managed;
433 char *x_key;
434 char *x_name;
436 GHashTable *set_properties;
438 XamlElementInstance (XamlElementInfo *info, const char* element_name, ElementType type, bool requires_managed = false)
440 this->element_name = element_name;
441 this->set_properties = NULL;
442 this->element_type = type;
443 this->parent = NULL;
444 this->info = info;
445 this->item = NULL;
446 this->value = NULL;
447 this->x_key = NULL;
448 this->x_name = NULL;
449 this->cleanup_value = true;
450 this->requires_managed = requires_managed;
451 this->delayed_properties = NULL;
453 children = new List ();
456 virtual ~XamlElementInstance ()
458 children->Clear (true);
459 delete children;
460 delete info;
462 g_free (x_key);
463 g_free (x_name);
465 if (cleanup_value)
466 delete value;
468 if (set_properties)
469 g_hash_table_destroy (set_properties);
471 if (element_name && element_type == PROPERTY)
472 g_free ((void*) element_name);
474 free_property_list (delayed_properties);
477 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) = 0;
478 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value) = 0;
479 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) = 0;
480 virtual void SetAttributes (XamlParserInfo *p, const char **attr) = 0;
482 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value);
483 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value);
486 char *GetKey () { return x_key; }
487 char *GetName () { return x_name; }
489 void SetName (XamlParserInfo *p, const char *name)
491 this->x_name = g_strdup (name);
494 void SetKey (XamlParserInfo *p, const char *key)
496 this->x_key = g_strdup (key);
499 virtual bool IsDependencyObject ()
501 return true;
504 virtual bool SetUnknownAttribute (XamlParserInfo *p, const char* name, const char* value);
506 void SetValue (Value *v)
508 if (value && cleanup_value)
509 delete value;
510 value = v;
513 virtual Value *GetAsValue ()
515 if (!value) {
516 value = new Value (item);
518 return value;
521 virtual DependencyObject *GetAsDependencyObject ()
523 return item;
526 virtual void SetDependencyObject (DependencyObject *value)
528 item = value;
531 virtual void* GetManagedPointer ()
533 return item;
536 virtual Value* GetParentPointer ()
538 XamlElementInstance *walk = parent;
539 while (walk && walk->element_type != XamlElementInstance::ELEMENT)
540 walk = walk->parent;
542 if (!walk)
543 return NULL;
545 return walk->GetAsValue ();
548 virtual bool IsTemplate ()
550 return false;
553 virtual XamlElementInfo* FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot);
555 void SetDelayedProperties (XamlParserInfo *p);
557 void DelaySetProperty (const char *xmlns, const char *name, const Value *value)
559 DelayedProperty *prop = new DelayedProperty (xmlns, name, value);
561 delayed_properties = g_slist_append (delayed_properties, prop);
564 bool IsPropertySet (const char *name)
566 if (!set_properties)
567 return false;
569 return g_hash_table_lookup (set_properties, name) != NULL;
572 void MarkPropertyAsSet (const char *name)
574 if (!set_properties)
575 set_properties = g_hash_table_new (g_str_hash, g_str_equal);
577 g_hash_table_insert (set_properties, (void *) name, GINT_TO_POINTER (TRUE));
581 void
582 unref_xaml_element (gpointer data, gpointer user_data)
584 DependencyObject* dob = (DependencyObject*) data;
585 //printf ("unref_xaml_element: %i\n", dob->id);
586 if (dob)
587 dob->unref ();
590 class XamlParserInfo {
591 public:
592 XML_Parser parser;
594 const char *file_name;
596 NameScope *namescope;
597 XamlElementInstance *top_element;
598 XamlNamespace *current_namespace;
599 XamlElementInstance *current_element;
600 const char *next_element;
601 Deployment *deployment;
603 GHashTable *namespace_map;
604 bool cdata_content;
605 GString *cdata;
607 bool implicit_default_namespace;
609 ParserErrorEventArgs *error_args;
611 XamlLoader *loader;
615 // If set, this is used to hydrate an existing object, not to create a new toplevel one
617 Value *hydrate_expecting;
618 bool hydrating;
620 char* buffer_until_element;
621 int buffer_depth;
622 BufferMode buffer_mode;
623 GString *buffer;
624 bool validate_templates;
626 private:
627 GList *created_elements;
628 GList *created_namespaces;
629 const char* xml_buffer;
630 int multi_buffer_offset;
631 int xml_buffer_start_index;
633 public:
634 XamlParserInfo (XML_Parser parser, const char *file_name)
636 this->deployment = Deployment::GetCurrent ();
637 this->parser = parser;
638 this->file_name = file_name;
639 this->namescope = new NameScope ();
641 top_element = NULL;
642 current_namespace = NULL;
643 current_element = NULL;
644 cdata_content = false;
645 cdata = NULL;
646 implicit_default_namespace = false;
647 error_args = NULL;
648 loader = NULL;
649 created_elements = NULL;
650 created_namespaces = NULL;
651 hydrate_expecting = NULL;
652 hydrating = false;
654 buffer_until_element = NULL;
655 buffer_depth = -1;
656 buffer = NULL;
657 xml_buffer = NULL;
658 multi_buffer_offset = 0;
659 validate_templates = false;
661 namespace_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
664 void AddCreatedElement (DependencyObject* element)
666 // if we have a loader, set the surface and base resource location
667 if (loader) {
668 element->SetIsAttached (true); /* Some glyphs (DRT 0/Test5, 58) do not show up without this */
669 element->SetResourceBase (loader->GetResourceBase());
672 // When instantiating a template, some elements are created which are not explicitly
673 // mentioned in the xaml. Therefore we need to keep walking up the tree until we find
674 // the last element which we set a value for Control::IsTemplateItem and propagate
675 // it from there.
676 XamlElementInstance *instance = current_element;
677 while (instance) {
678 if (!instance->IsDependencyObject () || !instance->GetAsDependencyObject ()) {
679 instance = instance->parent;
680 continue;
682 if (!instance->GetAsDependencyObject ()->ReadLocalValue (Control::IsTemplateItemProperty)) {
683 instance = instance->parent;
684 continue;
686 Control::SetIsTemplateItem (element, Control::GetIsTemplateItem (instance->GetAsDependencyObject ()));
687 if (DependencyObject *e = instance->GetAsDependencyObject ()->GetTemplateOwner ())
688 element->SetTemplateOwner (e);
689 break;
692 if (instance == NULL) {
693 Control::SetIsTemplateItem (element, loader->GetExpandingTemplate ());
694 element->SetTemplateOwner (loader->GetTemplateOwner ());
697 if (Control::GetIsTemplateItem (element))
698 NameScope::SetNameScope (element, namescope);
699 created_elements = g_list_prepend (created_elements, element);
702 void AddCreatedNamespace (XamlNamespace* ns)
704 created_namespaces = g_list_prepend (created_namespaces, ns);
707 void QueueBeginBuffering (char* buffer_until, BufferMode mode)
709 buffer_until_element = buffer_until;
710 buffer_depth = 1;
711 buffer_mode = mode;
713 xml_buffer_start_index = -1;
716 void BeginBuffering ()
718 xml_buffer_start_index = XML_GetCurrentByteIndex (parser) - multi_buffer_offset;
719 buffer = g_string_new (NULL);
722 bool ShouldBeginBuffering ()
724 return InBufferingMode () && xml_buffer_start_index == -1;
727 bool InBufferingMode ()
729 return buffer_until_element != NULL;
732 void AppendCurrentXml ()
734 if (!buffer)
735 return;
736 int pos = XML_GetCurrentByteIndex (parser) - multi_buffer_offset;
737 g_string_append_len (buffer, xml_buffer + xml_buffer_start_index, pos - xml_buffer_start_index);
740 char* ClearBuffer ()
742 AppendCurrentXml ();
744 buffer_depth = 0;
745 buffer_until_element = NULL;
747 if (!buffer)
748 return g_strdup ("");
750 char* res = buffer->str;
751 g_string_free (buffer, FALSE);
752 buffer = NULL;
753 return res;
756 void SetXmlBuffer (const char* xml_buffer)
758 if (InBufferingMode ())
759 AppendCurrentXml ();
761 if (this->xml_buffer)
762 multi_buffer_offset += strlen (this->xml_buffer);
764 this->xml_buffer = xml_buffer;
765 xml_buffer_start_index = 0;
768 void ValidateTemplate (const char* buffer, XamlContext* context, FrameworkTemplate *binding_source)
770 XamlLoader *loader = new XamlLoader (NULL, buffer, NULL, context);
771 Type::Kind dummy;
773 context->SetTemplateBindingSource (binding_source);
775 loader->SetImportDefaultXmlns (true);
777 MoonError error;
778 Value *result = loader->CreateFromStringWithError (buffer, true, &dummy, XamlLoader::IMPORT_DEFAULT_XMLNS | XamlLoader::VALIDATE_TEMPLATES, &error);
780 delete result;
781 delete loader;
783 if (error.number != MoonError::NO_ERROR) {
784 int line_number = error.line_number + XML_GetCurrentLineNumber (parser);
785 error_args = new ParserErrorEventArgs (error.message, file_name, line_number, error.char_position, error.code, NULL, NULL);
789 FrameworkTemplate *GetTemplateParent (XamlElementInstance *item)
791 XamlElementInstance *parent = item->parent;
793 while (parent && !parent->IsTemplate ())
794 parent = parent->parent;
796 if (parent)
797 return (FrameworkTemplate *) parent->GetManagedPointer ();
799 if (!loader)
800 return NULL;
802 XamlContext *context = loader->GetContext ();
803 if (!context)
804 return NULL;
806 return context->internal->template_parent;
809 Value *GetTopElementPtr ()
811 XamlContext *context = loader->GetContext ();
812 if (context)
813 return context->internal->top_element;
815 if (top_element)
816 return top_element->GetAsValue ();
818 return NULL;
821 ~XamlParserInfo ()
823 created_elements = g_list_reverse (created_elements);
824 g_list_foreach (created_elements, unref_xaml_element, NULL);
825 g_list_free (created_elements);
827 g_list_foreach (created_namespaces, destroy_created_namespace, NULL);
828 g_list_free (created_namespaces);
830 g_hash_table_destroy (namespace_map);
832 if (cdata)
833 g_string_free (cdata, TRUE);
834 if (top_element)
835 delete top_element;
836 namescope->unref ();
843 class XamlElementInfoNative : public XamlElementInfo {
844 Type *type;
846 public:
847 XamlElementInfoNative (Type *t) : XamlElementInfo (NULL, t->GetName (), t->GetKind ())
849 type = t;
852 Type* GetType ()
854 return type;
857 const char* GetName ()
859 return type->GetName ();
862 const char* GetContentProperty (XamlParserInfo *p);
864 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
865 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
866 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
870 class XamlElementInstanceNative : public XamlElementInstance {
871 XamlElementInfoNative *element_info;
872 XamlParserInfo *parser_info;
874 public:
875 XamlElementInstanceNative (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item = true);
877 virtual DependencyObject *CreateItem ();
879 virtual XamlElementInfo* FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot);
881 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value);
882 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value);
883 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child);
884 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
888 class XamlElementInstanceValueType : public XamlElementInstance {
889 XamlElementInfoNative *element_info;
890 XamlParserInfo *parser_info;
892 public:
893 XamlElementInstanceValueType (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type);
895 virtual bool IsDependencyObject ()
897 return false;
900 virtual Value *GetAsValue ()
902 if (value == NULL) {
903 // we are an empty element (e.g. <sys:String></sys:String>). do type specific magic here.
904 CreateValueItemFromString ("");
907 return value;
910 bool CreateValueItemFromString (const char* str);
912 // A Value type doesn't really support anything. It's just here so people can do <SolidColorBrush.Color><Color>#FF00FF</Color></SolidColorBrush.Color>
913 virtual DependencyObject *CreateItem () { return NULL; }
914 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) { return false; }
915 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value) { return false; }
916 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) { }
917 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
919 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value) { return false; }
920 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value) { return CreateValueItemFromString (value); }
923 class XamlElementInfoEnum : public XamlElementInfo {
924 public:
925 XamlElementInfoEnum (const char *name) : XamlElementInfo (NULL, name, Type::INT32)
929 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
930 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
931 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name) { return NULL; }
934 class XamlElementInstanceEnum : public XamlElementInstance {
936 public:
937 XamlElementInstanceEnum (XamlElementInfoEnum *element_info, const char *name, ElementType type);
939 virtual bool IsDependencyObject ()
941 return false;
944 virtual Value *GetAsValue ()
946 return value;
949 bool CreateEnumFromString (const char* str);
951 // An enum type doesn't really support anything. It's just here so people can do <Visibility>Visible</Visibility>
952 virtual DependencyObject *CreateItem () { return NULL; }
953 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) { return false; }
954 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value) { return false; }
955 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) { }
956 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
958 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value) { return false; }
959 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value) { return CreateEnumFromString (value); }
962 class XamlElementInstanceTemplate : public XamlElementInstanceNative {
963 public:
964 XamlElementInstanceTemplate (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item = true)
965 : XamlElementInstanceNative (element_info, parser_info, name, type, create_item)
969 virtual bool IsTemplate ()
971 return true;
976 class DefaultNamespace : public XamlNamespace {
977 public:
978 DefaultNamespace ()
980 AddPrefix ("");
983 virtual ~DefaultNamespace () { }
985 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
987 Type* t = Type::Find (p->deployment, el, false);
988 if (t && !kind_requires_managed_load (t->GetKind ()))
989 return new XamlElementInfoNative (t);
991 if (enums_is_enum_name (el))
992 return new XamlElementInfoEnum (g_strdup (el));
994 XamlElementInfo* managed_element = create_element_info_from_imported_managed_type (p, el, attr, create);
995 if (managed_element)
996 return managed_element;
998 return NULL;
1002 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1004 return false;
1007 virtual const char* GetUri () { return "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; }
1010 class XmlNamespace : public XamlNamespace {
1011 public:
1012 XmlNamespace ()
1014 AddPrefix ("xml");
1017 virtual ~XmlNamespace () { }
1019 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1021 return NULL;
1024 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1026 if (!strcmp ("lang", attr)) {
1027 if (item->IsDependencyObject ()) {
1028 DependencyObject *dob = item->GetAsDependencyObject ();
1029 if (dob->Is(Type::FRAMEWORKELEMENT)) {
1030 ((FrameworkElement*)dob)->SetLanguage (value);
1031 return true;
1036 return false;
1039 virtual const char* GetUri () { return "http://www.w3.org/XML/1998/namespace"; }
1042 class XNamespace : public XamlNamespace {
1043 public:
1044 XNamespace ()
1046 AddPrefix ("x");
1049 virtual ~XNamespace () { }
1051 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1053 return NULL;
1056 virtual char *FindTypeName (const char **attr, char **xmlns)
1058 char *res = NULL;
1060 if (!attr)
1061 return NULL;
1063 for (int i = 0; attr [i]; i += 2) {
1064 const char *ns = strchr (attr [i], '|');
1065 if (!ns)
1066 continue;
1068 if (strncmp (GetUri (), attr [i], ns - attr [i]) || strcmp ("Class", ns + 1))
1069 continue;
1071 ns = strchr (attr [i + 1], ';');
1072 if (!ns) {
1073 *xmlns = g_strdup ("");
1074 res = g_strdup (attr [i + 1]);
1075 } else {
1076 *xmlns = g_strdup (ns + 1);
1077 res = g_strndup (attr [i + 1], attr [i + 1] - ns);
1079 return res;
1081 return NULL;
1084 bool IsParentResourceDictionary (XamlElementInstance *parent)
1086 if (parent == NULL)
1087 return false;
1089 return Type::IsSubclassOf (Deployment::GetCurrent (), parent->info->GetKind (), Type::RESOURCE_DICTIONARY);
1092 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1094 if (!strcmp ("Name", attr)) {
1096 // Causes breakage in airlines
1097 // Maybe x:Name overwrites but Name does not?
1099 // if (p->namescope->FindName (value)) {
1100 // parser_error (p, p->current_element->element_name, "x:Name", 2028, "The name already exists in the tree: %s.", value);
1101 // return false;
1102 // }
1105 if (IsParentResourceDictionary (p->current_element)) {
1106 if (item->GetKey ()) {
1107 // XXX don't know the proper values here...
1108 parser_error (p, item->element_name, NULL, 2028,
1109 "The name already exists in the tree: %s.", value);
1110 return false;
1114 if (item->GetName ()) {
1115 parser_error (p, item->element_name, NULL, 2016, "Cannot specify both Name and x:Name attributes.");
1116 return false;
1119 item->SetName (p, value);
1121 if (item->IsDependencyObject ()) {
1122 NameScope *scope = p->namescope;
1123 if (!item->GetAsDependencyObject ()->SetName (value, scope)) {
1124 if (IsParentResourceDictionary (p->current_element)) {
1125 // FIXME: inside of a resource dictionary this has an extremly
1126 // strange behavior. this isn't exactly right, since not only
1127 // does the exception get swallowed, but the name seems to also
1128 // be unregistered.
1130 else {
1131 parser_error (p, item->element_name, NULL, 2028,
1132 "The name already exists in the tree: %s.", value);
1133 return false;
1136 return true;
1139 return false;
1142 if (!strcmp ("Key", attr)) {
1143 if (item->GetKey () && IsParentResourceDictionary (p->current_element) && !Type::IsSubclassOf (p->deployment, item->info->GetKind (), Type::STORYBOARD)) {
1144 // XXX don't know the proper values here...
1145 parser_error (p, item->element_name, NULL, 2028,
1146 "The name already exists in the tree: %s.", value);
1147 return false;
1149 item->SetKey (p, value);
1150 return true;
1153 if (!strcmp ("Class", attr)) {
1154 if (!is_legal_top_level_kind (item->info->GetKind ())) {
1155 // XXX don't know the proper values here...
1156 parser_error (p, item->element_name, attr, -1,
1157 "Cannot specify x:Class type '%s' on value type element (%s).", value, item->element_name);
1158 return false;
1161 if (p->top_element != item) {
1162 // HAH: what a useless error message
1163 parser_error (p, item->element_name, attr, 2012,
1164 "Unknown attribute %s on element %s.", attr, item->element_name);
1165 return false;
1168 // While hydrating, we do not need to create the toplevel class, its created already
1169 if (p->hydrating)
1170 return true;
1171 else {
1172 parser_error (p, item->element_name, attr, 4005,
1173 "Cannot specify x:Class in xaml files outside of a xap.");
1174 return false;
1178 return false;
1181 virtual const char* GetUri () { return X_NAMESPACE_URI; }
1185 class PrimitiveNamespace : public XamlNamespace {
1187 public:
1188 PrimitiveNamespace (char *prefix)
1190 AddPrefix (prefix);
1193 virtual ~PrimitiveNamespace ()
1197 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1199 if (!strcmp ("String", el)) {
1200 Type* t = Type::Find (p->deployment, Type::STRING);
1201 // it's not as easy in this case, because primitive clr strings require that the
1202 // character data be read in verbatim, including all whitespace.
1203 XamlElementInfo *info = new XamlElementInfoNative (t);
1204 info->SetIsCDataVerbatim (true);
1205 return info;
1206 } else if (!strcmp ("Int32", el)) {
1207 Type* t = Type::Find (p->deployment, Type::INT32);
1208 return new XamlElementInfoNative (t);
1209 } else if (!strcmp ("Double", el)) {
1210 Type* t = Type::Find (p->deployment, Type::DOUBLE);
1211 return new XamlElementInfoNative (t);
1212 } else if (!strcmp ("Boolean", el)) {
1213 Type* t = Type::Find (p->deployment, Type::BOOL);
1214 return new XamlElementInfoNative (t);
1215 } else if (!strcmp ("TimeSpan", el)) {
1216 Type* t = Type::Find (p->deployment, Type::TIMESPAN);
1217 return new XamlElementInfoNative (t);
1220 return NULL;
1223 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1225 return false;
1228 virtual const char* GetUri () { return PRIMITIVE_NAMESPACE_URI; }
1232 class MCIgnorableNamespace : public XamlNamespace {
1234 public:
1235 MCIgnorableNamespace (char *prefix)
1237 AddPrefix (prefix);
1240 virtual ~MCIgnorableNamespace ()
1244 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1246 return NULL;
1249 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1251 if (!strcmp ("Ignorable", attr)) {
1252 const char *start = value;
1253 do {
1254 const char *space = strchr (start, ' ');
1255 char *prefix;
1256 if (space) {
1257 prefix = g_strndup (start, space - start);
1258 start = space + 1;
1259 } else {
1260 prefix = g_strdup (start);
1261 start = NULL;
1264 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
1265 if (ns)
1266 ns->is_ignored = true;
1268 } while (start);
1270 return true;
1273 return false;
1276 virtual const char* GetUri () { return MC_IGNORABLE_NAMESPACE_URI; }
1280 static void
1281 destroy_created_namespace (gpointer data, gpointer user_data)
1283 XamlNamespace* ns = (XamlNamespace *) data;
1284 delete ns;
1288 class XamlElementInfoManaged : public XamlElementInfo {
1289 public:
1290 XamlElementInfoManaged (const char *xmlns, const char *name, XamlElementInfo *parent, Type::Kind dependency_type, Value *obj) : XamlElementInfo (xmlns, name, dependency_type)
1292 this->obj = obj;
1295 Value *obj;
1297 const char* GetName () { return name; }
1299 const char* GetContentProperty (XamlParserInfo *p);
1301 virtual bool RequiresManagedSet () { return true; }
1303 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
1304 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
1305 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
1309 class XamlElementInstanceManaged : public XamlElementInstance {
1310 public:
1311 XamlElementInstanceManaged (XamlElementInfo *info, const char *name, ElementType type, Value *obj);
1313 virtual bool IsDependencyObject ()
1315 return is_dependency_object;
1318 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value);
1319 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value);
1320 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child);
1321 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
1323 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value);
1324 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value);
1326 virtual void* GetManagedPointer ();
1327 virtual Value* GetParentPointer ();
1328 private:
1329 bool is_dependency_object;
1333 class XamlElementInfoImportedManaged : public XamlElementInfoManaged {
1334 public:
1335 XamlElementInfoImportedManaged (const char *name, XamlElementInfo *parent, Value *obj) : XamlElementInfoManaged (NULL, name, parent, obj->GetKind (), obj)
1339 const char* GetContentProperty (XamlParserInfo *p);
1341 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
1342 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
1343 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
1348 class ManagedNamespace : public XamlNamespace {
1349 public:
1350 char *xmlns;
1352 ManagedNamespace (char *xmlns, char *prefix)
1354 this->xmlns = xmlns;
1355 AddPrefix (prefix);
1358 virtual ~ManagedNamespace ()
1360 g_free (xmlns);
1363 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1365 char* type_name = NULL;
1366 char* type_xmlns = NULL;
1367 const char* use_xmlns = xmlns;
1369 if (!p->loader)
1370 return NULL;
1372 if (x_namespace) {
1373 // We might have an x:Class attribute specified, so we need to use that for the
1374 // type_name that we pass to LookupObject
1375 if (strcmp ("Application", el)) {
1376 type_name = x_namespace->FindTypeName (attr, &type_xmlns);
1377 if (type_name) {
1378 el = type_name;
1379 use_xmlns = type_xmlns;
1381 if (!p->hydrating) {
1382 parser_error (p, el, "x:Class", 4005, "Cannot specify x:Class in xaml files outside of a xap.");
1383 return NULL;
1389 Value *value = new Value ();
1390 if (!p->loader->LookupObject (p, p->GetTopElementPtr (), p->current_element ? p->current_element->GetAsValue () : NULL, use_xmlns, el, create, false, value)) {
1391 parser_error (p, el, NULL, 2007, "Unable to resolve managed type %s.", el);
1392 delete value;
1393 if (type_name)
1394 g_free (type_name);
1395 if (type_xmlns)
1396 g_free (type_xmlns);
1397 return NULL;
1400 if (p->hydrate_expecting) {
1402 // If we are hydrating a top level managed object, use the Value* passed
1403 // to Hydrate as our value
1405 Value *v = value;
1406 value = p->hydrate_expecting;
1407 delete v;
1410 XamlElementInfoManaged *info = new XamlElementInfoManaged (xmlns, g_strdup (el), NULL, value->GetKind (), value);
1411 if (type_name)
1412 g_free (type_name);
1413 if (type_xmlns)
1414 g_free (type_xmlns);
1415 return info;
1418 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1420 if (is_ignored)
1421 return true;
1423 if (p->loader) {
1424 Value v = Value (value);
1425 return p->loader->SetProperty (p, p->GetTopElementPtr (), item->info->xmlns, item->GetAsValue (), item, item->GetParentPointer (), xmlns, attr, &v, NULL);
1427 return false;
1431 virtual const char* GetUri () { return xmlns; }
1434 bool
1435 XamlLoader::LookupObject (void *p, Value *top_level, Value *parent, const char* xmlns, const char* type_name, bool create, bool is_property, Value *value)
1437 if (callbacks.lookup_object) {
1438 if (!vm_loaded && !LoadVM ())
1439 return false;
1440 MoonError error;
1441 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1442 bool res = callbacks.lookup_object (&data, parent, xmlns, type_name, create, is_property, value, &error);
1443 return res;
1446 return false;
1449 const char *
1450 XamlLoader::GetContentPropertyName (void *p, Value *top_level, Value *object)
1452 if (callbacks.get_content_property_name) {
1453 MoonError error;
1454 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1455 return callbacks.get_content_property_name (&data, object, &error);
1457 return NULL;
1460 bool
1461 XamlLoader::SetProperty (void *p, Value *top_level, const char* xmlns, Value *target, void *target_data, Value *target_parent, const char* prop_xmlns, const char *name, Value *value, void* value_data, int flags)
1463 if (callbacks.set_property) {
1464 MoonError error;
1465 XamlCallbackData data = XamlCallbackData (this, p, top_level, flags);
1466 bool res = callbacks.set_property (&data, xmlns, target, target_data, target_parent, prop_xmlns, name, value, value_data, &error);
1468 if (error.number != MoonError::NO_ERROR) {
1469 parser_error ((XamlParserInfo *) p, ((XamlElementInstance *) target_data)->element_name, NULL, error.code, error.message);
1470 return false;
1473 return res;
1476 return false;
1479 bool
1480 XamlLoader::AddChild (void *p, Value *top_level, Value *parent_parent, bool parent_is_property, const char* parent_xmlns, Value *parent, void *parent_data, Value *child, void *child_data)
1482 if (callbacks.add_child) {
1483 MoonError error;
1484 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1485 bool res = callbacks.add_child (&data, parent_parent, parent_is_property, parent_xmlns, parent, parent_data, child, child_data, &error);
1487 if (error.number != MoonError::NO_ERROR) {
1488 parser_error ((XamlParserInfo *) p, ((XamlElementInstance *) child_data)->element_name, NULL, error.code, error.message);
1489 return false;
1492 return res;
1494 return false;
1497 XamlLoader::XamlLoader (const char *resourceBase, const char* filename, const char* str, Surface* surface, XamlContext *context)
1499 Initialize (resourceBase, filename, str, surface, context);
1502 XamlLoader::XamlLoader (const char* filename, const char* str, Surface* surface, XamlContext *context)
1504 Initialize (NULL, filename, str, surface, context);
1507 void
1508 XamlLoader::Initialize (const char *resourceBase, const char* filename, const char* str, Surface* surface, XamlContext *context)
1510 this->filename = g_strdup (filename);
1511 this->resource_base = g_strdup (resourceBase);
1512 this->str = g_strdup (str);
1513 this->surface = surface;
1514 if (surface)
1515 surface->ref ();
1516 this->context = context;
1517 this->vm_loaded = false;
1518 this->error_args = NULL;
1519 this->expanding_template = false;
1520 this->template_owner = NULL;
1521 this->import_default_xmlns = false;
1523 if (context) {
1524 callbacks = context->internal->callbacks;
1525 this->vm_loaded = true;
1527 #if DEBUG
1528 if (!surface && debug_flags & RUNTIME_DEBUG_XAML) {
1529 printf ("XamlLoader::XamlLoader ('%s', '%s', %p): Initializing XamlLoader without a surface.\n",
1530 filename, str, surface);
1532 #endif
1535 XamlLoader::~XamlLoader ()
1537 g_free (filename);
1538 g_free (resource_base);
1539 g_free (str);
1540 if (surface)
1541 surface->unref ();
1542 surface = NULL;
1543 filename = NULL;
1544 str = NULL;
1545 if (error_args)
1546 error_args->unref();
1549 bool
1550 XamlLoader::LoadVM ()
1552 return false;
1555 XamlLoader*
1556 xaml_loader_new (const char *resourceBase, const char* filename, const char* str, Surface* surface)
1558 return new XamlLoader (resourceBase, filename, str, surface);
1561 void
1562 xaml_loader_free (XamlLoader* loader)
1564 delete loader;
1567 void
1568 xaml_loader_set_callbacks (XamlLoader* loader, XamlLoaderCallbacks callbacks)
1570 if (!loader) {
1571 LOG_XAML ("Trying to set callbacks for a null object\n");
1572 return;
1575 loader->callbacks = callbacks;
1576 loader->vm_loaded = true;
1579 static gboolean
1580 namespace_for_prefix (gpointer key, gpointer value, gpointer user_data)
1582 XamlNamespace *ns = (XamlNamespace *) value;
1583 const char *prefix = (const char *) user_data;
1585 return ns->HasPrefix (prefix);
1588 char*
1589 xaml_uri_for_prefix (void *parser, char* prefix)
1591 XamlParserInfo *p = (XamlParserInfo *) parser;
1593 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
1594 if (!ns)
1595 return NULL;
1597 return g_strdup (ns->GetUri ());
1601 // Called when we encounter an error. Note that memory ownership is taken for everything
1602 // except the message, this allows you to use g_strdup_printf when creating the error message
1604 static void
1605 parser_error (XamlParserInfo *p, const char *el, const char *attr, int error_code, const char *format, ...)
1607 char *message;
1608 va_list args;
1610 // Already failed
1611 if (p->error_args)
1612 return;
1614 // if parsing fails too early it's not safe (i.e. sigsegv) to call some functions, e.g. XML_GetCurrentLineNumber
1615 bool report_line_col = (error_code != XML_ERROR_XML_DECL);
1616 int line_number = report_line_col ? XML_GetCurrentLineNumber (p->parser) : 0;
1617 int char_position = report_line_col ? XML_GetCurrentColumnNumber (p->parser) : 0;
1619 va_start (args, format);
1620 message = g_strdup_vprintf (format, args);
1621 va_end (args);
1623 p->error_args = new ParserErrorEventArgs (message, p->file_name, line_number, char_position, error_code, el, attr);
1625 g_free (message);
1627 LOG_XAML ("PARSER ERROR, STOPPING PARSING: (%d) %s line: %d char: %d\n", error_code, message,
1628 line_number, char_position);
1630 XML_StopParser (p->parser, FALSE);
1633 void
1634 expat_parser_error (XamlParserInfo *p, XML_Error expat_error)
1636 // Already had an error
1637 if (p->error_args)
1638 return;
1640 LOG_XAML ("expat error is: %d\n", expat_error);
1642 switch (expat_error) {
1643 case XML_ERROR_DUPLICATE_ATTRIBUTE:
1644 parser_error (p, NULL, NULL, 7031, "wfc: unique attribute spec");
1645 break;
1646 case XML_ERROR_UNBOUND_PREFIX:
1647 parser_error (p, NULL, NULL, 7055, "undeclared prefix");
1648 break;
1649 case XML_ERROR_NO_ELEMENTS:
1650 parser_error (p, NULL, NULL, 7000, "unexpected end of input");
1651 break;
1652 case XML_ERROR_SYNTAX:
1653 parser_error (p, NULL, NULL, 2103, "syntax error");
1654 break;
1655 default:
1656 parser_error (p, NULL, NULL, expat_error, "Unhandled XML error %s", XML_ErrorString (expat_error));
1657 break;
1661 static void
1662 start_element (void *data, const char *el, const char **attr)
1664 XamlParserInfo *p = (XamlParserInfo *) data;
1665 XamlElementInfo *elem = NULL;
1666 XamlElementInstance *inst;
1667 Types *types = Deployment::GetCurrent ()->GetTypes ();
1669 if (!strcmp (el, INTERNAL_IGNORABLE_ELEMENT))
1670 return;
1672 if (p->ShouldBeginBuffering ()) {
1673 p->BeginBuffering ();
1674 return;
1677 if (p->InBufferingMode ()) {
1678 if (!strcmp (p->buffer_until_element, el))
1679 p->buffer_depth++;
1680 return;
1683 const char *dot = strchr (el, '.');
1684 if (!dot)
1685 elem = p->current_namespace->FindElement (p, el, attr, p->hydrate_expecting == NULL);
1687 if (p->error_args)
1688 return;
1691 if (elem) {
1692 if (p->hydrate_expecting){
1694 Type::Kind expecting_type = p->hydrate_expecting->GetObjectType ();
1696 if (!types->IsSubclassOf (expecting_type, elem->GetKind ())) {
1697 parser_error (p, el, NULL, -1, "Invalid top-level element found %s, expecting %s", el,
1698 types->Find (expecting_type)->GetName ());
1699 return;
1703 inst = elem->CreateWrappedElementInstance (p, p->hydrate_expecting);
1704 p->hydrate_expecting = NULL;
1705 } else
1706 inst = elem->CreateElementInstance (p);
1708 if (!inst)
1709 return;
1711 inst->parent = p->current_element;
1713 if (!p->top_element) {
1714 p->top_element = inst;
1715 if (inst->GetAsDependencyObject ())
1716 NameScope::SetNameScope (inst->GetAsDependencyObject (), p->namescope);
1719 if (inst->GetAsDependencyObject ())
1720 inst->GetAsDependencyObject ()->SetIsBeingParsed (true);
1722 inst->SetAttributes (p, attr);
1723 if (p->error_args)
1724 return;
1726 if (inst->IsDependencyObject ()) {
1727 if (p->current_element){
1728 if (p->current_element->info) {
1729 p->current_element->AddChild (p, inst);
1730 if (p->error_args)
1731 return;
1735 } else {
1736 // it's actually valid (from SL point of view) to have <Ellipse.Triggers> inside a <Rectangle>
1737 // however we can't add properties to something bad, like a <Recta.gle> element
1738 XamlElementInfo *prop_info = NULL;
1739 if (dot) {
1740 gchar *prop_elem = g_strndup (el, dot - el);
1741 prop_info = p->current_element->FindPropertyElement (p, el, dot);
1742 g_free (prop_elem);
1745 if (prop_info != NULL) {
1746 inst = prop_info->CreatePropertyElementInstance (p, g_strdup (el));
1747 inst->parent = p->current_element;
1749 if (attr [0] != NULL) {
1750 // It appears there is a bug in the error string but it matches the MS runtime
1751 parser_error (p, el, NULL, 2018, "The element %s does not support attributes.", attr[0]);
1752 return;
1755 if (prop_info && !strcmp (el, "TextBox.Text"))
1756 prop_info->SetIsCDataVerbatim (true);
1758 if (!p->top_element) {
1759 if (types->IsSubclassOf (prop_info->GetKind (), Type::COLLECTION)) {
1760 XamlElementInstance *wrap = prop_info->CreateElementInstance (p);
1761 NameScope::SetNameScope (wrap->GetAsDependencyObject (), p->namescope);
1762 p->top_element = wrap;
1763 p->current_element = wrap;
1764 return;
1767 } else {
1768 g_warning ("Unknown element: %s.", el);
1769 parser_error (p, el, NULL, 2007, "Unknown element: %s.", el);
1770 return;
1774 if (p->current_element) {
1775 p->current_element->children->Append (inst);
1777 p->current_element = inst;
1779 if (elem && element_begins_buffering (elem->GetKind ())) {
1780 p->QueueBeginBuffering (g_strdup (el), BUFFER_MODE_TEMPLATE);
1784 static bool
1785 allow_value_from_str_in_flush (XamlParserInfo *p, XamlElementInstance *parent)
1787 if (parent == NULL || parent->element_type != XamlElementInstance::PROPERTY || parent->parent == NULL || !parent->parent->IsDependencyObject ())
1788 return false;
1790 if (parent->info->GetKind () == Type::OBJECT)
1791 return true;
1793 return false;
1796 static void
1797 flush_char_data (XamlParserInfo *p)
1799 if (p->InBufferingMode ())
1800 return;
1802 if (!p->cdata || !p->current_element)
1803 return;
1805 if (p->current_element->info->IsCDataVerbatim()) {
1806 p->cdata->str = g_strstrip (p->cdata->str);
1809 if (p->current_element->element_type == XamlElementInstance::ELEMENT) {
1810 if (!p->current_element->TrySetContentProperty (p, p->cdata->str) && p->cdata_content) {
1811 if (allow_value_from_str_in_flush (p, p->current_element->parent)) {
1812 Value *v;
1813 if (value_from_str (p->current_element->info->GetKind (), NULL, p->cdata->str, &v)) {
1814 p->current_element->SetValue (v);
1815 goto cleanup;
1818 parser_error (p, p->current_element->element_name, NULL, 2011,
1819 "%s does not support text content.", p->current_element->element_name);
1821 } else if (p->current_element->element_type == XamlElementInstance::PROPERTY) {
1822 if (p->cdata_content && p->current_element->parent && !p->current_element->parent->SetProperty (p, p->current_element, p->cdata->str)) {
1823 parser_error (p, p->current_element->element_name, NULL, 2011,
1824 "%s does not support text content.", p->current_element->element_name);
1828 cleanup:
1829 if (p->cdata) {
1830 g_string_free (p->cdata, TRUE);
1831 p->cdata_content = false;
1832 p->cdata = NULL;
1836 static bool
1837 element_begins_buffering (Type::Kind kind)
1839 return Type::IsSubclassOf (Deployment::GetCurrent (), kind, Type::FRAMEWORKTEMPLATE);
1842 static gboolean
1843 is_default_namespace (gpointer key, gpointer value, gpointer user_data)
1845 return value == default_namespace;
1848 static void
1849 start_element_handler (void *data, const char *el, const char **attr)
1851 XamlParserInfo *p = (XamlParserInfo *) data;
1853 if (p->error_args)
1854 return;
1856 char **name = g_strsplit (el, "|", -1);
1857 XamlNamespace *next_namespace = NULL;
1858 char *element = NULL;
1860 if (g_strv_length (name) == 2) {
1861 // Find the proper namespace for our next element
1862 next_namespace = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, name [0]);
1863 element = name [1];
1866 if (!next_namespace && p->implicit_default_namespace) {
1867 // Use the default namespace for the next element
1868 next_namespace = default_namespace;
1869 element = name [0];
1870 } else if (!next_namespace) {
1871 if (!g_hash_table_find (p->namespace_map, is_default_namespace, NULL))
1872 return parser_error (p, el, NULL, 2263, "AG_E_PARSER_MISSING_DEFAULT_NAMESPACE");
1875 if (next_namespace && next_namespace->is_ignored) {
1876 p->current_namespace = next_namespace;
1877 if (!p->InBufferingMode ())
1878 p->QueueBeginBuffering (g_strdup (element), BUFFER_MODE_IGNORE);
1880 start_element (data, element, attr); // This will force the buffering to start/build depth if needed
1881 return;
1884 p->next_element = element;
1886 flush_char_data (p);
1888 // Now update our namespace
1889 p->current_namespace = next_namespace;
1891 if (!p->current_namespace && !p->InBufferingMode ()) {
1892 if (name[1])
1893 parser_error (p, name[1], NULL, -1, "No handlers available for namespace: '%s' (%s)\n", name[0], el);
1894 else
1895 parser_error (p, name[1], NULL, -1, "No namespace mapping available for element: '%s'\n", el);
1897 g_strfreev (name);
1898 return;
1901 p->next_element = NULL;
1902 start_element (data, element, attr);
1904 g_strfreev (name);
1907 static char*
1908 get_element_name (XamlParserInfo* p, const char *el)
1910 char **names = g_strsplit (el, "|", -1);
1911 char *name = g_strdup (names [g_strv_length (names) - 1]);
1913 g_strfreev (names);
1915 return name;
1918 static GSList *
1919 create_resource_list (XamlParserInfo *p)
1921 GSList *list = NULL;
1922 XamlElementInstance *walk = p->current_element;
1924 Types * types = Deployment::GetCurrent ()->GetTypes ();
1925 while (walk) {
1926 if (walk->element_type == XamlElementInstance::ELEMENT && types->IsSubclassOf (walk->info->GetKind (), Type::FRAMEWORKELEMENT)) {
1927 FrameworkElement *fwe = (FrameworkElement *)walk->GetAsDependencyObject ();
1928 if (g_slist_index (list, fwe) == -1)
1929 list = g_slist_prepend (list, fwe);
1931 if (walk->element_type == XamlElementInstance::ELEMENT && types->IsSubclassOf (walk->info->GetKind (), Type::RESOURCE_DICTIONARY)) {
1932 ResourceDictionary *rd = (ResourceDictionary *) walk->GetAsDependencyObject ();
1933 if (g_slist_index (list, rd) == -1)
1934 list = g_slist_prepend (list, walk->GetAsDependencyObject ());
1936 walk = walk->parent;
1939 list = g_slist_reverse (list);
1940 return list;
1943 static XamlContext *
1944 create_xaml_context (XamlParserInfo *p, FrameworkTemplate *template_, XamlContext *parent_context)
1946 GSList *resources = create_resource_list (p);
1947 XamlContextInternal *ic = new XamlContextInternal (p->loader->callbacks, p->GetTopElementPtr (), template_, p->namespace_map, resources, parent_context ? parent_context->internal : NULL);
1948 return new XamlContext (ic);
1951 static void
1952 end_element_handler (void *data, const char *el)
1954 XamlParserInfo *p = (XamlParserInfo *) data;
1955 DependencyObject *obj;
1957 if (!strcmp (el, INTERNAL_IGNORABLE_ELEMENT))
1958 return;
1960 if (p->error_args)
1961 return;
1963 if (!p->current_element) {
1964 g_warning ("p->current_element == NULL, current_element = %p (%s)\n",
1965 p->current_element, p->current_element ? p->current_element->element_name : "<NULL>");
1966 return;
1969 if (p->InBufferingMode ()) {
1970 char* name = get_element_name (p, el);
1971 if (!strcmp (p->buffer_until_element, name)) {
1972 p->buffer_depth--;
1974 if (p->buffer_depth == 0) {
1975 if (p->buffer_mode == BUFFER_MODE_TEMPLATE) {
1976 // OK we are done buffering, the element we are buffering for
1977 FrameworkTemplate* template_ = (FrameworkTemplate *) p->current_element->GetAsDependencyObject ();
1979 char* buffer = p->ClearBuffer ();
1981 XamlContext *context = create_xaml_context (p, template_, p->loader->GetContext());
1983 if (p->validate_templates) {
1984 p->ValidateTemplate (buffer, context, template_);
1986 if (p->error_args)
1987 return;
1990 template_->SetXamlBuffer (context, buffer);
1991 p->current_element = p->current_element->parent;
1992 } else if (p->buffer_mode == BUFFER_MODE_IGNORE) {
1993 // For now we'll actually keep/clear this buffer because it makes testing easier
1994 char *buffer = p->ClearBuffer ();
1995 g_free (buffer);
2000 g_free (name);
2001 return;
2004 switch (p->current_element->element_type) {
2005 case XamlElementInstance::ELEMENT:
2007 p->current_element->SetDelayedProperties (p);
2008 flush_char_data (p);
2010 // according to http://blogs.msdn.com/devdave/archive/2008/10/11/control-lifecycle.aspx
2011 // default styles are apply when the end tag is read.
2013 if (p->current_element->IsDependencyObject () &&
2014 p->current_element->GetAsDependencyObject() &&
2015 p->current_element->GetAsDependencyObject()->Is(Type::CONTROL)) {
2017 Control *control = (Control*)p->current_element->GetAsDependencyObject();
2018 ManagedTypeInfo *key = control->GetDefaultStyleKey ();
2020 if (key) {
2021 if (Application::GetCurrent () == NULL)
2022 g_warning ("attempting to use a null application applying default style while parsing.");
2023 else
2024 Application::GetCurrent()->ApplyDefaultStyle (control, key);
2027 else if (!p->current_element->IsDependencyObject ()) {
2029 if (p->current_element->parent)
2030 p->current_element->parent->AddChild (p, p->current_element);
2032 break;
2033 case XamlElementInstance::PROPERTY: {
2034 List::Node *walk = p->current_element->children->First ();
2035 while (walk) {
2036 XamlElementInstance *child = (XamlElementInstance *) walk;
2037 if (p->current_element->parent) {
2038 p->current_element->parent->SetProperty (p, p->current_element, child);
2040 walk = walk->next;
2042 flush_char_data (p);
2043 break;
2047 if ((obj = p->current_element->GetAsDependencyObject ()))
2048 obj->SetIsBeingParsed (false);
2050 p->current_element = p->current_element->parent;
2053 static void
2054 char_data_handler (void *data, const char *in, int inlen)
2056 XamlParserInfo *p = (XamlParserInfo *) data;
2057 register const char *inptr = in;
2058 const char *inend = in + inlen;
2059 const char *start;
2061 if (p->InBufferingMode ())
2062 return;
2064 if (p->error_args)
2065 return;
2067 if (p->current_element && p->current_element->info->IsCDataVerbatim()) {
2068 if (!p->cdata)
2069 p->cdata = g_string_new ("");
2071 g_string_append_len (p->cdata, inptr, inlen);
2072 p->cdata_content = true;
2073 return;
2076 if (!p->cdata) {
2077 p->cdata = g_string_new ("");
2079 if (g_ascii_isspace (*inptr)) {
2080 g_string_append_c (p->cdata, ' ');
2081 inptr++;
2083 while (inptr < inend && g_ascii_isspace (*inptr))
2084 inptr++;
2087 if (inptr == inend)
2088 return;
2089 } else if (g_ascii_isspace (p->cdata->str[p->cdata->len - 1])) {
2090 // previous cdata chunk ended with lwsp, skip over leading lwsp for this chunk
2091 while (inptr < inend && g_ascii_isspace (*inptr))
2092 inptr++;
2095 while (inptr < inend) {
2096 start = inptr;
2097 while (inptr < inend && !g_ascii_isspace (*inptr))
2098 inptr++;
2100 if (inptr > start) {
2101 g_string_append_len (p->cdata, start, inptr - start);
2102 p->cdata_content = true;
2105 if (inptr < inend) {
2106 g_string_append_c (p->cdata, ' ');
2107 inptr++;
2109 while (inptr < inend && g_ascii_isspace (*inptr))
2110 inptr++;
2115 static void
2116 start_namespace_handler (void *data, const char *prefix, const char *uri)
2118 XamlParserInfo *p = (XamlParserInfo *) data;
2120 if (p->InBufferingMode ())
2121 return;
2123 if (p->error_args)
2124 return;
2126 if (p->loader != NULL && p->loader->callbacks.import_xaml_xmlns != NULL) {
2127 MoonError error;
2128 XamlCallbackData data = XamlCallbackData (p->loader, p, p->GetTopElementPtr ());
2129 if (!p->loader->callbacks.import_xaml_xmlns (&data, uri, &error))
2130 return parser_error (p, p->current_element ? p->current_element->element_name : NULL, prefix, 2005, "Unknown namespace %s", uri);
2133 for (int i = 0; default_namespace_names [i]; i++) {
2134 if (!strcmp (default_namespace_names [i], uri)) {
2135 g_hash_table_insert (p->namespace_map, g_strdup (uri), default_namespace);
2136 return;
2140 if (!strcmp (X_NAMESPACE_URI, uri)){
2141 g_hash_table_insert (p->namespace_map, g_strdup (uri), x_namespace);
2142 } else if (!strcmp (PRIMITIVE_NAMESPACE_URI, uri)) {
2143 PrimitiveNamespace *pn = new PrimitiveNamespace (g_strdup (prefix));
2144 g_hash_table_insert (p->namespace_map, g_strdup (uri), pn);
2145 p->AddCreatedNamespace (pn);
2146 } else if (!strcmp (MC_IGNORABLE_NAMESPACE_URI, uri)) {
2147 MCIgnorableNamespace *mc = new MCIgnorableNamespace (g_strdup (prefix));
2148 g_hash_table_insert (p->namespace_map, g_strdup (uri), mc);
2149 p->AddCreatedNamespace (mc);
2150 } else {
2151 if (!p->loader) {
2152 return parser_error (p, (p->current_element ? p->current_element->element_name : NULL), prefix, -1,
2153 "No managed element callback installed to handle %s", uri);
2156 if (!prefix) {
2157 parser_error (p, (p->current_element ? p->current_element->element_name : NULL), NULL, 2262,
2158 "AG_E_PARSER_NAMESPACE_NOT_SUPPORTED");
2159 return;
2162 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, uri);
2164 if (ns) {
2165 ns->AddPrefix (prefix);
2166 return;
2169 ManagedNamespace *c = new ManagedNamespace (g_strdup (uri), g_strdup (prefix));
2170 g_hash_table_insert (p->namespace_map, g_strdup (c->xmlns), c);
2171 p->AddCreatedNamespace (c);
2175 static void
2176 start_doctype_handler (void *data,
2177 const XML_Char *doctype_name,
2178 const XML_Char *sysid,
2179 const XML_Char *pubid,
2180 int has_internal_subset)
2182 XamlParserInfo *p = (XamlParserInfo *) data;
2184 if (p->InBufferingMode ())
2185 return;
2187 if (sysid)
2188 return parser_error (p, NULL, NULL, 7050, "DTD was found but is prohibited");
2190 if (doctype_name)
2191 return parser_error (p, NULL, NULL, 7016, "incorrect document syntax.");
2194 static void
2195 add_default_namespaces (XamlParserInfo *p, bool sl_xmlns)
2197 if (sl_xmlns) {
2198 p->implicit_default_namespace = true;
2199 g_hash_table_insert (p->namespace_map, g_strdup ("http://schemas.microsoft.com/winfx/2006/xaml/presentation"), default_namespace);
2200 g_hash_table_insert (p->namespace_map, g_strdup (X_NAMESPACE_URI), x_namespace);
2202 g_hash_table_insert (p->namespace_map, g_strdup (XML_NAMESPACE_URI), xml_namespace);
2205 static void
2206 print_tree (XamlElementInstance *el, int depth)
2208 #if DEBUG
2209 if (debug_flags & RUNTIME_DEBUG_XAML) {
2210 for (int i = 0; i < depth; i++)
2211 printf ("\t");
2213 const char *name = NULL;
2215 if (!el) {
2216 printf (" -null- \n");
2217 return;
2220 if (el->element_type == XamlElementInstance::ELEMENT && el->IsDependencyObject ())
2221 name = el->GetAsDependencyObject ()->GetName ();
2222 printf ("%s (%s) (%p) (%s)\n", el->element_name, name ? name : "-no name-", el->parent, el->element_type == XamlElementInstance::PROPERTY ? "PROPERTY" : "ELEMENT");
2224 for (List::Node *walk = el->children->First (); walk != NULL; walk = walk->next) {
2225 XamlElementInstance *el = (XamlElementInstance *) walk;
2226 print_tree (el, depth + 1);
2229 #endif
2232 void
2233 xaml_parse_xmlns (const char* xmlns, char** type_name, char** ns, char** assembly)
2235 const char delimiters[] = ";";
2236 char* decl;
2237 char* buffer = g_strdup (xmlns);
2239 *type_name = NULL;
2240 *ns = NULL;
2241 *assembly = NULL;
2243 decl = strtok (buffer, delimiters);
2244 while (decl != NULL) {
2245 if (strstr (decl, "clr-namespace:") == decl) {
2246 if (*ns)
2247 g_free (*ns);
2248 *ns = g_strdup (decl + 14);
2249 } else if (strstr (decl, "assembly=") == decl) {
2250 if (*assembly)
2251 g_free (*assembly);
2252 *assembly = g_strdup (decl + 9);
2253 } else {
2254 if (*type_name)
2255 g_free (*type_name);
2256 *type_name = g_strdup (decl);
2259 decl = strtok (NULL, delimiters);
2261 g_free (buffer);
2264 Value *
2265 XamlLoader::CreateFromFile (const char *xaml_file, bool create_namescope,
2266 Type::Kind *element_type)
2268 Value *res = NULL;
2269 XamlParserInfo *parser_info = NULL;
2270 XML_Parser p = NULL;
2271 bool first_read = true;
2272 const char *inptr, *inend;
2273 TextStream *stream;
2274 char buffer[4096];
2275 ssize_t nread, n;
2277 LOG_XAML ("attemtping to load xaml file: %s\n", xaml_file);
2279 stream = new TextStream ();
2280 if (!stream->OpenFile (xaml_file, false)) {
2281 LOG_XAML ("can not open file\n");
2282 goto cleanup_and_return;
2285 if (!(p = XML_ParserCreateNS ("UTF-8", '|'))) {
2286 LOG_XAML ("can not create parser\n");
2287 goto cleanup_and_return;
2290 parser_info = new XamlParserInfo (p, xaml_file);
2292 parser_info->namescope->SetTemporary (!create_namescope);
2294 parser_info->loader = this;
2296 // TODO: This is just in here temporarily, to make life less difficult for everyone
2297 // while we are developing.
2298 add_default_namespaces (parser_info, false);
2300 XML_SetUserData (p, parser_info);
2302 XML_SetElementHandler (p, start_element_handler, end_element_handler);
2303 XML_SetCharacterDataHandler (p, char_data_handler);
2304 XML_SetNamespaceDeclHandler(p, start_namespace_handler, NULL);
2305 XML_SetDoctypeDeclHandler(p, start_doctype_handler, NULL);
2308 XML_SetProcessingInstructionHandler (p, proc_handler);
2311 while ((nread = stream->Read (buffer, sizeof (buffer))) >= 0) {
2312 inptr = buffer;
2313 n = nread;
2315 if (first_read && nread > 0) {
2316 // Remove preceding white space
2317 inend = buffer + nread;
2319 while (inptr < inend && g_ascii_isspace (*inptr))
2320 inptr++;
2322 if (inptr == inend)
2323 continue;
2325 n = (inend - inptr);
2326 first_read = false;
2329 parser_info->SetXmlBuffer (inptr);
2330 if (!XML_Parse (p, inptr, n, nread == 0)) {
2331 expat_parser_error (parser_info, XML_GetErrorCode (p));
2332 goto cleanup_and_return;
2335 if (nread == 0)
2336 break;
2339 print_tree (parser_info->top_element, 0);
2341 if (parser_info->top_element) {
2342 res = parser_info->top_element->GetAsValue ();
2343 // We want a copy because the old one is going to be deleted
2344 res = new Value (*res);
2346 if (element_type)
2347 *element_type = parser_info->top_element->info->GetKind ();
2349 if (parser_info->error_args) {
2350 *element_type = Type::INVALID;
2351 goto cleanup_and_return;
2355 cleanup_and_return:
2357 if (!parser_info)
2358 error_args = new ParserErrorEventArgs ("Error opening xaml file", xaml_file, 0, 0, 1, "", "");
2359 else if (parser_info->error_args) {
2360 error_args = parser_info->error_args;
2361 error_args->ref ();
2364 delete stream;
2366 if (p)
2367 XML_ParserFree (p);
2369 if (parser_info)
2370 delete parser_info;
2372 return res;
2375 Value *
2376 XamlLoader::CreateFromString (const char *xaml, bool create_namescope, Type::Kind *element_type, int flags)
2378 return HydrateFromString (xaml, NULL, create_namescope, element_type, flags);
2381 DependencyObject *
2382 value_to_dependency_object (Value *value)
2384 if (!value || !value->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT))
2385 return NULL;
2386 return value->AsDependencyObject ();
2389 DependencyObject *
2390 XamlLoader::CreateDependencyObjectFromFile (const char *xaml, bool create_namescope, Type::Kind *element_type)
2392 return value_to_dependency_object (CreateFromFile (xaml, create_namescope, element_type));
2395 DependencyObject *
2396 XamlLoader::CreateDependencyObjectFromString (const char *xaml, bool create_namescope, Type::Kind *element_type)
2398 return value_to_dependency_object (CreateFromString (xaml, create_namescope, element_type, IMPORT_DEFAULT_XMLNS));
2402 * Hydrates an existing DependencyObject (@object) with the contents from the @xaml
2403 * data
2405 Value *
2406 XamlLoader::HydrateFromString (const char *xaml, Value *object, bool create_namescope, Type::Kind *element_type, int flags)
2408 XML_Parser p = XML_ParserCreateNS ("utf-8", '|');
2409 XamlParserInfo *parser_info = NULL;
2410 Value *res = NULL;
2411 char *start = (char*)xaml;
2412 char *prepend = NULL;
2413 char *append = NULL;
2414 char * inputs [4] = {NULL, NULL, NULL, NULL};
2416 inputs [0] = start;
2418 if (!p) {
2419 LOG_XAML ("can not create parser\n");
2420 goto cleanup_and_return;
2423 #if 0
2424 if (true) {
2425 static int id = 0;
2426 char filename[64];
2427 FILE *fp;
2429 sprintf (filename, "createFromXaml.%d.xaml", id++);
2430 if ((fp = fopen (filename, "wt")) != NULL) {
2431 fwrite (xaml, strlen (xaml), 1, fp);
2432 fclose (fp);
2435 #endif
2437 parser_info = new XamlParserInfo (p, NULL);
2439 parser_info->namescope->SetTemporary (!create_namescope);
2441 parser_info->loader = this;
2442 parser_info->validate_templates = (flags & VALIDATE_TEMPLATES) == VALIDATE_TEMPLATES;
2445 // If we are hydrating, we are not null
2447 if (object != NULL) {
2448 parser_info->hydrate_expecting = object;
2449 parser_info->hydrating = true;
2450 if (Type::IsSubclassOf (parser_info->deployment, object->GetKind (), Type::DEPENDENCY_OBJECT)) {
2451 DependencyObject *dob = object->AsDependencyObject ();
2452 dob->SetIsAttached (true);
2453 dob->SetResourceBase (GetResourceBase());
2455 } else {
2456 parser_info->hydrate_expecting = NULL;
2457 parser_info->hydrating = false;
2460 // from_str gets the default namespaces implictly added
2461 add_default_namespaces (parser_info, (flags & IMPORT_DEFAULT_XMLNS) == IMPORT_DEFAULT_XMLNS);
2463 XML_SetUserData (p, parser_info);
2465 XML_SetElementHandler (p, start_element_handler, end_element_handler);
2466 XML_SetCharacterDataHandler (p, char_data_handler);
2467 XML_SetNamespaceDeclHandler(p, start_namespace_handler, NULL);
2468 XML_SetDoctypeDeclHandler(p, start_doctype_handler, NULL);
2471 XML_SetProcessingInstructionHandler (p, proc_handler);
2474 if (context) {
2475 prepend = context->internal->CreateIgnorableTagOpen ();
2476 append = context->internal->CreateIgnorableTagClose ();
2478 inputs [0] = prepend;
2479 inputs [1] = start;
2480 inputs [2] = append;
2483 for (int i = 0; inputs [i]; i++) {
2484 char *start = inputs [i];
2486 // don't freak out if the <?xml ... ?> isn't on the first line (see #328907)
2487 while (g_ascii_isspace (*start))
2488 start++;
2490 parser_info->SetXmlBuffer (start);
2491 if (!XML_Parse (p, start, strlen (start), inputs [i + 1] == NULL)) {
2492 expat_parser_error (parser_info, XML_GetErrorCode (p));
2493 LOG_XAML ("error parsing: %s\n\n", xaml);
2494 goto cleanup_and_return;
2498 print_tree (parser_info->top_element, 0);
2500 if (parser_info->top_element) {
2501 if (is_legal_top_level_kind (parser_info->top_element->info->GetKind ())) {
2502 res = parser_info->top_element->GetAsValue ();
2503 res = new Value (*res);
2504 if (res->Is (parser_info->deployment, Type::DEPENDENCY_OBJECT) && object) {
2505 DependencyObject *dob = res->AsDependencyObject ();
2506 dob->unref ();
2507 dob->SetIsHydratedFromXaml (parser_info->hydrating);
2511 if (element_type)
2512 *element_type = parser_info->top_element->info->GetKind ();
2514 if (!res && !parser_info->error_args)
2515 parser_info->error_args = new ParserErrorEventArgs ("No DependencyObject found", "", 0, 0, 1, "", "");
2517 if (parser_info->error_args) {
2518 delete res;
2519 res = NULL;
2520 if (element_type)
2521 *element_type = Type::INVALID;
2522 goto cleanup_and_return;
2526 cleanup_and_return:
2528 if (parser_info->error_args) {
2529 error_args = parser_info->error_args;
2530 printf ("Could not parse element %s, attribute %s, error: %s\n",
2531 error_args->xml_element,
2532 error_args->xml_attribute,
2533 error_args->GetErrorMessage());
2536 if (p)
2537 XML_ParserFree (p);
2538 if (parser_info)
2539 delete parser_info;
2540 if (prepend)
2541 g_free (prepend);
2542 if (append)
2543 g_free (append);
2545 return res;
2548 Value *
2549 XamlLoader::CreateFromFileWithError (const char *xaml_file, bool create_namescope, Type::Kind *element_type, MoonError *error)
2551 Value *res = CreateFromFile (xaml_file, create_namescope, element_type);
2552 if (error_args && error_args->GetErrorCode () != -1)
2553 MoonError::FillIn (error, error_args);
2554 return res;
2557 Value *
2558 XamlLoader::CreateFromStringWithError (const char *xaml, bool create_namescope, Type::Kind *element_type, int flags, MoonError *error)
2560 Value *res = CreateFromString (xaml, create_namescope, element_type, flags);
2561 if (error_args && error_args->GetErrorCode () != -1)
2562 MoonError::FillIn (error, error_args);
2563 return res;
2566 Value *
2567 XamlLoader::HydrateFromStringWithError (const char *xaml, Value *object, bool create_namescope, Type::Kind *element_type, int flags, MoonError *error)
2569 Value *res = HydrateFromString (xaml, object, create_namescope, element_type, flags);
2570 if (error_args && error_args->GetErrorCode () != -1)
2571 MoonError::FillIn (error, error_args);
2572 return res;
2575 static int
2576 parse_int (const char **pp, const char *end)
2578 const char *p = *pp;
2579 #if 0
2580 if (optional && AtEnd)
2581 return 0;
2582 #endif
2584 int res = 0;
2585 int count = 0;
2587 while (p <= end && g_ascii_isdigit (*p)) {
2588 res = res * 10 + *p - '0';
2589 p++;
2590 count++;
2593 #if 0
2594 if (count == 0)
2595 formatError = true;
2596 #endif
2598 *pp = p;
2599 return res;
2602 static gint64
2603 parse_ticks (const char **pp, const char *end)
2605 gint64 mag = 1000000;
2606 gint64 res = 0;
2607 bool digitseen = false;
2609 const char *p = *pp;
2611 while (mag > 0 && p <= end && g_ascii_isdigit (*p)) {
2612 res = res + (*p - '0') * mag;
2613 p++;
2614 mag = mag / 10;
2615 digitseen = true;
2618 #if 0
2619 if (!digitseen)
2620 formatError = true;
2621 #endif
2623 *pp = p;
2624 return res;
2627 bool
2628 time_span_from_str (const char *str, TimeSpan *res)
2630 const char *end = str + strlen (str);
2631 const char *p;
2633 bool negative = false;
2634 int days;
2635 int hours;
2636 int minutes;
2637 int seconds;
2638 gint64 ticks;
2640 p = str;
2642 if (*p == '-') {
2643 p++;
2644 negative = true;
2647 days = parse_int (&p, end);
2649 if (*p == '.') {
2650 p++;
2651 hours = parse_int (&p, end);
2653 else {
2654 hours = days;
2655 days = 0;
2658 if (*p == ':') p++;
2659 minutes = parse_int (&p, end);
2660 if (*p == ':') p++;
2661 seconds = parse_int (&p, end);
2662 if (*p == '.') {
2663 p++;
2664 ticks = parse_ticks (&p, end);
2666 else {
2667 ticks = 0;
2670 gint64 t = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
2671 t *= 10000000L;
2673 *res = negative ? (-t - ticks) : (t + ticks);
2675 return true;
2678 bool
2679 repeat_behavior_from_str (const char *str, RepeatBehavior *res)
2681 if (!g_ascii_strcasecmp ("Forever", str)) {
2682 *res = RepeatBehavior::Forever;
2683 return true;
2686 // check for "<float>x".
2688 // XXX more validation work is needed here.. but how do we
2689 // report an error?
2690 const char *x = strchr (str, 'x');
2691 if (x) {
2692 if (*(x + 1) != '\0') {
2693 return false;
2695 else {
2696 char *endptr;
2697 errno = 0;
2698 double d = g_ascii_strtod (str, &endptr);
2700 if (errno || endptr == str)
2701 return false;
2703 *res = RepeatBehavior (d);
2704 return true;
2708 /* XXX RepeatBehavior='XX:XX:XX' syntax is NOT correctly supported by
2709 Silverlight 1.0 (most likely a bug). It works fine in Silverlight 2.0
2710 though. We currently stick to the 2.0 behavior, not replicating the bug
2711 from 1.0.
2713 TimeSpan t;
2714 if (!time_span_from_str (str, &t))
2715 return false;
2717 *res = RepeatBehavior (t);
2719 return true;
2722 bool
2723 duration_from_str (const char *str, Duration *res)
2725 if (!g_ascii_strcasecmp ("Automatic", str)) {
2726 *res = Duration::Automatic;
2727 return true;
2730 if (!g_ascii_strcasecmp ("Forever", str)) {
2731 *res = Duration::Forever;
2732 return true;
2735 TimeSpan ts;
2736 if (!time_span_from_str (str, &ts))
2737 return false;
2739 *res = Duration (ts);
2740 return true;
2743 bool
2744 keytime_from_str (const char *str, KeyTime *res)
2746 if (!g_ascii_strcasecmp ("Uniform", str)) {
2747 *res = KeyTime::Uniform;
2748 return true;
2751 if (!g_ascii_strcasecmp ("Paced", str)) {
2752 *res = KeyTime::Paced;
2753 return true;
2756 /* check for a percentage first */
2757 const char *last = str + strlen(str) - 1;
2758 if (*last == '%') {
2759 char *ep;
2760 double pct = g_ascii_strtod (str, &ep);
2761 if (ep == last) {
2762 *res = KeyTime (pct);
2763 return true;
2767 TimeSpan ts;
2768 if (!time_span_from_str (str, &ts))
2769 return false;
2771 *res = KeyTime (ts);
2772 return true;
2775 bool
2776 key_spline_from_str (const char *str, KeySpline **res)
2778 PointCollection *pts = PointCollection::FromStr (str);
2780 if (!pts)
2781 return false;
2783 if (pts->GetCount () != 2) {
2784 pts->unref ();
2785 return false;
2788 *res = new KeySpline (*pts->GetValueAt (0)->AsPoint (), *pts->GetValueAt (1)->AsPoint ());
2790 pts->unref ();
2792 return true;
2795 Matrix *
2796 matrix_from_str (const char *str)
2798 if (!g_ascii_strcasecmp ("Identity", str)) {
2799 return new Matrix ();
2802 DoubleCollection *values = DoubleCollection::FromStr (str);
2803 Matrix *matrix;
2805 if (!values)
2806 return new Matrix ();
2808 if (values->GetCount () < 6) {
2809 values->unref ();
2810 return NULL;
2813 matrix = new Matrix ();
2814 matrix->SetM11 (values->GetValueAt (0)->AsDouble ());
2815 matrix->SetM12 (values->GetValueAt (1)->AsDouble ());
2816 matrix->SetM21 (values->GetValueAt (2)->AsDouble ());
2817 matrix->SetM22 (values->GetValueAt (3)->AsDouble ());
2818 matrix->SetOffsetX (values->GetValueAt (4)->AsDouble ());
2819 matrix->SetOffsetY (values->GetValueAt (5)->AsDouble ());
2821 values->unref ();
2823 return matrix;
2826 Matrix3D *
2827 matrix3d_from_str (const char *str)
2829 if (!g_ascii_strcasecmp ("Identity", str)) {
2830 return new Matrix3D ();
2833 DoubleCollection *values = DoubleCollection::FromStr (str);
2834 Matrix3D *matrix;
2836 if (!values)
2837 return new Matrix3D ();
2839 if (values->GetCount () < 12) {
2840 values->unref ();
2841 return NULL;
2844 matrix = new Matrix3D ();
2845 matrix->SetM11 (values->GetValueAt (0)->AsDouble ());
2846 matrix->SetM12 (values->GetValueAt (1)->AsDouble ());
2847 matrix->SetM13 (values->GetValueAt (2)->AsDouble ());
2848 matrix->SetM13 (values->GetValueAt (3)->AsDouble ());
2849 matrix->SetM21 (values->GetValueAt (4)->AsDouble ());
2850 matrix->SetM22 (values->GetValueAt (5)->AsDouble ());
2851 matrix->SetM23 (values->GetValueAt (6)->AsDouble ());
2852 matrix->SetM24 (values->GetValueAt (7)->AsDouble ());
2853 matrix->SetM31 (values->GetValueAt (8)->AsDouble ());
2854 matrix->SetM32 (values->GetValueAt (9)->AsDouble ());
2855 matrix->SetM33 (values->GetValueAt (10)->AsDouble ());
2856 matrix->SetM34 (values->GetValueAt (11)->AsDouble ());
2857 matrix->SetOffsetX (values->GetValueAt (12)->AsDouble ());
2858 matrix->SetOffsetY (values->GetValueAt (13)->AsDouble ());
2859 matrix->SetOffsetZ (values->GetValueAt (14)->AsDouble ());
2860 matrix->SetM44 (values->GetValueAt (15)->AsDouble ());
2862 values->unref ();
2864 return matrix;
2867 bool
2868 grid_length_from_str (const char *str, GridLength *grid_length)
2870 if (IS_NULL_OR_EMPTY (str)) {
2871 *grid_length = GridLength (0.0, GridUnitTypePixel);
2872 return true;
2875 if (str [0] == '*') {
2876 *grid_length = GridLength (1.0, GridUnitTypeStar);
2877 return true;
2880 // unit tests shows that "Auto", "auto", "aUtO"... all works
2881 if (!g_ascii_strcasecmp (str, "Auto")) {
2882 *grid_length = GridLength ();
2883 return true;
2886 char *endptr;
2887 errno = 0;
2888 double d = g_ascii_strtod (str, &endptr);
2890 if (errno || endptr == str)
2891 return false;
2893 *grid_length = GridLength (d, *endptr == '*' ? GridUnitTypeStar : GridUnitTypePixel);
2894 return true;
2897 static void
2898 advance (char **in)
2900 char *inptr = *in;
2902 while (*inptr && !g_ascii_isalnum (*inptr) && *inptr != '.' && *inptr != '-' && *inptr != '+')
2903 inptr = g_utf8_next_char (inptr);
2905 *in = inptr;
2908 static bool
2909 get_point (Point *p, char **in)
2911 char *end, *inptr = *in;
2912 double x, y;
2914 x = g_ascii_strtod (inptr, &end);
2915 if (end == inptr)
2916 return false;
2918 inptr = end;
2919 while (g_ascii_isspace (*inptr))
2920 inptr++;
2922 if (*inptr == ',')
2923 inptr++;
2925 while (g_ascii_isspace (*inptr))
2926 inptr++;
2928 y = g_ascii_strtod (inptr, &end);
2929 if (end == inptr)
2930 return false;
2932 p->x = x;
2933 p->y = y;
2935 *in = end;
2937 return true;
2940 static void
2941 make_relative (const Point *cp, Point *mv)
2943 mv->x += cp->x;
2944 mv->y += cp->y;
2947 static bool
2948 more_points_available (char **in)
2950 char *inptr = *in;
2952 while (g_ascii_isspace (*inptr) || *inptr == ',')
2953 inptr++;
2955 *in = inptr;
2957 return (g_ascii_isdigit (*inptr) || *inptr == '.' || *inptr == '-' || *inptr == '+');
2960 Geometry *
2961 geometry_from_str (const char *str)
2963 char *inptr = (char *) str;
2964 Point cp = Point (0, 0);
2965 Point cp1, cp2, cp3;
2966 Point start;
2967 char *end;
2968 PathGeometry *pg = NULL;
2969 FillRule fill_rule = FillRuleEvenOdd;
2970 bool cbz = false; // last figure is a cubic bezier curve
2971 bool qbz = false; // last figure is a quadratic bezier curve
2972 Point cbzp, qbzp; // points needed to create "smooth" beziers
2974 moon_path *path = moon_path_new (10);
2976 while (*inptr) {
2977 if (g_ascii_isspace (*inptr))
2978 inptr++;
2980 if (!inptr[0])
2981 break;
2983 bool relative = false;
2985 char c = *inptr;
2986 inptr = g_utf8_next_char (inptr);
2988 switch (c) {
2989 case 'f':
2990 case 'F':
2991 advance (&inptr);
2993 if (*inptr == '0')
2994 fill_rule = FillRuleEvenOdd;
2995 else if (*inptr == '1')
2996 fill_rule = FillRuleNonzero;
2997 else
2998 // FIXME: else it's a bad value and nothing should be rendered
2999 goto bad_pml; // partial: only this Path won't be rendered
3001 inptr = g_utf8_next_char (inptr);
3002 break;
3003 case 'm':
3004 relative = true;
3005 case 'M':
3006 if (!get_point (&cp1, &inptr))
3007 break;
3009 if (relative)
3010 make_relative (&cp, &cp1);
3012 // start point
3013 moon_move_to (path, cp1.x, cp1.y);
3015 start.x = cp.x = cp1.x;
3016 start.y = cp.y = cp1.y;
3018 advance (&inptr);
3019 while (more_points_available (&inptr)) {
3020 if (!get_point (&cp1, &inptr))
3021 break;
3023 if (relative)
3024 make_relative (&cp, &cp1);
3026 moon_line_to (path, cp1.x, cp1.y);
3029 cp.x = cp1.x;
3030 cp.y = cp1.y;
3031 cbz = qbz = false;
3032 break;
3034 case 'l':
3035 relative = true;
3036 case 'L':
3038 while (more_points_available (&inptr)) {
3039 if (!get_point (&cp1, &inptr))
3040 break;
3042 if (relative)
3043 make_relative (&cp, &cp1);
3045 moon_line_to (path, cp1.x, cp1.y);
3047 cp.x = cp1.x;
3048 cp.y = cp1.y;
3050 advance (&inptr);
3052 cbz = qbz = false;
3053 break;
3056 case 'h':
3057 relative = true;
3058 case 'H':
3060 double x = g_ascii_strtod (inptr, &end);
3061 if (end == inptr)
3062 break;
3064 inptr = end;
3066 if (relative)
3067 x += cp.x;
3068 cp = Point (x, cp.y);
3070 moon_line_to (path, cp.x, cp.y);
3071 cbz = qbz = false;
3072 break;
3075 case 'v':
3076 relative = true;
3077 case 'V':
3079 double y = g_ascii_strtod (inptr, &end);
3080 if (end == inptr)
3081 break;
3083 inptr = end;
3085 if (relative)
3086 y += cp.y;
3087 cp = Point (cp.x, y);
3089 moon_line_to (path, cp.x, cp.y);
3090 cbz = qbz = false;
3091 break;
3094 case 'c':
3095 relative = true;
3096 case 'C':
3098 while (more_points_available (&inptr)) {
3099 if (!get_point (&cp1, &inptr))
3100 break;
3102 if (relative)
3103 make_relative (&cp, &cp1);
3105 advance (&inptr);
3107 if (!get_point (&cp2, &inptr))
3108 break;
3110 if (relative)
3111 make_relative (&cp, &cp2);
3113 advance (&inptr);
3115 if (!get_point (&cp3, &inptr))
3116 break;
3118 if (relative)
3119 make_relative (&cp, &cp3);
3121 advance (&inptr);
3123 moon_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y, cp3.x, cp3.y);
3125 cp1.x = cp3.x;
3126 cp1.y = cp3.y;
3128 cp.x = cp3.x;
3129 cp.y = cp3.y;
3130 cbz = true;
3131 cbzp.x = cp2.x;
3132 cbzp.y = cp2.y;
3133 qbz = false;
3134 break;
3136 case 's':
3137 relative = true;
3138 case 'S':
3140 while (more_points_available (&inptr)) {
3141 if (!get_point (&cp2, &inptr))
3142 break;
3144 if (relative)
3145 make_relative (&cp, &cp2);
3147 advance (&inptr);
3149 if (!get_point (&cp3, &inptr))
3150 break;
3152 if (relative)
3153 make_relative (&cp, &cp3);
3155 if (cbz) {
3156 cp1.x = 2 * cp.x - cbzp.x;
3157 cp1.y = 2 * cp.y - cbzp.y;
3158 } else
3159 cp1 = cp;
3161 moon_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y, cp3.x, cp3.y);
3162 cbz = true;
3163 cbzp.x = cp2.x;
3164 cbzp.y = cp2.y;
3166 cp.x = cp3.x;
3167 cp.y = cp3.y;
3169 advance (&inptr);
3171 qbz = false;
3172 break;
3174 case 'q':
3175 relative = true;
3176 case 'Q':
3178 while (more_points_available (&inptr)) {
3179 if (!get_point (&cp1, &inptr))
3180 break;
3182 if (relative)
3183 make_relative (&cp, &cp1);
3185 advance (&inptr);
3187 if (!get_point (&cp2, &inptr))
3188 break;
3190 if (relative)
3191 make_relative (&cp, &cp2);
3193 advance (&inptr);
3195 moon_quad_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y);
3197 cp.x = cp2.x;
3198 cp.y = cp2.y;
3200 qbz = true;
3201 qbzp.x = cp1.x;
3202 qbzp.y = cp1.y;
3203 cbz = false;
3204 break;
3206 case 't':
3207 relative = true;
3208 case 'T':
3210 while (more_points_available (&inptr)) {
3211 if (!get_point (&cp2, &inptr))
3212 break;
3214 if (relative)
3215 make_relative (&cp, &cp2);
3217 if (qbz) {
3218 cp1.x = 2 * cp.x - qbzp.x;
3219 cp1.y = 2 * cp.y - qbzp.y;
3220 } else
3221 cp1 = cp;
3223 moon_quad_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y);
3224 qbz = true;
3225 qbzp.x = cp1.x;
3226 qbzp.y = cp1.y;
3228 cp.x = cp2.x;
3229 cp.y = cp2.y;
3231 advance (&inptr);
3233 cbz = false;
3234 break;
3236 case 'a':
3237 relative = true;
3238 case 'A':
3240 while (more_points_available (&inptr)) {
3241 if (!get_point (&cp1, &inptr))
3242 break;
3244 advance (&inptr);
3246 double angle = g_ascii_strtod (inptr, &end);
3247 if (end == inptr)
3248 break;
3250 inptr = end;
3251 advance (&inptr);
3253 int is_large = strtol (inptr, &end, 10);
3254 if (end == inptr)
3255 break;
3257 inptr = end;
3258 advance (&inptr);
3260 int sweep = strtol (inptr, &end, 10);
3261 if (end == inptr)
3262 break;
3264 inptr = end;
3265 advance (&inptr);
3267 if (!get_point (&cp2, &inptr))
3268 break;
3270 if (relative)
3271 make_relative (&cp, &cp2);
3273 moon_arc_to (path, cp1.x, cp1.y, angle, is_large, sweep, cp2.x, cp2.y);
3275 cp.x = cp2.x;
3276 cp.y = cp2.y;
3278 advance (&inptr);
3280 cbz = qbz = false;
3281 break;
3283 case 'z':
3284 case 'Z':
3285 moon_line_to (path, start.x, start.y);
3286 moon_close_path (path);
3287 moon_move_to (path, start.x, start.y);
3289 cp.x = start.x;
3290 cp.y = start.y;
3291 cbz = qbz = false;
3292 break;
3293 default:
3294 break;
3298 pg = new PathGeometry (path);
3299 pg->SetFillRule (fill_rule);
3300 return pg;
3302 bad_pml:
3303 moon_path_destroy (path);
3304 return NULL;
3307 static bool
3308 value_is_explicit_null (const char *str)
3310 return !strcmp ("{x:Null}", str);
3313 static bool
3314 is_managed_kind (Type::Kind kind)
3317 if (kind == Type::MANAGED ||
3318 kind == Type::OBJECT ||
3319 kind == Type::URI ||
3320 kind == Type::MANAGEDTYPEINFO ||
3321 kind == Type::DEPENDENCYPROPERTY)
3322 return true;
3324 return false;
3327 static bool
3328 kind_requires_managed_load (Type::Kind kind)
3330 if (kind == Type::USERCONTROL) {
3331 return true;
3334 return false;
3337 static bool
3338 is_legal_top_level_kind (Type::Kind kind)
3340 if (kind == Type::MANAGED || kind == Type::OBJECT || Type::IsSubclassOf (Deployment::GetCurrent (), kind, Type::DEPENDENCY_OBJECT))
3341 return true;
3342 return false;
3345 // NOTE: Keep definition in sync with class/System.Windows/Mono/NativeMethods.cs
3346 bool
3347 value_from_str_with_typename (const char *type_name, const char *prop_name, const char *str, Value **v)
3349 Type *t = Type::Find (Deployment::GetCurrent (), type_name);
3350 if (!t)
3351 return false;
3353 return value_from_str (t->GetKind (), prop_name, str, v);
3356 char *
3357 expand_property_path (XamlParserInfo *p, PropertyPath *path)
3359 if (!path->path)
3360 return NULL;
3362 bool expanded = false;
3363 GString *res = g_string_new (path->path);
3365 int len = strlen (res->str);
3366 for (int i = 0; i < len; i++) {
3367 if (res->str [i] == ':') {
3368 int e = i;
3369 int s = i - 1;
3370 int te = i + 1;
3371 for ( ; s > 0; s--) {
3372 if (!g_ascii_isalnum (res->str [s]))
3373 break;
3376 for ( ; te < len; te++) {
3377 if (!g_ascii_isalpha (res->str [te]) || res->str [te] == '_')
3378 break;
3381 char *prefix = g_strndup (res->str + s + 1, e - s - 1);
3382 char *type = g_strndup (res->str + e + 1, te - e - 1);
3384 res = g_string_erase (res, s + 1, te - s - 1);
3386 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
3387 if (!ns) {
3388 g_free (prefix);
3389 g_free (type);
3390 g_string_free (res, true);
3391 return NULL;
3394 XamlElementInfo *info = ns->FindElement (p, type, NULL, false);
3396 if (!info) {
3397 g_free (prefix);
3398 g_free (type);
3399 g_string_free (res, true);
3400 return NULL;
3403 char *uri = g_strdup_printf ("'%s'", Type::Find (p->deployment, info->GetKind ())->GetName ());
3405 res = g_string_insert (res, s + 1, uri);
3406 i = s + 1 + strlen (uri);
3407 len = strlen (res->str);
3409 delete info;
3410 g_free (uri);
3411 g_free (prefix);
3412 g_free (type);
3414 expanded = true;
3418 if (!expanded) {
3419 g_string_free (res, true);
3420 return NULL;
3423 char *expanded_str = res->str;
3424 g_string_free (res, false);
3426 return expanded_str;
3429 bool
3430 value_from_str (Type::Kind type, const char *prop_name, const char *str, Value **v)
3432 bool v_set = false;
3434 value_from_str_with_parser (NULL, type, prop_name, str, v, &v_set);
3436 return v_set;
3439 bool
3440 xaml_bool_from_str (const char *s, bool *res)
3442 bool b;
3443 char *endptr;
3445 if (!g_ascii_strcasecmp ("true", s))
3446 b = true;
3447 else if (!g_ascii_strcasecmp ("false", s))
3448 b = false;
3449 else {
3450 // Check if it's a string representing a decimal value
3451 gint64 l;
3453 errno = 0;
3454 l = strtol (s, &endptr, 10);
3456 if (errno || endptr == s || *endptr || l > G_MAXINT32 || l < G_MININT32)
3457 return false;;
3459 if (l == 0)
3460 b = false;
3461 else
3462 b = true;
3465 *res = b;
3466 return true;
3469 static bool
3470 value_from_str_with_parser (XamlParserInfo *p, Type::Kind type, const char *prop_name, const char *str, Value **v, bool *v_set)
3472 char *endptr;
3473 *v = NULL;
3475 if (value_is_explicit_null (str)) {
3476 *v = NULL;
3477 *v_set = true;
3478 return true;
3481 char *s = g_strdup (str);
3483 if (type == Type::OBJECT || type == Type::STRING) {
3484 // object and string use the literal string
3486 else {
3487 // everything else depends on the string being stripped
3488 s = g_strstrip (s);
3491 switch (type) {
3492 case Type::OBJECT: {
3493 // not much more can do here, unless we want to try to
3494 // probe str to see if it's actually meant to be a
3495 // specific type. just assume it's a string.
3496 *v = new Value (s);
3497 *v_set = true;
3498 break;
3501 case Type::BOOL: {
3502 bool b;
3504 if (!xaml_bool_from_str (s, &b))
3505 break;
3507 *v = new Value (b);
3508 *v_set = true;
3509 break;
3511 case Type::DOUBLE: {
3512 double d;
3514 // empty string should not reset default values with 0
3516 // FIXME: this causes a 2.0 unit test to fail (PrimitiveTest.ParseEmptyDouble)
3517 if (IS_NULL_OR_EMPTY(s)) {
3518 g_free (s);
3519 return false;
3522 bool is_nan = false;
3523 if (!g_ascii_strcasecmp (s, "NAN"))
3524 is_nan = true;
3525 else {
3526 errno = 0;
3527 d = g_ascii_strtod (s, &endptr);
3530 if (is_nan || errno || endptr == s || *endptr) {
3531 if (prop_name
3532 && (!strcmp (prop_name, "Width") || !strcmp (prop_name, "Height"))
3533 && (!g_ascii_strcasecmp (s, "Auto") || is_nan))
3534 d = NAN;
3535 else
3536 break;
3539 *v = new Value (d);
3540 *v_set = true;
3541 break;
3543 case Type::INT64: {
3544 gint64 l;
3546 errno = 0;
3547 l = strtol (s, &endptr, 10);
3549 if (errno || endptr == s)
3550 break;
3552 *v = new Value (l, Type::INT64);
3553 *v_set = true;
3554 break;
3556 case Type::TIMESPAN: {
3557 TimeSpan ts;
3559 if (!time_span_from_str (s, &ts))
3560 break;
3562 *v = new Value (ts, Type::TIMESPAN);
3563 *v_set = true;
3564 break;
3566 case Type::INT32: {
3567 int i;
3569 if (IS_NULL_OR_EMPTY(s))
3570 i = 0;
3571 else if (g_ascii_isalpha (s[0]) && prop_name) {
3572 i = enums_str_to_int (prop_name, s);
3573 if (i == -1) {
3574 // g_warning ("'%s' enum is not valid on '%s' property", str, prop_name);
3575 break;
3577 } else {
3578 errno = 0;
3579 long l = strtol (s, &endptr, 10);
3581 if (errno || endptr == s)
3582 break;
3584 i = (int) l;
3587 *v = new Value (i);
3588 *v_set = true;
3589 break;
3591 case Type::CHAR: {
3592 gunichar unichar = g_utf8_get_char_validated (str, -1);
3593 const char *next;
3595 if ((int) unichar < 0)
3596 break;
3598 if (!(next = g_utf8_next_char (str)) || *next != '\0')
3599 break;
3601 *v = new Value (unichar, Type::CHAR);
3602 *v_set = true;
3603 break;
3605 case Type::STRING: {
3606 *v = new Value (str);
3607 *v_set = true;
3608 break;
3610 case Type::COLOR: {
3611 Color *c = color_from_str (s);
3612 if (c == NULL)
3613 break;
3614 *v = new Value (*c);
3615 *v_set = true;
3616 delete c;
3617 break;
3619 case Type::REPEATBEHAVIOR: {
3620 RepeatBehavior rb = RepeatBehavior::Forever;
3622 if (!repeat_behavior_from_str (s, &rb))
3623 break;
3625 *v = new Value (rb);
3626 *v_set = true;
3627 break;
3629 case Type::DURATION: {
3630 Duration d = Duration::Forever;
3632 if (!duration_from_str (s, &d))
3633 break;
3635 *v = new Value (d);
3636 *v_set = true;
3637 break;
3639 case Type::KEYTIME: {
3640 KeyTime kt = KeyTime::Paced;
3642 if (!keytime_from_str (s, &kt))
3643 break;
3645 *v = new Value (kt);
3646 *v_set = true;
3647 break;
3649 case Type::KEYSPLINE: {
3650 KeySpline *ks;
3652 if (!key_spline_from_str (s, &ks))
3653 break;
3655 *v = Value::CreateUnrefPtr (ks);
3656 *v_set = true;
3657 break;
3659 case Type::BRUSH:
3660 case Type::SOLIDCOLORBRUSH: {
3661 // Only solid color brushes can be specified using attribute syntax
3662 Color *c = color_from_str (s);
3664 if (c == NULL)
3665 break;
3667 SolidColorBrush *scb = new SolidColorBrush ();
3669 scb->SetColor (c);
3670 delete c;
3672 *v = Value::CreateUnrefPtr (scb);
3673 *v_set = true;
3674 break;
3676 case Type::POINT: {
3677 Point p;
3679 if (!Point::FromStr (s, &p))
3680 break;
3682 *v = new Value (p);
3683 *v_set = true;
3684 break;
3686 case Type::SIZE: {
3687 Size size;
3689 if (!Size::FromStr (s, &size))
3690 break;
3692 *v = new Value (size);
3693 *v_set = true;
3694 break;
3696 case Type::RECT: {
3697 Rect rect;
3699 if (!Rect::FromStr (s, &rect))
3700 break;
3702 *v = new Value (rect);
3703 *v_set = true;
3704 break;
3706 case Type::CACHEMODE: {
3707 if (!strcmp (s, "BitmapCache")) {
3708 BitmapCache *bc = new BitmapCache ();
3709 *v = Value::CreateUnrefPtr (bc);
3710 *v_set = true;
3712 break;
3714 case Type::URI: {
3715 Uri uri;
3717 if (!uri.Parse (s)) {
3718 break;
3721 *v = new Value (uri);
3722 *v_set = true;
3723 break;
3725 case Type::DOUBLE_COLLECTION: {
3726 DoubleCollection *doubles = DoubleCollection::FromStr (s);
3727 if (!doubles) {
3728 *v = Value::CreateUnrefPtr (new DoubleCollection ());
3729 *v_set = true;
3730 break;
3733 *v = Value::CreateUnrefPtr (doubles);
3734 *v_set = true;
3735 break;
3737 case Type::POINT_COLLECTION: {
3738 PointCollection *points = PointCollection::FromStr (s);
3739 if (!points) {
3740 *v = Value::CreateUnrefPtr (new PointCollection ());
3741 *v_set = true;
3742 break;
3745 *v = Value::CreateUnrefPtr (points);
3746 *v_set = true;
3747 break;
3749 case Type::TRANSFORMGROUP: {
3750 if (IS_NULL_OR_EMPTY(s))
3751 break;
3753 Matrix *mv = matrix_from_str (s);
3754 if (!mv)
3755 break;
3757 TransformGroup *tg = new TransformGroup ();
3758 MatrixTransform *t = new MatrixTransform ();
3759 t->SetValue (MatrixTransform::MatrixProperty, Value (mv));
3761 tg->GetChildren()->Add (t);
3762 t->unref ();
3764 *v = new Value (tg);
3765 *v_set = true;
3766 tg->unref ();
3767 mv->unref ();
3768 break;
3770 case Type::TRANSFORM:
3772 if (!g_ascii_strcasecmp ("Identity", str)) {
3773 *v = NULL;
3774 *v_set = true;
3775 break;
3778 // Intentional fall through, you can create a matrix from a TRANSFORM property, but not using Identity
3779 case Type::MATRIXTRANSFORM:
3781 if (IS_NULL_OR_EMPTY(s))
3782 break;
3784 Matrix *mv = matrix_from_str (s);
3785 if (!mv)
3786 break;
3788 MatrixTransform *t = new MatrixTransform ();
3789 t->SetValue (MatrixTransform::MatrixProperty, Value (mv));
3791 *v = new Value (t);
3792 *v_set = true;
3793 t->unref ();
3794 mv->unref ();
3795 break;
3797 case Type::UNMANAGEDMATRIX:
3798 case Type::MATRIX: {
3799 // note: unlike TRANSFORM this creates an empty, identity, matrix for an empty string
3800 Matrix *matrix = matrix_from_str (s);
3801 if (!matrix)
3802 break;
3804 *v = new Value (matrix);
3805 *v_set = true;
3806 matrix->unref ();
3807 break;
3809 case Type::PROJECTION:
3811 if (!g_ascii_strcasecmp ("Identity", str)) {
3812 *v = NULL;
3813 *v_set = true;
3814 break;
3817 // Intentional fall through, you can create a matrix from a PROJECTION property, but not using Identity
3818 case Type::MATRIX3DPROJECTION:
3820 if (IS_NULL_OR_EMPTY(s))
3821 break;
3823 Matrix3D *mv = matrix3d_from_str (s);
3824 if (!mv)
3825 break;
3827 Matrix3DProjection *p = new Matrix3DProjection ();
3828 p->SetValue (Matrix3DProjection::ProjectionMatrixProperty, Value (mv));
3830 *v = new Value (p);
3831 *v_set = true;
3832 p->unref ();
3833 mv->unref ();
3834 break;
3836 case Type::UNMANAGEDMATRIX3D:
3837 case Type::MATRIX3D: {
3838 Matrix3D *matrix = matrix3d_from_str (s);
3839 if (!matrix)
3840 break;
3842 *v = new Value (matrix);
3843 *v_set = true;
3844 matrix->unref ();
3845 break;
3847 case Type::PATHGEOMETRY:
3848 case Type::GEOMETRY: {
3849 Geometry *geometry = geometry_from_str (s);
3851 if (!geometry)
3852 break;
3854 *v = new Value (geometry);
3855 *v_set = true;
3856 geometry->unref ();
3857 break;
3859 case Type::THICKNESS: {
3860 Thickness t;
3862 if (!Thickness::FromStr (s, &t))
3863 break;
3865 *v = new Value (t);
3866 *v_set = true;
3867 break;
3869 case Type::CORNERRADIUS: {
3870 CornerRadius c;
3872 if (!CornerRadius::FromStr (s, &c))
3873 break;
3875 *v = new Value (c);
3876 *v_set = true;
3877 break;
3879 case Type::GRIDLENGTH: {
3880 GridLength grid_length;
3882 if (!grid_length_from_str (s, &grid_length))
3883 break;
3885 *v = new Value (grid_length);
3886 *v_set = true;
3887 break;
3889 case Type::IMAGESOURCE:
3890 case Type::BITMAPIMAGE: {
3891 Uri uri;
3893 if (!uri.Parse (s))
3894 break;
3896 BitmapImage *bi = new BitmapImage ();
3898 bi->SetUriSource (&uri);
3900 *v = Value::CreateUnrefPtr (bi);
3901 *v_set = true;
3903 break;
3905 case Type::MULTISCALETILESOURCE:
3906 case Type::DEEPZOOMIMAGETILESOURCE: {
3907 // As far as I know the only thing you can create here is a URI based DeepZoomImageTileSource
3908 Uri uri;
3909 if (!uri.Parse (s))
3910 break;
3911 *v = Value::CreateUnrefPtr (new DeepZoomImageTileSource (&uri));
3912 *v_set = true;
3914 break;
3916 case Type::FONTFAMILY: {
3917 *v = new Value (FontFamily (s));
3918 *v_set = true;
3919 break;
3921 case Type::FONTWEIGHT: {
3922 int fw = enums_str_to_int ("FontWeight", s);
3923 if (fw != -1) {
3924 *v = new Value (FontWeight ((FontWeights)fw));
3925 *v_set = true;
3927 break;
3929 case Type::FONTSTYLE: {
3930 int fs = enums_str_to_int ("FontStyle", s);
3931 if (fs != -1) {
3932 *v = new Value (FontStyle ((FontStyles)fs));
3933 *v_set = true;
3935 break;
3937 case Type::FONTSTRETCH: {
3938 int fs = enums_str_to_int ("FontStretch", s);
3939 if (fs != -1) {
3940 *v = new Value (FontStretch ((FontStretches)fs));
3941 *v_set = true;
3943 break;
3945 case Type::PROPERTYPATH: {
3946 PropertyPath path (s);
3947 path.expanded_path = expand_property_path (p, &path);
3948 *v = new Value (path);
3949 *v_set = true;
3950 break;
3952 default:
3953 // we don't care about NULL or empty values
3954 if (!IS_NULL_OR_EMPTY (s)) {
3955 g_free (s);
3956 return true;
3960 g_free (s);
3961 return true;
3964 bool
3965 XamlElementInstance::TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value)
3967 const char* prop_name = info->GetContentProperty (p);
3969 if (!prop_name)
3970 return false;
3972 DependencyProperty *dep = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, info->GetKind ()), prop_name);
3973 if (!dep)
3974 return false;
3976 bool is_collection = Type::IsSubclassOf (p->deployment, dep->GetPropertyType(), Type::DEPENDENCY_OBJECT_COLLECTION);
3978 if (!is_collection && Type::IsSubclassOf (p->deployment, value->info->GetKind (), dep->GetPropertyType())) {
3979 MoonError err;
3980 if (!item->SetValueWithError (dep, value->GetAsValue (), &err)) {
3981 parser_error (p, value->element_name, NULL, err.code, err.message);
3982 return false;
3984 return true;
3987 // We only want to enter this if statement if we are NOT dealing with the content property element,
3988 // otherwise, attempting to use explicit property setting, would add the content property element
3989 // to the content property element collection
3990 if (is_collection && dep->GetPropertyType() != value->info->GetKind ()) {
3991 Value *col_v = item->GetValue (dep);
3992 Collection *col;
3994 if (!col_v) {
3995 col = collection_new (dep->GetPropertyType ());
3996 item->SetValue (dep, Value (col));
3997 col->unref ();
3998 } else {
3999 col = (Collection *) col_v->AsCollection ();
4002 MoonError err;
4003 if (-1 == col->AddWithError (value->GetAsValue (), &err)) {
4004 parser_error (p, value->element_name, NULL, err.code, err.message);
4005 return false;
4008 return true;
4011 return false;
4014 bool
4015 XamlElementInstance::TrySetContentProperty (XamlParserInfo *p, const char *value)
4017 const char* prop_name = info->GetContentProperty (p);
4019 if (!prop_name) {
4020 if (info->GetKind () == Type::ICON) {
4021 prop_name = "Source";
4022 } else
4023 return false;
4026 Type::Kind prop_type = p->current_element->info->GetKind ();
4027 DependencyProperty *content = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, prop_type), prop_name);
4029 // TODO: There might be other types that can be specified here,
4030 // but string is all i have found so far. If you can specify other
4031 // types, i should pull the property setting out of set_attributes
4032 // and use that code
4034 if (content && (content->GetPropertyType ()) == Type::STRING && value) {
4035 item->SetValue (content, Value (g_strstrip (p->cdata->str)));
4036 return true;
4037 } else if (content && (content->GetPropertyType ()) == Type::URI && value) {
4038 Uri uri;
4040 if (!uri.Parse (g_strstrip (p->cdata->str)))
4041 return false;
4043 item->SetValue (content, Value (uri));
4044 return true;
4045 } else if (Type::IsSubclassOf (p->deployment, info->GetKind (), Type::TEXTBLOCK)) {
4046 TextBlock *textblock = (TextBlock *) item;
4047 InlineCollection *inlines = textblock->GetInlines ();
4048 Inline *last = NULL;
4050 if (inlines && inlines->GetCount () > 0)
4051 last = inlines->GetValueAt (inlines->GetCount () - 1)->AsInline ();
4053 if (!p->cdata_content) {
4054 if (p->next_element && !strcmp (p->next_element, "Run") && last && last->GetObjectType () == Type::RUN &&
4055 !last->GetAutogenerated ()) {
4056 // LWSP between <Run> elements is to be treated as a single-SPACE <Run> element
4057 // Note: p->cdata is already canonicalized
4058 } else {
4059 // This is one of the following cases:
4061 // 1. LWSP before the first <Run> element
4062 // 2. LWSP after the last <Run> element
4063 // 3. LWSP between <Run> and <LineBreak> elements
4064 return true;
4066 } else {
4067 if (!p->next_element || !strcmp (p->next_element, "LineBreak"))
4068 g_strchomp (p->cdata->str);
4070 if (!last || last->GetObjectType () != Type::RUN || last->GetAutogenerated ())
4071 g_strchug (p->cdata->str);
4074 Run *run = new Run ();
4075 run->SetText (p->cdata->str);
4077 if (!inlines) {
4078 inlines = new InlineCollection ();
4079 textblock->SetInlines (inlines);
4080 inlines->unref ();
4083 inlines->Add (run);
4084 run->unref ();
4085 return true;
4088 return false;
4091 bool
4092 XamlElementInstance::SetUnknownAttribute (XamlParserInfo *p, const char *name, const char *value)
4094 if (!p->loader)
4095 return false;
4097 Value v = Value (value);
4098 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, name, &v, NULL)) {
4099 return false;
4101 return true;
4104 void
4105 XamlElementInstance::SetDelayedProperties (XamlParserInfo *p)
4107 GSList *walk = delayed_properties;
4109 while (walk) {
4110 DelayedProperty *prop = (DelayedProperty *) walk->data;
4112 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), prop->xmlns, prop->name, prop->value, NULL, XamlCallbackData::SETTING_DELAYED_PROPERTY)) {
4113 parser_error (p, element_name, prop->name, 2012,
4114 "Unknown property %s on element %s.",
4115 prop->name, element_name);
4116 return;
4119 walk = walk->next;
4124 XamlElementInfo *
4125 XamlElementInstance::FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot)
4127 // We didn't find anything so try looking up in managed
4128 if (!p->loader)
4129 return NULL;
4131 Value *v = new Value ();
4132 if (p->loader->LookupObject (p, p->GetTopElementPtr (), GetAsValue (), p->current_namespace->GetUri (), el, false, true, v)) {
4133 char *type_name = g_strndup (el, dot - el);
4135 XamlElementInfoManaged *res = new XamlElementInfoManaged (g_strdup (p->current_namespace->GetUri ()), el, info, v->GetKind (), v);
4136 XamlElementInfo *container = p->current_namespace->FindElement (p, type_name, NULL, false);
4137 info->SetPropertyOwnerKind (container->GetKind ());
4138 g_free (type_name);
4139 return res;
4142 delete v;
4143 return NULL;
4146 static XamlElementInfo *
4147 create_element_info_from_imported_managed_type (XamlParserInfo *p, const char *name, const char **attr, bool create)
4149 if (!p->loader)
4150 return NULL;
4152 char* type_name = NULL;
4153 char* type_xmlns = NULL;
4154 const char* use_xmlns = NULL;
4156 if (x_namespace) {
4157 // We might have an x:Class attribute specified, so we need to use that for the
4158 // type_name that we pass to LookupObject
4159 if (strcmp ("Application", name)) {
4160 type_name = x_namespace->FindTypeName (attr, &type_xmlns);
4161 if (type_name) {
4162 name = type_name;
4163 use_xmlns = type_xmlns;
4165 if (!p->hydrating) {
4166 parser_error (p, name, "x:Class", 4005, "Cannot specify x:Class in xaml files outside of a xap.");
4167 return NULL;
4173 Value *v = new Value ();
4174 if (!p->loader->LookupObject (p, use_xmlns ? p->GetTopElementPtr () : NULL, NULL, use_xmlns, name, create, false, v)) {
4175 delete v;
4176 if (type_name)
4177 g_free (type_name);
4178 if (type_xmlns)
4179 g_free (type_xmlns);
4180 return NULL;
4183 XamlElementInfoImportedManaged *info = new XamlElementInfoImportedManaged (g_strdup (name), NULL, v);
4185 if (create) {
4186 if (v->Is (p->deployment, Type::DEPENDENCY_OBJECT))
4187 p->AddCreatedElement (v->AsDependencyObject());
4190 return info;
4194 const char *
4195 XamlElementInfoNative::GetContentProperty (XamlParserInfo *p)
4197 return type->GetContentPropertyName ();
4200 XamlElementInstance *
4201 XamlElementInfoNative::CreateElementInstance (XamlParserInfo *p)
4203 if (type->IsValueType ())
4204 return new XamlElementInstanceValueType (this, p, GetName (), XamlElementInstance::ELEMENT);
4205 else if (type->IsSubclassOf (Type::FRAMEWORKTEMPLATE))
4206 return new XamlElementInstanceTemplate (this, p, GetName (), XamlElementInstance::ELEMENT);
4207 else
4208 return new XamlElementInstanceNative (this, p, GetName (), XamlElementInstance::ELEMENT);
4211 XamlElementInstance *
4212 XamlElementInfoNative::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4214 XamlElementInstance *res = new XamlElementInstanceNative (this, p, GetName (), XamlElementInstance::ELEMENT, false);
4215 res->SetDependencyObject (o->AsDependencyObject ());
4217 return res;
4220 XamlElementInfo *
4221 XamlElementInstanceNative::FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot)
4223 if (IsDependencyObject ()) {
4224 const char *prop_name = dot + 1;
4225 DependencyProperty *prop = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, info->GetKind ()), prop_name);
4226 if (prop) {
4227 XamlElementInfoNative *info = new XamlElementInfoNative (Type::Find (p->deployment, prop->GetPropertyType ()));
4228 info->SetPropertyOwnerKind (prop->GetOwnerType ());
4229 return info;
4233 return XamlElementInstance::FindPropertyElement (p, el, dot);
4236 XamlElementInstance *
4237 XamlElementInfoNative::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4239 return new XamlElementInstanceNative (this, p, name, XamlElementInstance::PROPERTY, false);
4242 XamlElementInstanceNative::XamlElementInstanceNative (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item) :
4243 XamlElementInstance (element_info, name, type)
4245 this->element_info = element_info;
4246 this->parser_info = parser_info;
4247 if (create_item)
4248 SetDependencyObject (CreateItem ());
4253 DependencyObject *
4254 XamlElementInstanceNative::CreateItem ()
4256 XamlElementInstance *walk = parser_info->current_element;
4257 Type *type = element_info->GetType ();
4259 DependencyObject *item = NULL;
4260 DependencyProperty *dep = NULL;
4262 if (type->IsSubclassOf (Type::COLLECTION) || type->IsSubclassOf (Type::RESOURCE_DICTIONARY)) {
4263 // If we are creating a collection, try walking up the element tree,
4264 // to find the parent that we belong to and using that instance for
4265 // our collection, instead of creating a new one
4267 // We attempt to advance past the property setter, because we might be dealing with a
4268 // content element
4270 if (walk && walk->element_type == XamlElementInstance::PROPERTY) {
4271 char **prop_name = g_strsplit (walk->element_name, ".", -1);
4273 walk = walk->parent;
4274 dep = DependencyProperty::GetDependencyProperty (Type::Find (parser_info->deployment, walk->info->GetKind ()), prop_name [1]);
4276 g_strfreev (prop_name);
4277 } else if (walk && walk->info->GetContentProperty (parser_info)) {
4278 dep = DependencyProperty::GetDependencyProperty (Type::Find (parser_info->deployment, walk->info->GetKind ()),
4279 (char *) walk->info->GetContentProperty (parser_info));
4282 if (dep && Type::IsSubclassOf (parser_info->deployment, dep->GetPropertyType(), type->GetKind ())) {
4283 Value *v = ((DependencyObject * ) walk->GetAsDependencyObject ())->GetValue (dep);
4284 if (v) {
4285 item = v->AsDependencyObject ();
4286 dep = NULL;
4288 // note: if !v then the default collection is NULL (e.g. PathFigureCollection)
4292 if (!item) {
4293 item = element_info->GetType()->IsCtorVisible() ? element_info->GetType ()->CreateInstance () : NULL;
4295 if (item) {
4296 parser_info->AddCreatedElement (item);
4298 // in case we must store the collection into the parent
4299 if (dep && dep->GetPropertyType() == type->GetKind ()) {
4300 MoonError err;
4301 Value item_value (item);
4302 if (!((DependencyObject * ) walk->GetAsDependencyObject ())->SetValueWithError (dep, &item_value, &err))
4303 parser_error (parser_info, element_name, NULL, err.code, err.message);
4305 } else {
4306 parser_error (parser_info, element_name, NULL, 2007, "Unknown element: %s.", element_name);
4310 return item;
4313 bool
4314 XamlElementInstanceNative::SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value)
4316 if (property->info->RequiresManagedSet () || value->info->RequiresManagedSet ())
4317 return p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, value->GetAsValue (), NULL);
4319 return dependency_object_set_property (p, this, property, value, true);
4322 bool
4323 XamlElementInstanceNative::SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value)
4325 char **prop_name = g_strsplit (property->element_name, ".", -1);
4326 Type *owner = Type::Find (p->deployment, prop_name [0]);
4327 DependencyProperty *dep;
4329 if (!owner)
4330 return false;
4332 dep = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, owner->GetKind ()), prop_name [1]);
4333 if (!dep)
4334 return false;
4336 return xaml_set_property_from_str (item, dep, value, NULL/*XXX*/);
4339 void
4340 XamlElementInstanceNative::AddChild (XamlParserInfo *p, XamlElementInstance *child)
4342 dependency_object_add_child (p, this, child, true);
4345 void
4346 XamlElementInstanceNative::SetAttributes (XamlParserInfo *p, const char **attr)
4348 dependency_object_set_attributes (p, this, attr);
4352 XamlElementInstanceValueType::XamlElementInstanceValueType (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type) :
4353 XamlElementInstance (element_info, name, type)
4355 this->element_info = element_info;
4356 this->parser_info = parser_info;
4359 bool
4360 XamlElementInstanceValueType::CreateValueItemFromString (const char* str)
4363 bool res = value_from_str (element_info->GetType ()->GetKind (), NULL, str, &value);
4364 return res;
4367 void
4368 XamlElementInstanceValueType::SetAttributes (XamlParserInfo *p, const char **attr)
4370 value_type_set_attributes (p, this, attr);
4373 XamlElementInstanceEnum::XamlElementInstanceEnum (XamlElementInfoEnum *element_info, const char *name, ElementType type) :
4374 XamlElementInstance (element_info, name, type)
4378 bool
4379 XamlElementInstanceEnum::CreateEnumFromString (const char* str)
4381 int i = enums_str_to_int (element_name, str);
4382 if (i == -1)
4383 return false;
4385 value = new Value (i);
4386 return true;
4389 void
4390 XamlElementInstanceEnum::SetAttributes (XamlParserInfo *p, const char **attr)
4392 value_type_set_attributes (p, this, attr);
4395 XamlElementInstance *
4396 XamlElementInfoEnum::CreateElementInstance (XamlParserInfo *p)
4398 return new XamlElementInstanceEnum (this, name, XamlElementInstance::ELEMENT);
4401 XamlElementInstance *
4402 XamlElementInfoEnum::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4404 XamlElementInstance *res = new XamlElementInstanceEnum (this, name, XamlElementInstance::ELEMENT);
4405 return res;
4408 const char *
4409 XamlElementInfoManaged::GetContentProperty (XamlParserInfo *p)
4411 if (!p->loader)
4412 return NULL;
4414 // TODO: We could cache this, but for now lets keep things as simple as possible.
4415 const char *res = p->loader->GetContentPropertyName (p, p->GetTopElementPtr (), obj);
4416 if (res)
4417 return res;
4418 return XamlElementInfo::GetContentProperty (p);
4421 XamlElementInstance *
4422 XamlElementInfoManaged::CreateElementInstance (XamlParserInfo *p)
4424 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, GetName (), XamlElementInstance::ELEMENT, obj);
4426 if (obj->Is (p->deployment, Type::DEPENDENCY_OBJECT))
4427 p->AddCreatedElement (inst->GetAsDependencyObject ());
4429 return inst;
4432 XamlElementInstance *
4433 XamlElementInfoManaged::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4435 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, GetName (), XamlElementInstance::ELEMENT, o);
4437 return inst;
4440 XamlElementInstance *
4441 XamlElementInfoManaged::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4443 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::PROPERTY, obj);
4445 return inst;
4448 XamlElementInstanceManaged::XamlElementInstanceManaged (XamlElementInfo *info, const char *name, ElementType type, Value *obj) :
4449 XamlElementInstance (info, name, type)
4451 // The managed code owns our Value objects
4452 cleanup_value = false;
4454 this->value = obj;
4456 if (obj->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT)) {
4457 this->is_dependency_object = true;
4458 this->SetDependencyObject (obj->AsDependencyObject ());
4460 else
4461 this->is_dependency_object = false;
4464 void *
4465 XamlElementInstanceManaged::GetManagedPointer ()
4467 if (value->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT))
4468 return value->AsDependencyObject ();
4469 return value->AsManagedObject ();
4472 Value *
4473 XamlElementInstanceManaged::GetParentPointer ()
4475 XamlElementInstance *walk = parent;
4476 while (walk && walk->element_type != XamlElementInstance::ELEMENT)
4477 walk = walk->parent;
4479 if (!walk) {
4480 return NULL;
4483 return walk->GetAsValue ();
4486 bool
4487 XamlElementInstanceManaged::SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value)
4489 if (GetAsDependencyObject () != NULL && dependency_object_set_property (p, this, property, value, false))
4490 return true;
4491 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, value->GetAsValue (), value);
4494 bool
4495 XamlElementInstanceManaged::SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value)
4497 Value v = Value (value);
4498 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, &v, NULL);
4501 void
4502 XamlElementInstanceManaged::AddChild (XamlParserInfo *p, XamlElementInstance *child)
4504 if (element_type == XamlElementInstance::PROPERTY) {
4505 Value *prop = new Value (element_name);
4506 p->loader->AddChild (p, p->GetTopElementPtr (), GetParentPointer (), true, info->xmlns, prop, this, child->GetAsValue (), child);
4507 delete prop;
4508 return;
4511 p->loader->AddChild (p, p->GetTopElementPtr (), GetParentPointer (), false, info->xmlns, GetAsValue (), this, child->GetAsValue (), child);
4514 void
4515 XamlElementInstanceManaged::SetAttributes (XamlParserInfo *p, const char **attr)
4517 dependency_object_set_attributes (p, this, attr);
4520 bool
4521 XamlElementInstanceManaged::TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value)
4523 Value *v = value->GetAsValue ();
4524 const char* prop_name = info->GetContentProperty (p);
4526 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, prop_name, v, value);
4529 bool
4530 XamlElementInstanceManaged::TrySetContentProperty (XamlParserInfo *p, const char *value)
4532 if (Type::IsSubclassOf (p->deployment, info->GetKind (), Type::CONTENTCONTROL)) {
4533 // Content controls are not allowed to have their content set as text, they need to have a child element
4534 // if you want to set the content of a contentcontrol to text you need to use attribute syntax
4535 return false;
4538 if (!XamlElementInstance::TrySetContentProperty (p, value)) {
4539 const char* prop_name = info->GetContentProperty (p);
4540 if (!p->cdata_content)
4541 return false;
4542 Value v = Value (value);
4543 bool res = p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, prop_name, &v, NULL);
4544 return res;
4547 return false;
4550 XamlElementInstance *
4551 XamlElementInfoImportedManaged::CreateElementInstance (XamlParserInfo *p)
4553 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::ELEMENT, obj);
4555 return inst;
4558 const char *
4559 XamlElementInfoImportedManaged::GetContentProperty (XamlParserInfo *p)
4561 if (!p->loader)
4562 return NULL;
4564 // TODO: Test, it's possible that managed objects that aren't DOs are allowed to have content properties.
4565 if (!obj->Is (p->deployment, Type::DEPENDENCY_OBJECT))
4566 return XamlElementInfo::GetContentProperty (p);
4569 // TODO: We could cache this, but for now lets keep things as simple as possible.
4570 const char *res = p->loader->GetContentPropertyName (p, p->GetTopElementPtr (), obj);
4571 if (res)
4572 return res;
4574 return XamlElementInfo::GetContentProperty (p);
4577 XamlElementInstance *
4578 XamlElementInfoImportedManaged::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4580 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, Type::Find (p->deployment, o->GetKind ())->GetName (), XamlElementInstance::ELEMENT, o);
4582 return inst;
4585 XamlElementInstance *
4586 XamlElementInfoImportedManaged::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4588 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::PROPERTY, obj);
4590 return inst;
4595 /// Add Child funcs
4598 static const char*
4599 get_key_from_child (XamlElementInstance *child)
4601 const char *key = child->GetKey ();
4602 if (key)
4603 return key;
4605 key = child->GetName ();
4606 if (key)
4607 return key;
4609 if (child->IsDependencyObject ()) {
4610 DependencyObject *c = child->GetAsDependencyObject();
4612 if (Type::IsSubclassOf (c->GetDeployment (), Type::STYLE, child->info->GetKind ())) {
4613 Value *v = c->GetValue (Style::TargetTypeProperty);
4614 if (v && v->GetKind () == Type::MANAGEDTYPEINFO)
4615 key = v->AsManagedTypeInfo ()->full_name;
4617 if (key)
4618 return key;
4622 return NULL;
4625 static void
4626 dependency_object_add_child (XamlParserInfo *p, XamlElementInstance *parent, XamlElementInstance *child, bool fail_if_no_prop)
4628 Types *types = Deployment::GetCurrent ()->GetTypes ();
4629 if (parent->element_type == XamlElementInstance::PROPERTY) {
4631 if (parent->info->RequiresManagedSet ())
4632 return;
4634 char **prop_name = g_strsplit (parent->element_name, ".", -1);
4635 Type *owner = types->Find (prop_name [0]);
4637 if (owner) {
4638 DependencyProperty *dep = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, owner->GetKind ()), prop_name [1]);
4640 g_strfreev (prop_name);
4642 if (!dep) {
4643 g_warning ("Unknown element: %s.", parent->element_name);
4644 if (fail_if_no_prop)
4645 parser_error (p, parent->element_name, NULL, 2007, "Unknown element: %s.", parent->element_name);
4646 return;
4649 // XamlElementInfoEnum has Type::INVALID as
4650 // its kind, which is why that first check is
4651 // here.
4652 if (child->info->GetKind() != Type::MANAGED &&
4653 !types->Find (child->info->GetKind())->IsCtorVisible()) {
4654 // we can't instantiate this type
4655 return parser_error (p, child->element_name, NULL, 2007,
4656 "Unknown element: %s.", child->element_name);
4659 // Don't add the child element, if it is the entire collection
4660 if (dep->GetPropertyType() == child->info->GetKind ())
4661 return;
4663 Type::Kind prop_type = dep->GetPropertyType ();
4664 if (!types->IsSubclassOf (prop_type, Type::DEPENDENCY_OBJECT_COLLECTION)
4665 && !types->IsSubclassOf (prop_type, Type::RESOURCE_DICTIONARY))
4666 return;
4668 // Most common case, we will have a parent that we can snag the collection from
4669 DependencyObject *obj = (DependencyObject *) parent->parent->GetAsDependencyObject ();
4670 if (!obj)
4671 return;
4673 Value *col_v = obj->GetValue (dep);
4674 if (!col_v) {
4675 Type *col_type = types->Find (prop_type);
4676 DependencyObject *c_obj = col_type->CreateInstance ();
4677 obj->SetValue (dep, Value::CreateUnrefPtr (c_obj));
4678 col_v = obj->GetValue (dep);
4679 c_obj->unref ();
4681 Collection *col = col_v->AsCollection ();
4682 MoonError err;
4684 if (types->IsSubclassOf (prop_type, Type::DEPENDENCY_OBJECT_COLLECTION)) {
4685 Value child_val (child->GetAsDependencyObject ());
4686 if (-1 == col->AddWithError (&child_val, &err))
4687 return parser_error (p, child->element_name, NULL, err.code, err.message);
4689 else if (types->IsSubclassOf (prop_type, Type::RESOURCE_DICTIONARY)) {
4690 ResourceDictionary *dict = (ResourceDictionary *)col;
4692 const char *key = get_key_from_child (child);
4694 if (key == NULL) {
4695 // XXX don't know the proper values here...
4696 return parser_error (p, child->element_name, NULL, 2007,
4697 "You must specify an x:Key or x:Name for elements in a ResourceDictionary");
4700 Value *child_as_value = child->GetAsValue ();
4702 if (!child_as_value) {
4703 // XXX don't know the proper values here...
4704 return parser_error (p, child->element_name, NULL, 2007,
4705 "Error adding child to ResourceDictionary");
4708 bool added = dict->AddWithError (key, child_as_value, &err);
4709 if (!added)
4710 return parser_error (p, child->element_name, NULL, err.code, err.message);
4713 return;
4716 return;
4719 if (types->IsSubclassOf (parent->info->GetKind (), Type::DEPENDENCY_OBJECT_COLLECTION)) {
4720 Collection *col = (Collection *) parent->GetAsDependencyObject ();
4721 MoonError err;
4722 Value child_val ((DependencyObject*)child->GetAsDependencyObject ());
4724 if (-1 == col->AddWithError (&child_val, &err))
4725 return parser_error (p, child->element_name, NULL, err.code, err.message);
4726 return;
4728 else if (types->IsSubclassOf (parent->info->GetKind (), Type::RESOURCE_DICTIONARY)) {
4729 ResourceDictionary *dict = (ResourceDictionary *) parent->GetAsDependencyObject ();
4731 MoonError err;
4732 const char *key = get_key_from_child (child);
4734 if (key == NULL) {
4735 // XXX don't know the proper values here...
4736 return parser_error (p, child->element_name, NULL, 2007,
4737 "You must specify an x:Key or x:Name for elements in a ResourceDictionary");
4740 Value *child_as_value = child->GetAsValue ();
4741 bool added = dict->AddWithError (key, child_as_value, &err);
4742 if (!added)
4743 return parser_error (p, child->element_name, NULL, err.code, err.message);
4747 if (parent->element_type != XamlElementInstance::PROPERTY) {
4748 parent->TrySetContentProperty (p, child);
4751 // Do nothing if we aren't adding to a collection, or a content property collection
4756 /// set property funcs
4759 // these are just a bunch of special cases
4760 static void
4761 dependency_object_missed_property (XamlElementInstance *item, XamlElementInstance *prop, XamlElementInstance *value, char **prop_name)
4766 static bool
4767 set_managed_attached_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *prop, XamlElementInstance *value)
4769 if (!p->loader)
4770 return false;
4772 return p->loader->SetProperty (p, p->GetTopElementPtr (), item->info->xmlns, item->GetAsValue (), item, item->GetParentPointer (), prop->info->xmlns, prop->element_name, value->GetAsValue (), value);
4775 static bool
4776 dependency_object_set_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *property, XamlElementInstance *value, bool raise_errors)
4778 char **prop_name = g_strsplit (property->element_name, ".", -1);
4779 DependencyObject *dep = item->GetAsDependencyObject ();
4780 DependencyProperty *prop = NULL;
4781 bool res;
4782 Types *types = Deployment::GetCurrent ()->GetTypes ();
4784 if (types->Find (item->info->GetKind ())->IsValueType ()) {
4785 if (raise_errors) parser_error (p, item->element_name, NULL, -1, "Value types (%s) do not have properties.", property->element_name);
4786 g_strfreev (prop_name);
4787 return false;
4790 if (types->Find (property->info->GetPropertyOwnerKind ())->IsCustomType ()) {
4791 g_strfreev (prop_name);
4792 return set_managed_attached_property (p, item, property, value);
4795 if (!dep) {
4796 // FIXME is this really where this check should live
4797 if (raise_errors)
4798 parser_error (p, item->element_name, NULL, 2030,
4799 "Property element %s cannot be used inside another property element.",
4800 property->element_name);
4802 g_strfreev (prop_name);
4803 return false;
4806 prop = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, item->info->GetKind ()), prop_name [1]);
4808 if (prop) {
4809 if (prop->IsReadOnly ()) {
4810 if (raise_errors)
4811 parser_error (p, item->element_name, NULL, 2014,
4812 "The attribute %s is read only and cannot be set.", prop->GetName ());
4813 res = false;
4814 } else if (types->IsSubclassOf (value->info->GetKind (), prop->GetPropertyType())) {
4815 // an empty collection can be NULL and valid
4816 if (item->IsPropertySet (prop->GetName())) {
4817 if (raise_errors)
4818 parser_error (p, item->element_name, NULL, 2033,
4819 "Cannot specify the value multiple times for property: %s.",
4820 property->element_name);
4821 res = false;
4822 } else {
4823 MoonError err;
4825 // HACK - since the Setter is added to the collection *before* its properties are set
4826 // we find ourselves with a sealed Setter - which should not be possible at the parse time
4827 SetterBase *sb = NULL;
4828 if (types->IsSubclassOf (dep->GetObjectType (), Type::SETTERBASE)) {
4829 sb = (SetterBase*) dep;
4830 sb->SetIsSealed (false);
4833 if (!is_managed_kind (value->info->GetKind ()) && !value->info->RequiresManagedSet()) {
4834 if (!dep->SetValueWithError (prop, value->GetAsValue (), &err)) {
4835 if (raise_errors)
4836 parser_error (p, item->element_name, NULL, err.code, err.message);
4837 res = false;
4838 goto cleanup;
4841 } else {
4842 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, item->GetAsValue (), item, item->GetParentPointer (), NULL, prop_name [1], value->GetAsValue (), NULL)) {
4843 if (raise_errors)
4844 parser_error (p, item->element_name, NULL, err.code, err.message);
4845 res = false;
4846 goto cleanup;
4851 // re-seal the Setter (end-HACK)
4852 if (sb)
4853 sb->SetIsSealed (true);
4855 item->MarkPropertyAsSet (prop->GetName());
4856 res = true;
4858 } else if (types->IsSubclassOf (prop->GetPropertyType (), Type::COLLECTION) || types->IsSubclassOf (prop->GetPropertyType (), Type::RESOURCE_DICTIONARY)) {
4859 // The items were added in add_child
4860 return true;
4861 } else {
4862 if (raise_errors)
4863 parser_error (p, item->element_name, NULL, 2010, "does not support %s as content.", value->element_name);
4864 res = false;
4866 } else {
4867 dependency_object_missed_property (item, property, value, prop_name);
4868 res = false;
4871 cleanup:
4872 g_strfreev (prop_name);
4873 return res;
4876 bool
4877 xaml_set_property_from_str (DependencyObject *obj, DependencyProperty *prop, const char *value, MoonError *error)
4879 Value *v = NULL;
4880 bool rv = true;
4882 if (!value_from_str (prop->GetPropertyType(), prop->GetName(), value, &v))
4883 return false;
4885 // it's possible for (a valid) value to be NULL (and we must keep the default value)
4886 if (v) {
4887 rv = obj->SetValueWithError (prop, v, error);
4888 delete v;
4891 return rv;
4894 bool
4895 xaml_is_valid_event_name (Deployment *deployment, Type::Kind kind, const char *name, bool allow_desktop_events)
4897 Type *type = Type::Find (deployment, kind);
4898 if (!type)
4899 return false;
4901 int event_id = type->LookupEvent (name);
4902 if (event_id == -1)
4903 return false;
4905 if (!allow_desktop_events || (moonlight_flags & RUNTIME_INIT_DESKTOP_EXTENSIONS) == 0) {
4906 // if we're not allowing desktop-only events, or if the user hasn't allowed them,
4907 // return false if the name corresponds to one of them.
4908 if (!strcmp (name, "MouseRightButtonDown") ||
4909 !strcmp (name, "MouseRightButtonUp") ||
4910 !strcmp (name, "MouseWheel"))
4911 return false;
4914 return true;
4917 static void
4918 value_type_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr)
4920 // the only attributes value on value types seem to be x:Key
4921 // and x:Name, but reuse the generic namespace attribute stuff
4922 // anyway.
4924 for (int i = 0; attr [i]; i += 2) {
4925 // Skip empty attrs
4926 if (attr[i + 1] == NULL || attr[i + 1][0] == '\0')
4927 continue;
4929 char **attr_name = g_strsplit (attr [i], "|", -1);
4931 if (attr_name [1]) {
4933 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
4935 if (!ns)
4936 return parser_error (p, item->element_name, attr[i], 7055, "undeclared prefix");
4938 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
4940 g_strfreev (attr_name);
4942 // Setting managed attributes can cause errors galore
4943 if (p->error_args)
4944 return;
4946 continue;
4949 g_strfreev (attr_name);
4953 static void
4954 dependency_object_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr)
4956 Types *types = Deployment::GetCurrent ()->GetTypes ();
4957 GList *delay_att = NULL;
4959 for (int i = 0; attr [i]; i += 2) {
4961 if (p->error_args)
4962 return;
4964 // Setting attributes like x:Class can change item->item, so we
4965 // need to make sure we have an up to date pointer
4966 DependencyObject *dep = item->GetAsDependencyObject ();
4967 char **attr_name = g_strsplit (attr [i], "|", -1);
4969 if (attr_name [1]) {
4970 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
4972 if (ns != x_namespace) {
4973 delay_att = g_list_append (delay_att, GINT_TO_POINTER (i));
4974 g_strfreev (attr_name);
4975 continue;
4978 if (!ns) {
4979 g_strfreev (attr_name);
4980 return parser_error (p, item->element_name, attr[i], 5055, "undeclared prefix");
4983 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
4985 g_strfreev (attr_name);
4987 // Setting managed attributes can cause errors galore
4988 if (p->error_args)
4989 return;
4991 continue;
4994 g_strfreev (attr_name);
4996 const char *pname = attr [i];
4997 char *atchname = NULL;
4998 for (int a = 0; attr [i][a]; a++) {
4999 if (attr [i][a] != '.')
5000 continue;
5001 atchname = g_strndup (attr [i], a);
5002 pname = attr [i] + a + 1;
5003 break;
5006 DependencyProperty *prop = NULL;
5007 if (atchname) {
5008 Type *attached_type = types->Find (atchname);
5009 if (attached_type)
5010 prop = DependencyProperty::GetDependencyProperty (attached_type, pname);
5011 } else {
5012 prop = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, item->info->GetKind ()), pname);
5015 if (prop) {
5016 if (prop->GetId () == DependencyObject::NameProperty) {
5018 if (item->GetName ()) {
5019 parser_error (p, item->element_name, NULL, 2016, "Cannot specify both Name and x:Name attributes.");
5020 return;
5023 // XXX toshok - I don't like doing this here... but it fixes airlines.
5024 item->SetKey (p, attr[i+1]);
5026 NameScope *scope = p->namescope;
5027 if (!item->GetAsDependencyObject ()->SetName (attr [i+1], scope)) {
5028 parser_error (p, item->element_name, NULL, 2028,
5029 "The name already exists in the tree: %s.", attr [i+1]);
5030 g_free (atchname);
5031 g_list_free (delay_att);
5032 return;
5034 continue;
5037 if (prop->IsReadOnly ()) {
5038 parser_error (p, item->element_name, NULL, 2014,
5039 "The attribute %s is read only and cannot be set.", prop->GetName ());
5040 g_free (atchname);
5041 g_list_free (delay_att);
5042 return;
5045 if (item->IsPropertySet (prop->GetName())) {
5046 parser_error (p, item->element_name, attr [i], 2033,
5047 "Cannot specify the value multiple times for property: %s.", prop->GetName ());
5048 g_free (atchname);
5049 g_list_free (delay_att);
5050 return;
5053 Value *v = NULL;
5054 bool v_set = false;
5055 char *attr_value = g_strdup (attr [i+1]);
5057 bool need_managed = false;
5058 if (attr[i+1][0] == '{') {
5059 if (attr[i+1][1] == '}') {
5060 // {} is an escape sequence so you can have strings like {StaticResource}
5061 char *nv = attr_value;
5062 attr_value = g_strdup (attr_value + 2);
5063 g_free (nv);
5065 else if (attr[i+1][strlen(attr[i+1]) - 1] == '}') {
5066 need_managed = true;
5070 if (!need_managed) {
5071 if (!value_from_str_with_parser (p, prop->GetPropertyType(), prop->GetName(), attr_value, &v, &v_set)) {
5072 delete v;
5073 g_free (attr_value);
5074 continue;
5078 Type::Kind propKind = prop->GetPropertyType ();
5080 if (need_managed || is_managed_kind (propKind) || types->Find (prop->GetOwnerType ())->IsCustomType () || (v && is_managed_kind (v->GetKind ()))) {
5081 bool str_value = false;
5082 if (!v_set) {
5083 v = new Value (attr [i + 1]); // Note that we passed the non escaped value, not attr_value
5084 v_set = true;
5085 str_value = true;
5088 // printf ("setting managed property: %s::%s to %s=%s\n", dep->GetType ()->GetName (), prop->GetName (), attr [i], attr [i + 1]);
5089 if (p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, item->GetAsValue (), item, item->GetParentPointer (), NULL, g_strdup (attr [i]), v, NULL)) {
5090 delete v;
5091 g_free (attr_value);
5092 continue;
5093 } else {
5094 if (str_value) {
5095 delete v;
5096 v = NULL;
5098 if (!value_from_str_with_parser (p, prop->GetPropertyType(), prop->GetName(), attr_value, &v, &v_set)) {
5099 delete v;
5100 g_free (attr_value);
5101 continue;
5107 if (!v_set && !value_is_explicit_null (attr [i + 1])) { // Check the non escaped value
5108 parser_error (p, item->element_name, attr [i], 2024, "Invalid attribute value %s for property %s.", attr [i+1], attr [i]);
5110 g_free (attr_value);
5111 g_free (atchname);
5112 g_list_free (delay_att);
5113 return;
5116 MoonError err;
5117 // printf ("settng: %s %s value type: %s prop type: %s\n", attr [i], attr [i+1], v ? Type::Find (v->GetKind ())->GetName () : "--null--", Type::Find (prop->GetPropertyType ())->GetName ());
5118 if (!dep->SetValueWithError (prop, v, &err))
5119 parser_error (p, item->element_name, attr [i], err.code, err.message);
5120 else
5121 item->MarkPropertyAsSet (prop->GetName());
5123 delete v;
5124 g_free (attr_value);
5125 } else {
5126 delay_att = g_list_append (delay_att, GINT_TO_POINTER (i));
5129 if (atchname)
5130 g_free (atchname);
5133 GList *walk = g_list_first (delay_att);
5134 while (walk) {
5135 int i = GPOINTER_TO_INT (walk->data);
5137 if (p->error_args)
5138 return;
5140 char **attr_name = g_strsplit (attr [i], "|", -1);
5142 if (attr_name [1]) {
5143 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
5145 if (ns == x_namespace) {
5146 // Skip these, they are handled earlier
5147 g_strfreev (attr_name);
5148 walk = walk->prev;
5151 if (!ns) {
5152 g_strfreev (attr_name);
5153 parser_error (p, item->element_name, attr[i], 5055, "undeclared prefix");
5154 break;
5157 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
5159 g_strfreev (attr_name);
5161 // Setting managed attributes can cause errors galore
5162 if (p->error_args)
5163 break;
5164 } else {
5165 if (!item->SetUnknownAttribute (p, attr [i], attr [i + 1])) {
5166 parser_error (p, item->element_name, attr [i], 2012,
5167 "Unknown attribute %s on element %s.",
5168 attr [i], item->element_name);
5169 break;
5173 walk = walk->next;
5176 g_list_free (delay_att);
5180 static Value *
5181 lookup_named_item (XamlElementInstance *top, const char *name)
5183 Types *types = Deployment::GetCurrent ()->GetTypes ();
5184 XamlElementInstance *inst = top;
5186 while (inst) {
5187 if (inst->element_type == XamlElementInstance::ELEMENT) {
5188 ResourceDictionary *rd = NULL;
5189 Type::Kind kind = inst->info->GetKind ();
5191 if (types->IsSubclassOf (kind, Type::FRAMEWORKELEMENT)) {
5192 rd = inst->GetAsDependencyObject ()->GetValue (UIElement::ResourcesProperty)->AsResourceDictionary ();
5193 } else if (types->IsSubclassOf (kind, Type::RESOURCE_DICTIONARY)) {
5194 rd = (ResourceDictionary*) inst->GetAsDependencyObject ();
5197 if (rd) {
5198 bool exists;
5199 Value *res = lookup_resource_dictionary (rd, name, &exists);
5200 if (exists)
5201 return res;
5205 inst = inst->parent;
5208 return NULL;
5211 static Value *
5212 lookup_resource_dictionary (ResourceDictionary *rd, const char *name, bool *exists)
5214 *exists = false;
5215 Value *resource_value = rd->Get (name, exists);
5216 return *exists ? new Value (*resource_value) : NULL;
5219 Value *
5220 xaml_lookup_named_item (void *parser, void *instance, const char* name)
5222 XamlParserInfo *p = (XamlParserInfo *) parser;
5223 XamlElementInstance *inst = (XamlElementInstance *) instance;
5224 Value *res = NULL;
5226 if (inst)
5227 res = lookup_named_item (inst, name);
5229 XamlContext *context = p->loader->GetContext ();
5230 if (!res && context)
5231 context->internal->LookupNamedItem (name, &res);
5233 if (!res) {
5234 Application *app = Application::GetCurrent ();
5235 if (app) {
5236 ResourceDictionary *rd = app->GetResources ();
5238 bool exists = false;
5239 res = lookup_resource_dictionary (rd, name, &exists);
5241 if (res && Type::IsSubclassOf (p->deployment, res->GetKind (), Type::DEPENDENCY_OBJECT)) {
5242 DependencyObject *dob = res->AsDependencyObject ();
5243 NameScope::SetNameScope (dob, dob->FindNameScope ());
5248 return res;
5251 void *
5252 xaml_get_template_parent (void *parser, void *element_instance)
5254 XamlParserInfo *p = (XamlParserInfo *) parser;
5255 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5257 return p->GetTemplateParent (item);
5260 char *
5261 xaml_get_element_key (void *parser, void *element_instance)
5263 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5264 const char *key = item->GetKey ();
5265 if (!key)
5266 key = item->GetName ();
5267 return g_strdup (key);
5270 char *
5271 xaml_get_element_name (void *parser, void *element_instance)
5273 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5274 return g_strdup (item->element_name);
5277 bool
5278 xaml_is_property_set (void *parser, void *element_instance, char *name)
5280 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5281 return item->IsPropertySet (name);
5284 void
5285 xaml_mark_property_as_set (void *parser, void *element_instance, char *name)
5287 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5288 item->MarkPropertyAsSet (g_strdup (name));
5291 void
5292 xaml_delay_set_property (void *parser, void *element_instance, const char *xmlns, const char *name, const Value *value)
5294 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5295 item->DelaySetProperty (xmlns, name, value);
5298 void
5299 xaml_init (void)
5301 default_namespace = new DefaultNamespace ();
5302 x_namespace = new XNamespace ();
5303 xml_namespace = new XmlNamespace ();