revert jeff's last commit since it breaks the build
[moon.git] / src / xaml.cpp
blob62e6d51d29cd4efd85eb63228db144aed9eca2e4
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"
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;
127 XamlNamespace ()
129 name = NULL;
130 is_ignored = false;
133 virtual ~XamlNamespace () { }
134 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create) = 0;
135 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value) = 0;
137 virtual const char* GetUri () = 0;
138 virtual const char* GetPrefix () = 0;
141 void
142 add_namespace_data (gpointer key, gpointer value, gpointer user_data)
144 XamlNamespace *ns = (XamlNamespace *) value;
145 GHashTable *table = (GHashTable *) user_data;
147 if ((void *)ns != (void *)default_namespace)
148 g_hash_table_insert (table, g_strdup (ns->GetPrefix ()), g_strdup (ns->GetUri ()));
151 void
152 add_namespace_to_ignorable (gpointer key, gpointer value, gpointer user_data)
154 char *prefix = (char *) key;
155 char *uri = (char *) value;
156 GString *str = (GString *) user_data;
158 g_string_append_printf (str, "xmlns:%s=\"%s\" ", prefix, uri);
161 class XamlContextInternal {
163 public:
164 Value *top_element;
165 FrameworkTemplate *template_parent;
166 GHashTable *imported_namespaces;
167 XamlLoaderCallbacks callbacks;
168 GSList *resources;
169 XamlContextInternal *parent_context;
171 DependencyObject *source;
173 XamlContextInternal (XamlLoaderCallbacks callbacks, Value *top_element, FrameworkTemplate *template_parent, GHashTable *namespaces, GSList *resources, XamlContextInternal *parent_context)
175 this->callbacks = callbacks;
176 this->top_element = new Value (*top_element);
177 this->template_parent = template_parent;
178 this->resources = resources;
179 this->parent_context = parent_context;
181 if (this->callbacks.create_gchandle)
182 this->callbacks.create_gchandle ();
183 imported_namespaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
184 g_hash_table_foreach (namespaces, add_namespace_data, imported_namespaces);
188 ~XamlContextInternal ()
190 if (imported_namespaces)
191 g_hash_table_destroy (imported_namespaces);
192 if (resources)
193 g_slist_free (resources);
194 delete top_element;
197 char *CreateIgnorableTagOpen ()
199 GString *str = g_string_new ("<" INTERNAL_IGNORABLE_ELEMENT " ");
200 g_hash_table_foreach (imported_namespaces, add_namespace_to_ignorable, str);
202 str = g_string_append (str, ">");
204 char *res = str->str;
205 g_string_free (str, false);
207 return res;
210 char *CreateIgnorableTagClose ()
212 return g_strdup ("</" INTERNAL_IGNORABLE_ELEMENT ">");
215 bool LookupNamedItem (const char* name, Value **v)
217 if (!resources)
218 return NULL;
220 bool exists = false;
221 GSList *walk = resources;
222 while (walk) {
223 DependencyObject *dob = (DependencyObject*)walk->data;
224 if (dob->Is (Type::RESOURCE_DICTIONARY))
225 *v = lookup_resource_dictionary ((ResourceDictionary *) walk->data, name, &exists);
226 else /* dob->Is (Type::FRAMEWORKELEMENT) */ {
227 ResourceDictionary *rd = dob->GetValue (UIElement::ResourcesProperty)->AsResourceDictionary();
228 *v = lookup_resource_dictionary (rd, name, &exists);
231 if (exists)
232 break;
233 walk = walk->next;
236 if (exists)
237 return exists;
238 else if (!parent_context)
239 return false;
241 return parent_context->LookupNamedItem (name, v);
244 void SetTemplateBindingSource (DependencyObject *source)
246 this->source = source;
249 DependencyObject* GetTemplateBindingSource ()
251 return source;
256 XamlContext::XamlContext (XamlContextInternal *internal)
258 this->internal = internal;
261 XamlContext::~XamlContext ()
263 delete internal;
266 void
267 XamlContext::SetTemplateBindingSource (DependencyObject *source)
269 internal->SetTemplateBindingSource (source);
272 DependencyObject*
273 XamlContext::GetTemplateBindingSource ()
275 return internal->GetTemplateBindingSource ();
278 class XamlElementInfo {
279 protected:
280 Type::Kind kind;
281 Type::Kind property_owner_kind;
282 bool cdata_verbatim;
284 public:
285 XamlElementInfo *parent;
286 const char *name;
287 const char *xmlns;
289 XamlElementInfo (const char *xmlns, const char *name, Type::Kind kind)
291 this->parent = NULL;
292 this->kind = kind;
293 this->name = name;
294 this->xmlns = xmlns;
295 this->cdata_verbatim = false;
297 this->property_owner_kind = Type::INVALID;
300 ~XamlElementInfo ()
304 virtual Type::Kind GetKind () { return kind; }
306 virtual void SetPropertyOwnerKind (Type::Kind value) { property_owner_kind = value; }
307 virtual Type::Kind GetPropertyOwnerKind () { return property_owner_kind; }
309 virtual const char *GetContentProperty (XamlParserInfo *p)
311 Type *t = Type::Find (Deployment::GetCurrent (), kind);
312 if (t)
313 return t->GetContentPropertyName ();
314 return NULL;
317 void SetIsCDataVerbatim (bool flag)
319 cdata_verbatim = flag;
322 bool IsCDataVerbatim ()
324 return cdata_verbatim;
327 virtual bool RequiresManagedSet () { return false; }
329 virtual XamlElementInstance *CreateElementInstance (XamlParserInfo *p) = 0;
330 virtual XamlElementInstance *CreateWrappedElementInstance (XamlParserInfo *p, Value *o) = 0;
331 virtual XamlElementInstance *CreatePropertyElementInstance (XamlParserInfo *p, const char *name) = 0;
335 struct DelayedProperty {
336 char *xmlns;
337 char *name;
338 Value *value;
340 DelayedProperty (const char *xmlns, const char *name, const Value *value)
342 this->xmlns = g_strdup (xmlns);
343 this->name = g_strdup (name);
344 this->value = new Value (*value);
347 ~DelayedProperty ()
349 g_free (xmlns);
350 g_free (name);
351 delete value;
355 static void
356 free_property_list (GSList *list)
358 GSList *walk = list;
360 while (walk) {
361 DelayedProperty *prop = (DelayedProperty *) walk->data;
363 delete prop;
364 walk = walk->next;
367 g_slist_free (list);
370 class XamlElementInstance : public List::Node {
372 protected:
373 DependencyObject *item;
374 Value *value;
375 bool cleanup_value;
376 GSList *delayed_properties;
378 public:
379 const char *element_name;
380 XamlElementInfo *info;
382 XamlElementInstance *parent;
383 List *children;
385 enum ElementType {
386 ELEMENT,
387 PROPERTY,
388 INVALID
391 int element_type;
392 bool requires_managed;
393 char *x_key;
394 char *x_name;
396 GHashTable *set_properties;
398 XamlElementInstance (XamlElementInfo *info, const char* element_name, ElementType type, bool requires_managed = false)
400 this->element_name = element_name;
401 this->set_properties = NULL;
402 this->element_type = type;
403 this->parent = NULL;
404 this->info = info;
405 this->item = NULL;
406 this->value = NULL;
407 this->x_key = NULL;
408 this->x_name = NULL;
409 this->cleanup_value = true;
410 this->requires_managed = requires_managed;
411 this->delayed_properties = NULL;
413 children = new List ();
416 virtual ~XamlElementInstance ()
418 children->Clear (true);
419 delete children;
420 delete info;
422 g_free (x_key);
423 g_free (x_name);
425 if (cleanup_value)
426 delete value;
428 if (set_properties)
429 g_hash_table_destroy (set_properties);
431 if (element_name && element_type == PROPERTY)
432 g_free ((void*) element_name);
434 free_property_list (delayed_properties);
437 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) = 0;
438 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value) = 0;
439 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) = 0;
440 virtual void SetAttributes (XamlParserInfo *p, const char **attr) = 0;
442 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value);
443 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value);
446 char *GetKey () { return x_key; }
447 char *GetName () { return x_name; }
449 void SetName (XamlParserInfo *p, const char *name)
451 this->x_name = g_strdup (name);
454 void SetKey (XamlParserInfo *p, const char *key)
456 this->x_key = g_strdup (key);
459 virtual bool IsDependencyObject ()
461 return true;
464 virtual bool SetUnknownAttribute (XamlParserInfo *p, const char* name, const char* value);
466 void SetValue (Value *v)
468 if (value && cleanup_value)
469 delete value;
470 value = v;
473 virtual Value *GetAsValue ()
475 if (!value) {
476 value = new Value (item);
478 return value;
481 virtual DependencyObject *GetAsDependencyObject ()
483 return item;
486 virtual void SetDependencyObject (DependencyObject *value)
488 item = value;
491 virtual void* GetManagedPointer ()
493 return item;
496 virtual Value* GetParentPointer ()
498 XamlElementInstance *walk = parent;
499 while (walk && walk->element_type != XamlElementInstance::ELEMENT)
500 walk = walk->parent;
502 if (!walk)
503 return NULL;
505 return walk->GetAsValue ();
508 virtual bool IsTemplate ()
510 return false;
513 virtual XamlElementInfo* FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot);
515 void SetDelayedProperties (XamlParserInfo *p);
517 void DelaySetProperty (const char *xmlns, const char *name, const Value *value)
519 DelayedProperty *prop = new DelayedProperty (xmlns, name, value);
521 delayed_properties = g_slist_append (delayed_properties, prop);
524 bool IsPropertySet (const char *name)
526 if (!set_properties)
527 return false;
529 return g_hash_table_lookup (set_properties, name) != NULL;
532 void MarkPropertyAsSet (const char *name)
534 if (!set_properties)
535 set_properties = g_hash_table_new (g_str_hash, g_str_equal);
537 g_hash_table_insert (set_properties, (void *) name, GINT_TO_POINTER (TRUE));
541 void
542 unref_xaml_element (gpointer data, gpointer user_data)
544 DependencyObject* dob = (DependencyObject*) data;
545 //printf ("unref_xaml_element: %i\n", dob->id);
546 if (dob)
547 dob->unref ();
550 class XamlParserInfo {
551 public:
552 XML_Parser parser;
554 const char *file_name;
556 NameScope *namescope;
557 XamlElementInstance *top_element;
558 XamlNamespace *current_namespace;
559 XamlElementInstance *current_element;
560 const char *next_element;
561 Deployment *deployment;
563 GHashTable *namespace_map;
564 bool cdata_content;
565 GString *cdata;
567 bool implicit_default_namespace;
569 ParserErrorEventArgs *error_args;
571 XamlLoader *loader;
575 // If set, this is used to hydrate an existing object, not to create a new toplevel one
577 Value *hydrate_expecting;
578 bool hydrating;
580 char* buffer_until_element;
581 int buffer_depth;
582 BufferMode buffer_mode;
583 GString *buffer;
584 bool validate_templates;
586 private:
587 GList *created_elements;
588 GList *created_namespaces;
589 const char* xml_buffer;
590 int multi_buffer_offset;
591 int xml_buffer_start_index;
593 public:
594 XamlParserInfo (XML_Parser parser, const char *file_name)
596 this->deployment = Deployment::GetCurrent ();
597 this->parser = parser;
598 this->file_name = file_name;
599 this->namescope = new NameScope ();
601 top_element = NULL;
602 current_namespace = NULL;
603 current_element = NULL;
604 cdata_content = false;
605 cdata = NULL;
606 implicit_default_namespace = false;
607 error_args = NULL;
608 loader = NULL;
609 created_elements = NULL;
610 created_namespaces = NULL;
611 hydrate_expecting = NULL;
612 hydrating = false;
614 buffer_until_element = NULL;
615 buffer_depth = -1;
616 buffer = NULL;
617 xml_buffer = NULL;
618 multi_buffer_offset = 0;
619 validate_templates = false;
621 namespace_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
624 void AddCreatedElement (DependencyObject* element)
626 // if we have a loader, set the surface and base resource location
627 if (loader) {
628 element->SetIsAttached (true); /* Some glyphs (DRT 0/Test5, 58) do not show up without this */
629 element->SetResourceBase (loader->GetResourceBase());
632 // When instantiating a template, some elements are created which are not explicitly
633 // mentioned in the xaml. Therefore we need to keep walking up the tree until we find
634 // the last element which we set a value for Control::IsTemplateItem and propagate
635 // it from there.
636 XamlElementInstance *instance = current_element;
637 while (instance) {
638 if (!instance->IsDependencyObject () || !instance->GetAsDependencyObject ()) {
639 instance = instance->parent;
640 continue;
642 if (!instance->GetAsDependencyObject ()->ReadLocalValue (Control::IsTemplateItemProperty)) {
643 instance = instance->parent;
644 continue;
646 Control::SetIsTemplateItem (element, Control::GetIsTemplateItem (instance->GetAsDependencyObject ()));
647 if (DependencyObject *e = instance->GetAsDependencyObject ()->GetTemplateOwner ())
648 element->SetTemplateOwner (e);
649 break;
652 if (instance == NULL) {
653 Control::SetIsTemplateItem (element, loader->GetExpandingTemplate ());
654 element->SetTemplateOwner (loader->GetTemplateOwner ());
657 if (Control::GetIsTemplateItem (element))
658 NameScope::SetNameScope (element, namescope);
659 created_elements = g_list_prepend (created_elements, element);
662 void AddCreatedNamespace (XamlNamespace* ns)
664 created_namespaces = g_list_prepend (created_namespaces, ns);
667 void QueueBeginBuffering (char* buffer_until, BufferMode mode)
669 buffer_until_element = buffer_until;
670 buffer_depth = 1;
671 buffer_mode = mode;
673 xml_buffer_start_index = -1;
676 void BeginBuffering ()
678 xml_buffer_start_index = XML_GetCurrentByteIndex (parser) - multi_buffer_offset;
679 buffer = g_string_new (NULL);
682 bool ShouldBeginBuffering ()
684 return InBufferingMode () && xml_buffer_start_index == -1;
687 bool InBufferingMode ()
689 return buffer_until_element != NULL;
692 void AppendCurrentXml ()
694 if (!buffer)
695 return;
696 int pos = XML_GetCurrentByteIndex (parser) - multi_buffer_offset;
697 g_string_append_len (buffer, xml_buffer + xml_buffer_start_index, pos - xml_buffer_start_index);
700 char* ClearBuffer ()
702 AppendCurrentXml ();
704 buffer_depth = 0;
705 buffer_until_element = NULL;
707 if (!buffer)
708 return g_strdup ("");
710 char* res = buffer->str;
711 g_string_free (buffer, FALSE);
712 buffer = NULL;
713 return res;
716 void SetXmlBuffer (const char* xml_buffer)
718 if (InBufferingMode ())
719 AppendCurrentXml ();
721 if (this->xml_buffer)
722 multi_buffer_offset += strlen (this->xml_buffer);
724 this->xml_buffer = xml_buffer;
725 xml_buffer_start_index = 0;
728 void ValidateTemplate (const char* buffer, XamlContext* context, FrameworkTemplate *binding_source)
730 XamlLoader *loader = new XamlLoader (NULL, buffer, NULL, context);
731 Type::Kind dummy;
733 context->SetTemplateBindingSource (binding_source);
735 loader->SetImportDefaultXmlns (true);
737 MoonError error;
738 Value *result = loader->CreateFromStringWithError (buffer, true, &dummy, XamlLoader::IMPORT_DEFAULT_XMLNS | XamlLoader::VALIDATE_TEMPLATES, &error);
740 delete result;
741 delete loader;
743 if (error.number != MoonError::NO_ERROR) {
744 int line_number = error.line_number + XML_GetCurrentLineNumber (parser);
745 error_args = new ParserErrorEventArgs (error.message, file_name, line_number, error.char_position, error.code, NULL, NULL);
749 FrameworkTemplate *GetTemplateParent (XamlElementInstance *item)
751 XamlElementInstance *parent = item->parent;
753 while (parent && !parent->IsTemplate ())
754 parent = parent->parent;
756 if (parent)
757 return (FrameworkTemplate *) parent->GetManagedPointer ();
759 if (!loader)
760 return NULL;
762 XamlContext *context = loader->GetContext ();
763 if (!context)
764 return NULL;
766 return context->internal->template_parent;
769 Value *GetTopElementPtr ()
771 XamlContext *context = loader->GetContext ();
772 if (context)
773 return context->internal->top_element;
775 if (top_element)
776 return top_element->GetAsValue ();
778 return NULL;
781 ~XamlParserInfo ()
783 created_elements = g_list_reverse (created_elements);
784 g_list_foreach (created_elements, unref_xaml_element, NULL);
785 g_list_free (created_elements);
787 g_list_foreach (created_namespaces, destroy_created_namespace, NULL);
788 g_list_free (created_namespaces);
790 g_hash_table_destroy (namespace_map);
792 if (cdata)
793 g_string_free (cdata, TRUE);
794 if (top_element)
795 delete top_element;
796 namescope->unref ();
803 class XamlElementInfoNative : public XamlElementInfo {
804 Type *type;
806 public:
807 XamlElementInfoNative (Type *t) : XamlElementInfo (NULL, t->GetName (), t->GetKind ())
809 type = t;
812 Type* GetType ()
814 return type;
817 const char* GetName ()
819 return type->GetName ();
822 const char* GetContentProperty (XamlParserInfo *p);
824 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
825 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
826 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
830 class XamlElementInstanceNative : public XamlElementInstance {
831 XamlElementInfoNative *element_info;
832 XamlParserInfo *parser_info;
834 public:
835 XamlElementInstanceNative (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item = true);
837 virtual DependencyObject *CreateItem ();
839 virtual XamlElementInfo* FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot);
841 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value);
842 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value);
843 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child);
844 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
848 class XamlElementInstanceValueType : public XamlElementInstance {
849 XamlElementInfoNative *element_info;
850 XamlParserInfo *parser_info;
852 public:
853 XamlElementInstanceValueType (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type);
855 virtual bool IsDependencyObject ()
857 return false;
860 virtual Value *GetAsValue ()
862 if (value == NULL) {
863 // we are an empty element (e.g. <sys:String></sys:String>). do type specific magic here.
864 CreateValueItemFromString ("");
867 return value;
870 bool CreateValueItemFromString (const char* str);
872 // A Value type doesn't really support anything. It's just here so people can do <SolidColorBrush.Color><Color>#FF00FF</Color></SolidColorBrush.Color>
873 virtual DependencyObject *CreateItem () { return NULL; }
874 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) { return false; }
875 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value) { return false; }
876 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) { }
877 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
879 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value) { return false; }
880 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value) { return CreateValueItemFromString (value); }
883 class XamlElementInfoEnum : public XamlElementInfo {
884 public:
885 XamlElementInfoEnum (const char *name) : XamlElementInfo (NULL, name, Type::INT32)
889 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
890 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
891 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name) { return NULL; }
894 class XamlElementInstanceEnum : public XamlElementInstance {
896 public:
897 XamlElementInstanceEnum (XamlElementInfoEnum *element_info, const char *name, ElementType type);
899 virtual bool IsDependencyObject ()
901 return false;
904 virtual Value *GetAsValue ()
906 return value;
909 bool CreateEnumFromString (const char* str);
911 // An enum type doesn't really support anything. It's just here so people can do <Visibility>Visible</Visibility>
912 virtual DependencyObject *CreateItem () { return NULL; }
913 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) { return false; }
914 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value) { return false; }
915 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) { }
916 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
918 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value) { return false; }
919 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value) { return CreateEnumFromString (value); }
922 class XamlElementInstanceTemplate : public XamlElementInstanceNative {
923 public:
924 XamlElementInstanceTemplate (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item = true)
925 : XamlElementInstanceNative (element_info, parser_info, name, type, create_item)
929 virtual bool IsTemplate ()
931 return true;
936 class DefaultNamespace : public XamlNamespace {
937 public:
938 DefaultNamespace () { }
940 virtual ~DefaultNamespace () { }
942 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
944 Type* t = Type::Find (p->deployment, el, false);
945 if (t && !kind_requires_managed_load (t->GetKind ()))
946 return new XamlElementInfoNative (t);
948 if (enums_is_enum_name (el))
949 return new XamlElementInfoEnum (g_strdup (el));
951 XamlElementInfo* managed_element = create_element_info_from_imported_managed_type (p, el, attr, create);
952 if (managed_element)
953 return managed_element;
955 return NULL;
959 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
961 return false;
964 virtual const char* GetUri () { return "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; }
965 virtual const char* GetPrefix () { return ""; }
968 class XmlNamespace : public XamlNamespace {
969 public:
970 XmlNamespace () { }
972 virtual ~XmlNamespace () { }
974 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
976 return NULL;
979 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
981 if (!strcmp ("lang", attr)) {
982 if (item->IsDependencyObject ()) {
983 DependencyObject *dob = item->GetAsDependencyObject ();
984 if (dob->Is(Type::FRAMEWORKELEMENT)) {
985 ((FrameworkElement*)dob)->SetLanguage (value);
986 return true;
991 return false;
994 virtual const char* GetUri () { return "http://www.w3.org/XML/1998/namespace"; }
995 virtual const char* GetPrefix () { return "xml"; }
998 class XNamespace : public XamlNamespace {
999 public:
1000 XNamespace () { }
1002 virtual ~XNamespace () { }
1004 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1006 return NULL;
1009 virtual char *FindTypeName (const char **attr, char **xmlns)
1011 char *res = NULL;
1013 if (!attr)
1014 return NULL;
1016 for (int i = 0; attr [i]; i += 2) {
1017 const char *ns = strchr (attr [i], '|');
1018 if (!ns)
1019 continue;
1021 if (strncmp (GetUri (), attr [i], ns - attr [i]) || strcmp ("Class", ns + 1))
1022 continue;
1024 ns = strchr (attr [i + 1], ';');
1025 if (!ns) {
1026 *xmlns = g_strdup ("");
1027 res = g_strdup (attr [i + 1]);
1028 } else {
1029 *xmlns = g_strdup (ns + 1);
1030 res = g_strndup (attr [i + 1], attr [i + 1] - ns);
1032 return res;
1034 return NULL;
1037 bool IsParentResourceDictionary (XamlElementInstance *parent)
1039 if (parent == NULL)
1040 return false;
1042 return Type::IsSubclassOf (Deployment::GetCurrent (), parent->info->GetKind (), Type::RESOURCE_DICTIONARY);
1045 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1047 if (!strcmp ("Name", attr)) {
1049 // Causes breakage in airlines
1050 // Maybe x:Name overwrites but Name does not?
1052 // if (p->namescope->FindName (value)) {
1053 // parser_error (p, p->current_element->element_name, "x:Name", 2028, "The name already exists in the tree: %s.", value);
1054 // return false;
1055 // }
1058 if (IsParentResourceDictionary (p->current_element)) {
1059 if (item->GetKey ()) {
1060 // XXX don't know the proper values here...
1061 parser_error (p, item->element_name, NULL, 2028,
1062 "The name already exists in the tree: %s.", value);
1063 return false;
1067 if (item->GetName ()) {
1068 parser_error (p, item->element_name, NULL, 2016, "Cannot specify both Name and x:Name attributes.");
1069 return false;
1072 item->SetName (p, value);
1074 if (item->IsDependencyObject ()) {
1075 NameScope *scope = p->namescope;
1076 if (!item->GetAsDependencyObject ()->SetName (value, scope)) {
1077 if (IsParentResourceDictionary (p->current_element)) {
1078 // FIXME: inside of a resource dictionary this has an extremly
1079 // strange behavior. this isn't exactly right, since not only
1080 // does the exception get swallowed, but the name seems to also
1081 // be unregistered.
1083 else {
1084 parser_error (p, item->element_name, NULL, 2028,
1085 "The name already exists in the tree: %s.", value);
1086 return false;
1089 return true;
1092 return false;
1095 if (!strcmp ("Key", attr)) {
1096 if (item->GetKey () && IsParentResourceDictionary (p->current_element) && !Type::IsSubclassOf (p->deployment, item->info->GetKind (), Type::STORYBOARD)) {
1097 // XXX don't know the proper values here...
1098 parser_error (p, item->element_name, NULL, 2028,
1099 "The name already exists in the tree: %s.", value);
1100 return false;
1102 item->SetKey (p, value);
1103 return true;
1106 if (!strcmp ("Class", attr)) {
1107 if (!is_legal_top_level_kind (item->info->GetKind ())) {
1108 // XXX don't know the proper values here...
1109 parser_error (p, item->element_name, attr, -1,
1110 "Cannot specify x:Class type '%s' on value type element (%s).", value, item->element_name);
1111 return false;
1114 if (p->top_element != item) {
1115 // HAH: what a useless error message
1116 parser_error (p, item->element_name, attr, 2012,
1117 "Unknown attribute %s on element %s.", attr, item->element_name);
1118 return false;
1121 // While hydrating, we do not need to create the toplevel class, its created already
1122 if (p->hydrating)
1123 return true;
1124 else {
1125 parser_error (p, item->element_name, attr, 4005,
1126 "Cannot specify x:Class in xaml files outside of a xap.");
1127 return false;
1131 return false;
1134 virtual const char* GetUri () { return X_NAMESPACE_URI; }
1135 virtual const char* GetPrefix () { return "x"; }
1139 class PrimitiveNamespace : public XamlNamespace {
1141 private:
1142 char *prefix;
1145 public:
1146 PrimitiveNamespace (char *prefix)
1148 this->prefix = prefix;
1151 virtual ~PrimitiveNamespace ()
1153 if (prefix)
1154 g_free (prefix);
1157 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1159 if (!strcmp ("String", el)) {
1160 Type* t = Type::Find (p->deployment, Type::STRING);
1161 // it's not as easy in this case, because primitive clr strings require that the
1162 // character data be read in verbatim, including all whitespace.
1163 XamlElementInfo *info = new XamlElementInfoNative (t);
1164 info->SetIsCDataVerbatim (true);
1165 return info;
1166 } else if (!strcmp ("Int32", el)) {
1167 Type* t = Type::Find (p->deployment, Type::INT32);
1168 return new XamlElementInfoNative (t);
1169 } else if (!strcmp ("Double", el)) {
1170 Type* t = Type::Find (p->deployment, Type::DOUBLE);
1171 return new XamlElementInfoNative (t);
1172 } else if (!strcmp ("Boolean", el)) {
1173 Type* t = Type::Find (p->deployment, Type::BOOL);
1174 return new XamlElementInfoNative (t);
1175 } else if (!strcmp ("TimeSpan", el)) {
1176 Type* t = Type::Find (p->deployment, Type::TIMESPAN);
1177 return new XamlElementInfoNative (t);
1180 return NULL;
1183 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1185 return false;
1188 virtual const char* GetUri () { return PRIMITIVE_NAMESPACE_URI; }
1189 virtual const char* GetPrefix () { return prefix; }
1193 class MCIgnorableNamespace : public XamlNamespace {
1195 private:
1196 char *prefix;
1198 public:
1199 MCIgnorableNamespace (char *prefix)
1201 this->prefix = prefix;
1204 virtual ~MCIgnorableNamespace ()
1206 if (prefix)
1207 g_free (prefix);
1210 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1212 return NULL;
1215 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1217 if (!strcmp ("Ignorable", attr)) {
1218 const char *start = value;
1219 do {
1220 const char *space = strchr (start, ' ');
1221 char *prefix;
1222 if (space) {
1223 prefix = g_strndup (start, space - start);
1224 start = space + 1;
1225 } else {
1226 prefix = g_strdup (start);
1227 start = NULL;
1230 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
1231 if (ns)
1232 ns->is_ignored = true;
1234 } while (start);
1236 return true;
1239 return false;
1242 virtual const char* GetUri () { return MC_IGNORABLE_NAMESPACE_URI; }
1243 virtual const char* GetPrefix () { return prefix; }
1247 static void
1248 destroy_created_namespace (gpointer data, gpointer user_data)
1250 XamlNamespace* ns = (XamlNamespace *) data;
1251 delete ns;
1255 class XamlElementInfoManaged : public XamlElementInfo {
1256 public:
1257 XamlElementInfoManaged (const char *xmlns, const char *name, XamlElementInfo *parent, Type::Kind dependency_type, Value *obj) : XamlElementInfo (xmlns, name, dependency_type)
1259 this->obj = obj;
1262 Value *obj;
1264 const char* GetName () { return name; }
1266 const char* GetContentProperty (XamlParserInfo *p);
1268 virtual bool RequiresManagedSet () { return true; }
1270 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
1271 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
1272 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
1276 class XamlElementInstanceManaged : public XamlElementInstance {
1277 public:
1278 XamlElementInstanceManaged (XamlElementInfo *info, const char *name, ElementType type, Value *obj);
1280 virtual bool IsDependencyObject ()
1282 return is_dependency_object;
1285 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value);
1286 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value);
1287 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child);
1288 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
1290 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value);
1291 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value);
1293 virtual void* GetManagedPointer ();
1294 virtual Value* GetParentPointer ();
1295 private:
1296 bool is_dependency_object;
1300 class XamlElementInfoImportedManaged : public XamlElementInfoManaged {
1301 public:
1302 XamlElementInfoImportedManaged (const char *name, XamlElementInfo *parent, Value *obj) : XamlElementInfoManaged (NULL, name, parent, obj->GetKind (), obj)
1306 const char* GetContentProperty (XamlParserInfo *p);
1308 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
1309 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
1310 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
1315 class ManagedNamespace : public XamlNamespace {
1316 public:
1317 char *xmlns;
1318 char *prefix;
1320 ManagedNamespace (char *xmlns, char *prefix)
1322 this->xmlns = xmlns;
1323 this->prefix = prefix;
1326 virtual ~ManagedNamespace ()
1328 g_free (xmlns);
1329 g_free (prefix);
1332 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1334 char* type_name = NULL;
1335 char* type_xmlns = NULL;
1336 const char* use_xmlns = xmlns;
1338 if (!p->loader)
1339 return NULL;
1341 if (x_namespace) {
1342 // We might have an x:Class attribute specified, so we need to use that for the
1343 // type_name that we pass to LookupObject
1344 if (strcmp ("Application", el)) {
1345 type_name = x_namespace->FindTypeName (attr, &type_xmlns);
1346 if (type_name) {
1347 el = type_name;
1348 use_xmlns = type_xmlns;
1350 if (!p->hydrating) {
1351 parser_error (p, el, "x:Class", 4005, "Cannot specify x:Class in xaml files outside of a xap.");
1352 return NULL;
1358 Value *value = new Value ();
1359 if (!p->loader->LookupObject (p, p->GetTopElementPtr (), p->current_element ? p->current_element->GetAsValue () : NULL, use_xmlns, el, create, false, value)) {
1360 parser_error (p, el, NULL, 2007, "Unable to resolve managed type %s.", el);
1361 delete value;
1362 if (type_name)
1363 g_free (type_name);
1364 if (type_xmlns)
1365 g_free (type_xmlns);
1366 return NULL;
1369 if (p->hydrate_expecting) {
1371 // If we are hydrating a top level managed object, use the Value* passed
1372 // to Hydrate as our value
1374 Value *v = value;
1375 value = p->hydrate_expecting;
1376 delete v;
1379 XamlElementInfoManaged *info = new XamlElementInfoManaged (xmlns, g_strdup (el), NULL, value->GetKind (), value);
1380 if (type_name)
1381 g_free (type_name);
1382 if (type_xmlns)
1383 g_free (type_xmlns);
1384 return info;
1387 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1389 if (is_ignored)
1390 return true;
1392 if (p->loader) {
1393 Value v = Value (value);
1394 return p->loader->SetProperty (p, p->GetTopElementPtr (), item->info->xmlns, item->GetAsValue (), item, item->GetParentPointer (), xmlns, attr, &v, NULL);
1396 return false;
1400 virtual const char* GetUri () { return xmlns; }
1401 virtual const char* GetPrefix () { return prefix; }
1404 bool
1405 XamlLoader::LookupObject (void *p, Value *top_level, Value *parent, const char* xmlns, const char* type_name, bool create, bool is_property, Value *value)
1407 if (callbacks.lookup_object) {
1408 if (!vm_loaded && !LoadVM ())
1409 return false;
1410 MoonError error;
1411 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1412 bool res = callbacks.lookup_object (&data, parent, xmlns, type_name, create, is_property, value, &error);
1413 return res;
1416 return false;
1419 const char *
1420 XamlLoader::GetContentPropertyName (void *p, Value *top_level, Value *object)
1422 if (callbacks.get_content_property_name) {
1423 MoonError error;
1424 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1425 return callbacks.get_content_property_name (&data, object, &error);
1427 return NULL;
1430 bool
1431 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)
1433 if (callbacks.set_property) {
1434 MoonError error;
1435 XamlCallbackData data = XamlCallbackData (this, p, top_level, flags);
1436 bool res = callbacks.set_property (&data, xmlns, target, target_data, target_parent, prop_xmlns, name, value, value_data, &error);
1438 if (error.number != MoonError::NO_ERROR) {
1439 parser_error ((XamlParserInfo *) p, ((XamlElementInstance *) target_data)->element_name, NULL, error.code, error.message);
1440 return false;
1443 return res;
1446 return false;
1449 bool
1450 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)
1452 if (callbacks.add_child) {
1453 MoonError error;
1454 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1455 bool res = callbacks.add_child (&data, parent_parent, parent_is_property, parent_xmlns, parent, parent_data, child, child_data, &error);
1457 if (error.number != MoonError::NO_ERROR) {
1458 parser_error ((XamlParserInfo *) p, ((XamlElementInstance *) child_data)->element_name, NULL, error.code, error.message);
1459 return false;
1462 return res;
1464 return false;
1467 XamlLoader::XamlLoader (const char *resourceBase, const char* filename, const char* str, Surface* surface, XamlContext *context)
1469 Initialize (resourceBase, filename, str, surface, context);
1472 XamlLoader::XamlLoader (const char* filename, const char* str, Surface* surface, XamlContext *context)
1474 Initialize (NULL, filename, str, surface, context);
1477 void
1478 XamlLoader::Initialize (const char *resourceBase, const char* filename, const char* str, Surface* surface, XamlContext *context)
1480 this->filename = g_strdup (filename);
1481 this->resource_base = g_strdup (resourceBase);
1482 this->str = g_strdup (str);
1483 this->surface = surface;
1484 if (surface)
1485 surface->ref ();
1486 this->context = context;
1487 this->vm_loaded = false;
1488 this->error_args = NULL;
1489 this->expanding_template = false;
1490 this->template_owner = NULL;
1491 this->import_default_xmlns = false;
1493 if (context) {
1494 callbacks = context->internal->callbacks;
1495 this->vm_loaded = true;
1497 #if DEBUG
1498 if (!surface && debug_flags & RUNTIME_DEBUG_XAML) {
1499 printf ("XamlLoader::XamlLoader ('%s', '%s', %p): Initializing XamlLoader without a surface.\n",
1500 filename, str, surface);
1502 #endif
1505 XamlLoader::~XamlLoader ()
1507 g_free (filename);
1508 g_free (resource_base);
1509 g_free (str);
1510 if (surface)
1511 surface->unref ();
1512 surface = NULL;
1513 filename = NULL;
1514 str = NULL;
1515 if (error_args)
1516 error_args->unref();
1519 bool
1520 XamlLoader::LoadVM ()
1522 return false;
1525 XamlLoader*
1526 xaml_loader_new (const char *resourceBase, const char* filename, const char* str, Surface* surface)
1528 return new XamlLoader (resourceBase, filename, str, surface);
1531 void
1532 xaml_loader_free (XamlLoader* loader)
1534 delete loader;
1537 void
1538 xaml_loader_set_callbacks (XamlLoader* loader, XamlLoaderCallbacks callbacks)
1540 if (!loader) {
1541 LOG_XAML ("Trying to set callbacks for a null object\n");
1542 return;
1545 loader->callbacks = callbacks;
1546 loader->vm_loaded = true;
1549 static gboolean
1550 namespace_for_prefix (gpointer key, gpointer value, gpointer user_data)
1552 XamlNamespace *ns = (XamlNamespace *) value;
1553 const char *prefix = (const char *) user_data;
1555 if (!strcmp (prefix, ns->GetPrefix ()))
1556 return TRUE;
1557 return FALSE;
1560 char*
1561 xaml_uri_for_prefix (void *parser, char* prefix)
1563 XamlParserInfo *p = (XamlParserInfo *) parser;
1565 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
1566 if (!ns)
1567 return NULL;
1569 return g_strdup (ns->GetUri ());
1573 // Called when we encounter an error. Note that memory ownership is taken for everything
1574 // except the message, this allows you to use g_strdup_printf when creating the error message
1576 static void
1577 parser_error (XamlParserInfo *p, const char *el, const char *attr, int error_code, const char *format, ...)
1579 char *message;
1580 va_list args;
1582 // Already failed
1583 if (p->error_args)
1584 return;
1586 // if parsing fails too early it's not safe (i.e. sigsegv) to call some functions, e.g. XML_GetCurrentLineNumber
1587 bool report_line_col = (error_code != XML_ERROR_XML_DECL);
1588 int line_number = report_line_col ? XML_GetCurrentLineNumber (p->parser) : 0;
1589 int char_position = report_line_col ? XML_GetCurrentColumnNumber (p->parser) : 0;
1591 va_start (args, format);
1592 message = g_strdup_vprintf (format, args);
1593 va_end (args);
1595 p->error_args = new ParserErrorEventArgs (message, p->file_name, line_number, char_position, error_code, el, attr);
1597 g_free (message);
1599 LOG_XAML ("PARSER ERROR, STOPPING PARSING: (%d) %s line: %d char: %d\n", error_code, message,
1600 line_number, char_position);
1602 XML_StopParser (p->parser, FALSE);
1605 void
1606 expat_parser_error (XamlParserInfo *p, XML_Error expat_error)
1608 // Already had an error
1609 if (p->error_args)
1610 return;
1612 LOG_XAML ("expat error is: %d\n", expat_error);
1614 switch (expat_error) {
1615 case XML_ERROR_DUPLICATE_ATTRIBUTE:
1616 parser_error (p, NULL, NULL, 7031, "wfc: unique attribute spec");
1617 break;
1618 case XML_ERROR_UNBOUND_PREFIX:
1619 parser_error (p, NULL, NULL, 7055, "undeclared prefix");
1620 break;
1621 case XML_ERROR_NO_ELEMENTS:
1622 parser_error (p, NULL, NULL, 7000, "unexpected end of input");
1623 break;
1624 case XML_ERROR_SYNTAX:
1625 parser_error (p, NULL, NULL, 2103, "syntax error");
1626 break;
1627 default:
1628 parser_error (p, NULL, NULL, expat_error, "Unhandled XML error %s", XML_ErrorString (expat_error));
1629 break;
1633 static void
1634 start_element (void *data, const char *el, const char **attr)
1636 XamlParserInfo *p = (XamlParserInfo *) data;
1637 XamlElementInfo *elem = NULL;
1638 XamlElementInstance *inst;
1639 Types *types = Deployment::GetCurrent ()->GetTypes ();
1641 if (!strcmp (el, INTERNAL_IGNORABLE_ELEMENT))
1642 return;
1644 if (p->ShouldBeginBuffering ()) {
1645 p->BeginBuffering ();
1646 return;
1649 if (p->InBufferingMode ()) {
1650 if (!strcmp (p->buffer_until_element, el))
1651 p->buffer_depth++;
1652 return;
1655 const char *dot = strchr (el, '.');
1656 if (!dot)
1657 elem = p->current_namespace->FindElement (p, el, attr, p->hydrate_expecting == NULL);
1659 if (p->error_args)
1660 return;
1663 if (elem) {
1664 if (p->hydrate_expecting){
1666 Type::Kind expecting_type = p->hydrate_expecting->GetObjectType ();
1668 if (!types->IsSubclassOf (expecting_type, elem->GetKind ())) {
1669 parser_error (p, el, NULL, -1, "Invalid top-level element found %s, expecting %s", el,
1670 types->Find (expecting_type)->GetName ());
1671 return;
1675 inst = elem->CreateWrappedElementInstance (p, p->hydrate_expecting);
1676 p->hydrate_expecting = NULL;
1677 } else
1678 inst = elem->CreateElementInstance (p);
1680 if (!inst)
1681 return;
1683 inst->parent = p->current_element;
1685 if (!p->top_element) {
1686 p->top_element = inst;
1687 if (inst->GetAsDependencyObject ())
1688 NameScope::SetNameScope (inst->GetAsDependencyObject (), p->namescope);
1691 if (inst->GetAsDependencyObject ())
1692 inst->GetAsDependencyObject ()->SetIsBeingParsed (true);
1694 inst->SetAttributes (p, attr);
1695 if (p->error_args)
1696 return;
1698 if (inst->IsDependencyObject ()) {
1699 if (p->current_element){
1700 if (p->current_element->info) {
1701 p->current_element->AddChild (p, inst);
1702 if (p->error_args)
1703 return;
1707 } else {
1708 // it's actually valid (from SL point of view) to have <Ellipse.Triggers> inside a <Rectangle>
1709 // however we can't add properties to something bad, like a <Recta.gle> element
1710 XamlElementInfo *prop_info = NULL;
1711 if (dot) {
1712 gchar *prop_elem = g_strndup (el, dot - el);
1713 prop_info = p->current_element->FindPropertyElement (p, el, dot);
1714 g_free (prop_elem);
1717 if (prop_info != NULL) {
1718 inst = prop_info->CreatePropertyElementInstance (p, g_strdup (el));
1719 inst->parent = p->current_element;
1721 if (attr [0] != NULL) {
1722 // It appears there is a bug in the error string but it matches the MS runtime
1723 parser_error (p, el, NULL, 2018, "The element %s does not support attributes.", attr[0]);
1724 return;
1727 if (prop_info && !strcmp (el, "TextBox.Text"))
1728 prop_info->SetIsCDataVerbatim (true);
1730 if (!p->top_element) {
1731 if (types->IsSubclassOf (prop_info->GetKind (), Type::COLLECTION)) {
1732 XamlElementInstance *wrap = prop_info->CreateElementInstance (p);
1733 NameScope::SetNameScope (wrap->GetAsDependencyObject (), p->namescope);
1734 p->top_element = wrap;
1735 p->current_element = wrap;
1736 return;
1739 } else {
1740 g_warning ("Unknown element: %s.", el);
1741 parser_error (p, el, NULL, 2007, "Unknown element: %s.", el);
1742 return;
1746 if (p->current_element) {
1747 p->current_element->children->Append (inst);
1749 p->current_element = inst;
1751 if (elem && element_begins_buffering (elem->GetKind ())) {
1752 p->QueueBeginBuffering (g_strdup (el), BUFFER_MODE_TEMPLATE);
1756 static bool
1757 allow_value_from_str_in_flush (XamlParserInfo *p, XamlElementInstance *parent)
1759 if (parent == NULL || parent->element_type != XamlElementInstance::PROPERTY || parent->parent == NULL || !parent->parent->IsDependencyObject ())
1760 return false;
1762 if (parent->info->GetKind () == Type::OBJECT)
1763 return true;
1765 return false;
1768 static void
1769 flush_char_data (XamlParserInfo *p)
1771 if (p->InBufferingMode ())
1772 return;
1774 if (!p->cdata || !p->current_element)
1775 return;
1777 if (p->current_element->info->IsCDataVerbatim()) {
1778 p->cdata->str = g_strstrip (p->cdata->str);
1781 if (p->current_element->element_type == XamlElementInstance::ELEMENT) {
1782 if (!p->current_element->TrySetContentProperty (p, p->cdata->str) && p->cdata_content) {
1783 if (allow_value_from_str_in_flush (p, p->current_element->parent)) {
1784 Value *v;
1785 if (value_from_str (p->current_element->info->GetKind (), NULL, p->cdata->str, &v)) {
1786 p->current_element->SetValue (v);
1787 goto cleanup;
1790 parser_error (p, p->current_element->element_name, NULL, 2011,
1791 "%s does not support text content.", p->current_element->element_name);
1793 } else if (p->current_element->element_type == XamlElementInstance::PROPERTY) {
1794 if (p->cdata_content && p->current_element->parent && !p->current_element->parent->SetProperty (p, p->current_element, p->cdata->str)) {
1795 parser_error (p, p->current_element->element_name, NULL, 2011,
1796 "%s does not support text content.", p->current_element->element_name);
1800 cleanup:
1801 if (p->cdata) {
1802 g_string_free (p->cdata, TRUE);
1803 p->cdata_content = false;
1804 p->cdata = NULL;
1808 static bool
1809 element_begins_buffering (Type::Kind kind)
1811 return Type::IsSubclassOf (Deployment::GetCurrent (), kind, Type::FRAMEWORKTEMPLATE);
1814 static gboolean
1815 is_default_namespace (gpointer key, gpointer value, gpointer user_data)
1817 return value == default_namespace;
1820 static void
1821 start_element_handler (void *data, const char *el, const char **attr)
1823 XamlParserInfo *p = (XamlParserInfo *) data;
1825 if (p->error_args)
1826 return;
1828 char **name = g_strsplit (el, "|", -1);
1829 XamlNamespace *next_namespace = NULL;
1830 char *element = NULL;
1832 if (g_strv_length (name) == 2) {
1833 // Find the proper namespace for our next element
1834 next_namespace = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, name [0]);
1835 element = name [1];
1838 if (!next_namespace && p->implicit_default_namespace) {
1839 // Use the default namespace for the next element
1840 next_namespace = default_namespace;
1841 element = name [0];
1842 } else if (!next_namespace) {
1843 if (!g_hash_table_find (p->namespace_map, is_default_namespace, NULL))
1844 return parser_error (p, el, NULL, 2263, "AG_E_PARSER_MISSING_DEFAULT_NAMESPACE");
1847 if (next_namespace && next_namespace->is_ignored) {
1848 p->current_namespace = next_namespace;
1849 if (!p->InBufferingMode ())
1850 p->QueueBeginBuffering (g_strdup (element), BUFFER_MODE_IGNORE);
1852 start_element (data, element, attr); // This will force the buffering to start/build depth if needed
1853 return;
1856 p->next_element = element;
1858 flush_char_data (p);
1860 // Now update our namespace
1861 p->current_namespace = next_namespace;
1863 if (!p->current_namespace && !p->InBufferingMode ()) {
1864 if (name[1])
1865 parser_error (p, name[1], NULL, -1, "No handlers available for namespace: '%s' (%s)\n", name[0], el);
1866 else
1867 parser_error (p, name[1], NULL, -1, "No namespace mapping available for element: '%s'\n", el);
1869 g_strfreev (name);
1870 return;
1873 p->next_element = NULL;
1874 start_element (data, element, attr);
1876 g_strfreev (name);
1879 static char*
1880 get_element_name (XamlParserInfo* p, const char *el)
1882 char **names = g_strsplit (el, "|", -1);
1883 char *name = g_strdup (names [g_strv_length (names) - 1]);
1885 g_strfreev (names);
1887 return name;
1890 static GSList *
1891 create_resource_list (XamlParserInfo *p)
1893 GSList *list = NULL;
1894 XamlElementInstance *walk = p->current_element;
1896 Types * types = Deployment::GetCurrent ()->GetTypes ();
1897 while (walk) {
1898 if (walk->element_type == XamlElementInstance::ELEMENT && types->IsSubclassOf (walk->info->GetKind (), Type::FRAMEWORKELEMENT)) {
1899 FrameworkElement *fwe = (FrameworkElement *)walk->GetAsDependencyObject ();
1900 if (g_slist_index (list, fwe) == -1)
1901 list = g_slist_prepend (list, fwe);
1903 if (walk->element_type == XamlElementInstance::ELEMENT && types->IsSubclassOf (walk->info->GetKind (), Type::RESOURCE_DICTIONARY)) {
1904 ResourceDictionary *rd = (ResourceDictionary *) walk->GetAsDependencyObject ();
1905 if (g_slist_index (list, rd) == -1)
1906 list = g_slist_prepend (list, walk->GetAsDependencyObject ());
1908 walk = walk->parent;
1911 list = g_slist_reverse (list);
1912 return list;
1915 static XamlContext *
1916 create_xaml_context (XamlParserInfo *p, FrameworkTemplate *template_, XamlContext *parent_context)
1918 GSList *resources = create_resource_list (p);
1919 XamlContextInternal *ic = new XamlContextInternal (p->loader->callbacks, p->GetTopElementPtr (), template_, p->namespace_map, resources, parent_context ? parent_context->internal : NULL);
1920 return new XamlContext (ic);
1923 static void
1924 end_element_handler (void *data, const char *el)
1926 XamlParserInfo *p = (XamlParserInfo *) data;
1927 DependencyObject *obj;
1929 if (!strcmp (el, INTERNAL_IGNORABLE_ELEMENT))
1930 return;
1932 if (p->error_args)
1933 return;
1935 if (!p->current_element) {
1936 g_warning ("p->current_element == NULL, current_element = %p (%s)\n",
1937 p->current_element, p->current_element ? p->current_element->element_name : "<NULL>");
1938 return;
1941 if (p->InBufferingMode ()) {
1942 char* name = get_element_name (p, el);
1943 if (!strcmp (p->buffer_until_element, name)) {
1944 p->buffer_depth--;
1946 if (p->buffer_depth == 0) {
1947 if (p->buffer_mode == BUFFER_MODE_TEMPLATE) {
1948 // OK we are done buffering, the element we are buffering for
1949 FrameworkTemplate* template_ = (FrameworkTemplate *) p->current_element->GetAsDependencyObject ();
1951 char* buffer = p->ClearBuffer ();
1953 XamlContext *context = create_xaml_context (p, template_, p->loader->GetContext());
1955 if (p->validate_templates) {
1956 p->ValidateTemplate (buffer, context, template_);
1958 if (p->error_args)
1959 return;
1962 template_->SetXamlBuffer (context, buffer);
1963 p->current_element = p->current_element->parent;
1964 } else if (p->buffer_mode == BUFFER_MODE_IGNORE) {
1965 // For now we'll actually keep/clear this buffer because it makes testing easier
1966 char *buffer = p->ClearBuffer ();
1967 g_free (buffer);
1972 g_free (name);
1973 return;
1976 switch (p->current_element->element_type) {
1977 case XamlElementInstance::ELEMENT:
1979 p->current_element->SetDelayedProperties (p);
1980 flush_char_data (p);
1982 // according to http://blogs.msdn.com/devdave/archive/2008/10/11/control-lifecycle.aspx
1983 // default styles are apply when the end tag is read.
1985 if (p->current_element->IsDependencyObject () &&
1986 p->current_element->GetAsDependencyObject() &&
1987 p->current_element->GetAsDependencyObject()->Is(Type::CONTROL)) {
1989 Control *control = (Control*)p->current_element->GetAsDependencyObject();
1990 ManagedTypeInfo *key = control->GetDefaultStyleKey ();
1992 if (key) {
1993 if (Application::GetCurrent () == NULL)
1994 g_warning ("attempting to use a null application applying default style while parsing.");
1995 else
1996 Application::GetCurrent()->ApplyDefaultStyle (control, key);
1999 else if (!p->current_element->IsDependencyObject ()) {
2001 if (p->current_element->parent)
2002 p->current_element->parent->AddChild (p, p->current_element);
2004 break;
2005 case XamlElementInstance::PROPERTY: {
2006 List::Node *walk = p->current_element->children->First ();
2007 while (walk) {
2008 XamlElementInstance *child = (XamlElementInstance *) walk;
2009 if (p->current_element->parent) {
2010 p->current_element->parent->SetProperty (p, p->current_element, child);
2012 walk = walk->next;
2014 flush_char_data (p);
2015 break;
2019 if ((obj = p->current_element->GetAsDependencyObject ()))
2020 obj->SetIsBeingParsed (false);
2022 p->current_element = p->current_element->parent;
2025 static void
2026 char_data_handler (void *data, const char *in, int inlen)
2028 XamlParserInfo *p = (XamlParserInfo *) data;
2029 register const char *inptr = in;
2030 const char *inend = in + inlen;
2031 const char *start;
2033 if (p->InBufferingMode ())
2034 return;
2036 if (p->error_args)
2037 return;
2039 if (p->current_element && p->current_element->info->IsCDataVerbatim()) {
2040 if (!p->cdata)
2041 p->cdata = g_string_new ("");
2043 g_string_append_len (p->cdata, inptr, inlen);
2044 p->cdata_content = true;
2045 return;
2048 if (!p->cdata) {
2049 p->cdata = g_string_new ("");
2051 if (g_ascii_isspace (*inptr)) {
2052 g_string_append_c (p->cdata, ' ');
2053 inptr++;
2055 while (inptr < inend && g_ascii_isspace (*inptr))
2056 inptr++;
2059 if (inptr == inend)
2060 return;
2061 } else if (g_ascii_isspace (p->cdata->str[p->cdata->len - 1])) {
2062 // previous cdata chunk ended with lwsp, skip over leading lwsp for this chunk
2063 while (inptr < inend && g_ascii_isspace (*inptr))
2064 inptr++;
2067 while (inptr < inend) {
2068 start = inptr;
2069 while (inptr < inend && !g_ascii_isspace (*inptr))
2070 inptr++;
2072 if (inptr > start) {
2073 g_string_append_len (p->cdata, start, inptr - start);
2074 p->cdata_content = true;
2077 if (inptr < inend) {
2078 g_string_append_c (p->cdata, ' ');
2079 inptr++;
2081 while (inptr < inend && g_ascii_isspace (*inptr))
2082 inptr++;
2087 static void
2088 start_namespace_handler (void *data, const char *prefix, const char *uri)
2090 XamlParserInfo *p = (XamlParserInfo *) data;
2092 if (p->InBufferingMode ())
2093 return;
2095 if (p->error_args)
2096 return;
2098 if (p->loader != NULL && p->loader->callbacks.import_xaml_xmlns != NULL) {
2099 MoonError error;
2100 XamlCallbackData data = XamlCallbackData (p->loader, p, p->GetTopElementPtr ());
2101 if (!p->loader->callbacks.import_xaml_xmlns (&data, uri, &error))
2102 return parser_error (p, p->current_element ? p->current_element->element_name : NULL, prefix, 2005, "Unknown namespace %s", uri);
2105 for (int i = 0; default_namespace_names [i]; i++) {
2106 if (!strcmp (default_namespace_names [i], uri)) {
2107 g_hash_table_insert (p->namespace_map, g_strdup (uri), default_namespace);
2108 return;
2112 if (!strcmp (X_NAMESPACE_URI, uri)){
2113 g_hash_table_insert (p->namespace_map, g_strdup (uri), x_namespace);
2114 } else if (!strcmp (PRIMITIVE_NAMESPACE_URI, uri)) {
2115 PrimitiveNamespace *pn = new PrimitiveNamespace (g_strdup (prefix));
2116 g_hash_table_insert (p->namespace_map, g_strdup (uri), pn);
2117 p->AddCreatedNamespace (pn);
2118 } else if (!strcmp (MC_IGNORABLE_NAMESPACE_URI, uri)) {
2119 MCIgnorableNamespace *mc = new MCIgnorableNamespace (g_strdup (prefix));
2120 g_hash_table_insert (p->namespace_map, g_strdup (uri), mc);
2121 p->AddCreatedNamespace (mc);
2122 } else {
2123 if (!p->loader) {
2124 return parser_error (p, (p->current_element ? p->current_element->element_name : NULL), prefix, -1,
2125 "No managed element callback installed to handle %s", uri);
2128 if (!prefix) {
2129 parser_error (p, (p->current_element ? p->current_element->element_name : NULL), NULL, 2262,
2130 "AG_E_PARSER_NAMESPACE_NOT_SUPPORTED");
2131 return;
2134 ManagedNamespace *c = new ManagedNamespace (g_strdup (uri), g_strdup (prefix));
2135 g_hash_table_insert (p->namespace_map, g_strdup (c->xmlns), c);
2136 p->AddCreatedNamespace (c);
2140 static void
2141 start_doctype_handler (void *data,
2142 const XML_Char *doctype_name,
2143 const XML_Char *sysid,
2144 const XML_Char *pubid,
2145 int has_internal_subset)
2147 XamlParserInfo *p = (XamlParserInfo *) data;
2149 if (p->InBufferingMode ())
2150 return;
2152 if (sysid)
2153 return parser_error (p, NULL, NULL, 7050, "DTD was found but is prohibited");
2155 if (doctype_name)
2156 return parser_error (p, NULL, NULL, 7016, "incorrect document syntax.");
2159 static void
2160 add_default_namespaces (XamlParserInfo *p, bool sl_xmlns)
2162 if (sl_xmlns) {
2163 p->implicit_default_namespace = true;
2164 g_hash_table_insert (p->namespace_map, g_strdup ("http://schemas.microsoft.com/winfx/2006/xaml/presentation"), default_namespace);
2165 g_hash_table_insert (p->namespace_map, g_strdup (X_NAMESPACE_URI), x_namespace);
2167 g_hash_table_insert (p->namespace_map, g_strdup (XML_NAMESPACE_URI), xml_namespace);
2170 static void
2171 print_tree (XamlElementInstance *el, int depth)
2173 #if DEBUG
2174 if (debug_flags & RUNTIME_DEBUG_XAML) {
2175 for (int i = 0; i < depth; i++)
2176 printf ("\t");
2178 const char *name = NULL;
2180 if (!el) {
2181 printf (" -null- \n");
2182 return;
2185 if (el->element_type == XamlElementInstance::ELEMENT && el->IsDependencyObject ())
2186 name = el->GetAsDependencyObject ()->GetName ();
2187 printf ("%s (%s) (%p) (%s)\n", el->element_name, name ? name : "-no name-", el->parent, el->element_type == XamlElementInstance::PROPERTY ? "PROPERTY" : "ELEMENT");
2189 for (List::Node *walk = el->children->First (); walk != NULL; walk = walk->next) {
2190 XamlElementInstance *el = (XamlElementInstance *) walk;
2191 print_tree (el, depth + 1);
2194 #endif
2197 void
2198 xaml_parse_xmlns (const char* xmlns, char** type_name, char** ns, char** assembly)
2200 const char delimiters[] = ";";
2201 char* decl;
2202 char* buffer = g_strdup (xmlns);
2204 *type_name = NULL;
2205 *ns = NULL;
2206 *assembly = NULL;
2208 decl = strtok (buffer, delimiters);
2209 while (decl != NULL) {
2210 if (strstr (decl, "clr-namespace:") == decl) {
2211 if (*ns)
2212 g_free (*ns);
2213 *ns = g_strdup (decl + 14);
2214 } else if (strstr (decl, "assembly=") == decl) {
2215 if (*assembly)
2216 g_free (*assembly);
2217 *assembly = g_strdup (decl + 9);
2218 } else {
2219 if (*type_name)
2220 g_free (*type_name);
2221 *type_name = g_strdup (decl);
2224 decl = strtok (NULL, delimiters);
2226 g_free (buffer);
2229 Value *
2230 XamlLoader::CreateFromFile (const char *xaml_file, bool create_namescope,
2231 Type::Kind *element_type)
2233 Value *res = NULL;
2234 XamlParserInfo *parser_info = NULL;
2235 XML_Parser p = NULL;
2236 bool first_read = true;
2237 const char *inptr, *inend;
2238 TextStream *stream;
2239 char buffer[4096];
2240 ssize_t nread, n;
2242 LOG_XAML ("attemtping to load xaml file: %s\n", xaml_file);
2244 stream = new TextStream ();
2245 if (!stream->OpenFile (xaml_file, false)) {
2246 LOG_XAML ("can not open file\n");
2247 goto cleanup_and_return;
2250 if (!(p = XML_ParserCreateNS ("UTF-8", '|'))) {
2251 LOG_XAML ("can not create parser\n");
2252 goto cleanup_and_return;
2255 parser_info = new XamlParserInfo (p, xaml_file);
2257 parser_info->namescope->SetTemporary (!create_namescope);
2259 parser_info->loader = this;
2261 // TODO: This is just in here temporarily, to make life less difficult for everyone
2262 // while we are developing.
2263 add_default_namespaces (parser_info, false);
2265 XML_SetUserData (p, parser_info);
2267 XML_SetElementHandler (p, start_element_handler, end_element_handler);
2268 XML_SetCharacterDataHandler (p, char_data_handler);
2269 XML_SetNamespaceDeclHandler(p, start_namespace_handler, NULL);
2270 XML_SetDoctypeDeclHandler(p, start_doctype_handler, NULL);
2273 XML_SetProcessingInstructionHandler (p, proc_handler);
2276 while ((nread = stream->Read (buffer, sizeof (buffer))) >= 0) {
2277 inptr = buffer;
2278 n = nread;
2280 if (first_read && nread > 0) {
2281 // Remove preceding white space
2282 inend = buffer + nread;
2284 while (inptr < inend && g_ascii_isspace (*inptr))
2285 inptr++;
2287 if (inptr == inend)
2288 continue;
2290 n = (inend - inptr);
2291 first_read = false;
2294 parser_info->SetXmlBuffer (inptr);
2295 if (!XML_Parse (p, inptr, n, nread == 0)) {
2296 expat_parser_error (parser_info, XML_GetErrorCode (p));
2297 goto cleanup_and_return;
2300 if (nread == 0)
2301 break;
2304 print_tree (parser_info->top_element, 0);
2306 if (parser_info->top_element) {
2307 res = parser_info->top_element->GetAsValue ();
2308 // We want a copy because the old one is going to be deleted
2309 res = new Value (*res);
2311 if (element_type)
2312 *element_type = parser_info->top_element->info->GetKind ();
2314 if (parser_info->error_args) {
2315 *element_type = Type::INVALID;
2316 goto cleanup_and_return;
2320 cleanup_and_return:
2322 if (!parser_info)
2323 error_args = new ParserErrorEventArgs ("Error opening xaml file", xaml_file, 0, 0, 1, "", "");
2324 else if (parser_info->error_args) {
2325 error_args = parser_info->error_args;
2326 error_args->ref ();
2329 delete stream;
2331 if (p)
2332 XML_ParserFree (p);
2334 if (parser_info)
2335 delete parser_info;
2337 return res;
2340 Value *
2341 XamlLoader::CreateFromString (const char *xaml, bool create_namescope, Type::Kind *element_type, int flags)
2343 return HydrateFromString (xaml, NULL, create_namescope, element_type, flags);
2346 DependencyObject *
2347 value_to_dependency_object (Value *value)
2349 if (!value || !value->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT))
2350 return NULL;
2351 return value->AsDependencyObject ();
2354 DependencyObject *
2355 XamlLoader::CreateDependencyObjectFromFile (const char *xaml, bool create_namescope, Type::Kind *element_type)
2357 return value_to_dependency_object (CreateFromFile (xaml, create_namescope, element_type));
2360 DependencyObject *
2361 XamlLoader::CreateDependencyObjectFromString (const char *xaml, bool create_namescope, Type::Kind *element_type)
2363 return value_to_dependency_object (CreateFromString (xaml, create_namescope, element_type, IMPORT_DEFAULT_XMLNS));
2367 * Hydrates an existing DependencyObject (@object) with the contents from the @xaml
2368 * data
2370 Value *
2371 XamlLoader::HydrateFromString (const char *xaml, Value *object, bool create_namescope, Type::Kind *element_type, int flags)
2373 XML_Parser p = XML_ParserCreateNS ("utf-8", '|');
2374 XamlParserInfo *parser_info = NULL;
2375 Value *res = NULL;
2376 char *start = (char*)xaml;
2377 char *prepend = NULL;
2378 char *append = NULL;
2379 char * inputs [4] = {NULL, NULL, NULL, NULL};
2381 inputs [0] = start;
2383 if (!p) {
2384 LOG_XAML ("can not create parser\n");
2385 goto cleanup_and_return;
2388 #if 0
2389 if (true) {
2390 static int id = 0;
2391 char filename[64];
2392 FILE *fp;
2394 sprintf (filename, "createFromXaml.%d.xaml", id++);
2395 if ((fp = fopen (filename, "wt")) != NULL) {
2396 fwrite (xaml, strlen (xaml), 1, fp);
2397 fclose (fp);
2400 #endif
2402 parser_info = new XamlParserInfo (p, NULL);
2404 parser_info->namescope->SetTemporary (!create_namescope);
2406 parser_info->loader = this;
2407 parser_info->validate_templates = (flags & VALIDATE_TEMPLATES) == VALIDATE_TEMPLATES;
2410 // If we are hydrating, we are not null
2412 if (object != NULL) {
2413 parser_info->hydrate_expecting = object;
2414 parser_info->hydrating = true;
2415 if (Type::IsSubclassOf (parser_info->deployment, object->GetKind (), Type::DEPENDENCY_OBJECT)) {
2416 DependencyObject *dob = object->AsDependencyObject ();
2417 dob->SetIsAttached (true);
2418 dob->SetResourceBase (GetResourceBase());
2420 } else {
2421 parser_info->hydrate_expecting = NULL;
2422 parser_info->hydrating = false;
2425 // from_str gets the default namespaces implictly added
2426 add_default_namespaces (parser_info, (flags & IMPORT_DEFAULT_XMLNS) == IMPORT_DEFAULT_XMLNS);
2428 XML_SetUserData (p, parser_info);
2430 XML_SetElementHandler (p, start_element_handler, end_element_handler);
2431 XML_SetCharacterDataHandler (p, char_data_handler);
2432 XML_SetNamespaceDeclHandler(p, start_namespace_handler, NULL);
2433 XML_SetDoctypeDeclHandler(p, start_doctype_handler, NULL);
2436 XML_SetProcessingInstructionHandler (p, proc_handler);
2439 if (context) {
2440 prepend = context->internal->CreateIgnorableTagOpen ();
2441 append = context->internal->CreateIgnorableTagClose ();
2443 inputs [0] = prepend;
2444 inputs [1] = start;
2445 inputs [2] = append;
2448 for (int i = 0; inputs [i]; i++) {
2449 char *start = inputs [i];
2451 // don't freak out if the <?xml ... ?> isn't on the first line (see #328907)
2452 while (g_ascii_isspace (*start))
2453 start++;
2455 parser_info->SetXmlBuffer (start);
2456 if (!XML_Parse (p, start, strlen (start), inputs [i + 1] == NULL)) {
2457 expat_parser_error (parser_info, XML_GetErrorCode (p));
2458 LOG_XAML ("error parsing: %s\n\n", xaml);
2459 goto cleanup_and_return;
2463 print_tree (parser_info->top_element, 0);
2465 if (parser_info->top_element) {
2466 if (is_legal_top_level_kind (parser_info->top_element->info->GetKind ())) {
2467 res = parser_info->top_element->GetAsValue ();
2468 res = new Value (*res);
2469 if (res->Is (parser_info->deployment, Type::DEPENDENCY_OBJECT) && object) {
2470 DependencyObject *dob = res->AsDependencyObject ();
2471 dob->unref ();
2472 dob->SetIsHydratedFromXaml (parser_info->hydrating);
2476 if (element_type)
2477 *element_type = parser_info->top_element->info->GetKind ();
2479 if (!res && !parser_info->error_args)
2480 parser_info->error_args = new ParserErrorEventArgs ("No DependencyObject found", "", 0, 0, 1, "", "");
2482 if (parser_info->error_args) {
2483 delete res;
2484 res = NULL;
2485 if (element_type)
2486 *element_type = Type::INVALID;
2487 goto cleanup_and_return;
2491 cleanup_and_return:
2493 if (parser_info->error_args) {
2494 error_args = parser_info->error_args;
2495 printf ("Could not parse element %s, attribute %s, error: %s\n",
2496 error_args->xml_element,
2497 error_args->xml_attribute,
2498 error_args->GetErrorMessage());
2501 if (p)
2502 XML_ParserFree (p);
2503 if (parser_info)
2504 delete parser_info;
2505 if (prepend)
2506 g_free (prepend);
2507 if (append)
2508 g_free (append);
2510 return res;
2513 Value *
2514 XamlLoader::CreateFromFileWithError (const char *xaml_file, bool create_namescope, Type::Kind *element_type, MoonError *error)
2516 Value *res = CreateFromFile (xaml_file, create_namescope, element_type);
2517 if (error_args && error_args->GetErrorCode () != -1)
2518 MoonError::FillIn (error, error_args);
2519 return res;
2522 Value *
2523 XamlLoader::CreateFromStringWithError (const char *xaml, bool create_namescope, Type::Kind *element_type, int flags, MoonError *error)
2525 Value *res = CreateFromString (xaml, create_namescope, element_type, flags);
2526 if (error_args && error_args->GetErrorCode () != -1)
2527 MoonError::FillIn (error, error_args);
2528 return res;
2531 Value *
2532 XamlLoader::HydrateFromStringWithError (const char *xaml, Value *object, bool create_namescope, Type::Kind *element_type, int flags, MoonError *error)
2534 Value *res = HydrateFromString (xaml, object, create_namescope, element_type, flags);
2535 if (error_args && error_args->GetErrorCode () != -1)
2536 MoonError::FillIn (error, error_args);
2537 return res;
2540 static int
2541 parse_int (const char **pp, const char *end)
2543 const char *p = *pp;
2544 #if 0
2545 if (optional && AtEnd)
2546 return 0;
2547 #endif
2549 int res = 0;
2550 int count = 0;
2552 while (p <= end && g_ascii_isdigit (*p)) {
2553 res = res * 10 + *p - '0';
2554 p++;
2555 count++;
2558 #if 0
2559 if (count == 0)
2560 formatError = true;
2561 #endif
2563 *pp = p;
2564 return res;
2567 static gint64
2568 parse_ticks (const char **pp, const char *end)
2570 gint64 mag = 1000000;
2571 gint64 res = 0;
2572 bool digitseen = false;
2574 const char *p = *pp;
2576 while (mag > 0 && p <= end && g_ascii_isdigit (*p)) {
2577 res = res + (*p - '0') * mag;
2578 p++;
2579 mag = mag / 10;
2580 digitseen = true;
2583 #if 0
2584 if (!digitseen)
2585 formatError = true;
2586 #endif
2588 *pp = p;
2589 return res;
2592 bool
2593 time_span_from_str (const char *str, TimeSpan *res)
2595 const char *end = str + strlen (str);
2596 const char *p;
2598 bool negative = false;
2599 int days;
2600 int hours;
2601 int minutes;
2602 int seconds;
2603 gint64 ticks;
2605 p = str;
2607 if (*p == '-') {
2608 p++;
2609 negative = true;
2612 days = parse_int (&p, end);
2614 if (*p == '.') {
2615 p++;
2616 hours = parse_int (&p, end);
2618 else {
2619 hours = days;
2620 days = 0;
2623 if (*p == ':') p++;
2624 minutes = parse_int (&p, end);
2625 if (*p == ':') p++;
2626 seconds = parse_int (&p, end);
2627 if (*p == '.') {
2628 p++;
2629 ticks = parse_ticks (&p, end);
2631 else {
2632 ticks = 0;
2635 gint64 t = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
2636 t *= 10000000L;
2638 *res = negative ? (-t - ticks) : (t + ticks);
2640 return true;
2643 bool
2644 repeat_behavior_from_str (const char *str, RepeatBehavior *res)
2646 if (!g_ascii_strcasecmp ("Forever", str)) {
2647 *res = RepeatBehavior::Forever;
2648 return true;
2651 // check for "<float>x".
2653 // XXX more validation work is needed here.. but how do we
2654 // report an error?
2655 const char *x = strchr (str, 'x');
2656 if (x) {
2657 if (*(x + 1) != '\0') {
2658 return false;
2660 else {
2661 char *endptr;
2662 errno = 0;
2663 double d = g_ascii_strtod (str, &endptr);
2665 if (errno || endptr == str)
2666 return false;
2668 *res = RepeatBehavior (d);
2669 return true;
2673 /* XXX RepeatBehavior='XX:XX:XX' syntax is NOT correctly supported by
2674 Silverlight 1.0 (most likely a bug). It works fine in Silverlight 2.0
2675 though. We currently stick to the 2.0 behavior, not replicating the bug
2676 from 1.0.
2678 TimeSpan t;
2679 if (!time_span_from_str (str, &t))
2680 return false;
2682 *res = RepeatBehavior (t);
2684 return true;
2687 bool
2688 duration_from_str (const char *str, Duration *res)
2690 if (!g_ascii_strcasecmp ("Automatic", str)) {
2691 *res = Duration::Automatic;
2692 return true;
2695 if (!g_ascii_strcasecmp ("Forever", str)) {
2696 *res = Duration::Forever;
2697 return true;
2700 TimeSpan ts;
2701 if (!time_span_from_str (str, &ts))
2702 return false;
2704 *res = Duration (ts);
2705 return true;
2708 bool
2709 keytime_from_str (const char *str, KeyTime *res)
2711 if (!g_ascii_strcasecmp ("Uniform", str)) {
2712 *res = KeyTime::Uniform;
2713 return true;
2716 if (!g_ascii_strcasecmp ("Paced", str)) {
2717 *res = KeyTime::Paced;
2718 return true;
2721 /* check for a percentage first */
2722 const char *last = str + strlen(str) - 1;
2723 if (*last == '%') {
2724 char *ep;
2725 double pct = g_ascii_strtod (str, &ep);
2726 if (ep == last) {
2727 *res = KeyTime (pct);
2728 return true;
2732 TimeSpan ts;
2733 if (!time_span_from_str (str, &ts))
2734 return false;
2736 *res = KeyTime (ts);
2737 return true;
2740 bool
2741 key_spline_from_str (const char *str, KeySpline **res)
2743 PointCollection *pts = PointCollection::FromStr (str);
2745 if (!pts)
2746 return false;
2748 if (pts->GetCount () != 2) {
2749 pts->unref ();
2750 return false;
2753 *res = new KeySpline (*pts->GetValueAt (0)->AsPoint (), *pts->GetValueAt (1)->AsPoint ());
2755 pts->unref ();
2757 return true;
2760 Matrix *
2761 matrix_from_str (const char *str)
2763 if (!g_ascii_strcasecmp ("Identity", str)) {
2764 return new Matrix ();
2767 DoubleCollection *values = DoubleCollection::FromStr (str);
2768 Matrix *matrix;
2770 if (!values)
2771 return new Matrix ();
2773 if (values->GetCount () < 6) {
2774 values->unref ();
2775 return NULL;
2778 matrix = new Matrix ();
2779 matrix->SetM11 (values->GetValueAt (0)->AsDouble ());
2780 matrix->SetM12 (values->GetValueAt (1)->AsDouble ());
2781 matrix->SetM21 (values->GetValueAt (2)->AsDouble ());
2782 matrix->SetM22 (values->GetValueAt (3)->AsDouble ());
2783 matrix->SetOffsetX (values->GetValueAt (4)->AsDouble ());
2784 matrix->SetOffsetY (values->GetValueAt (5)->AsDouble ());
2786 values->unref ();
2788 return matrix;
2791 Matrix3D *
2792 matrix3d_from_str (const char *str)
2794 if (!g_ascii_strcasecmp ("Identity", str)) {
2795 return new Matrix3D ();
2798 DoubleCollection *values = DoubleCollection::FromStr (str);
2799 Matrix3D *matrix;
2801 if (!values)
2802 return new Matrix3D ();
2804 if (values->GetCount () < 12) {
2805 values->unref ();
2806 return NULL;
2809 matrix = new Matrix3D ();
2810 matrix->SetM11 (values->GetValueAt (0)->AsDouble ());
2811 matrix->SetM12 (values->GetValueAt (1)->AsDouble ());
2812 matrix->SetM13 (values->GetValueAt (2)->AsDouble ());
2813 matrix->SetM13 (values->GetValueAt (3)->AsDouble ());
2814 matrix->SetM21 (values->GetValueAt (4)->AsDouble ());
2815 matrix->SetM22 (values->GetValueAt (5)->AsDouble ());
2816 matrix->SetM23 (values->GetValueAt (6)->AsDouble ());
2817 matrix->SetM24 (values->GetValueAt (7)->AsDouble ());
2818 matrix->SetM31 (values->GetValueAt (8)->AsDouble ());
2819 matrix->SetM32 (values->GetValueAt (9)->AsDouble ());
2820 matrix->SetM33 (values->GetValueAt (10)->AsDouble ());
2821 matrix->SetM34 (values->GetValueAt (11)->AsDouble ());
2822 matrix->SetOffsetX (values->GetValueAt (12)->AsDouble ());
2823 matrix->SetOffsetY (values->GetValueAt (13)->AsDouble ());
2824 matrix->SetOffsetZ (values->GetValueAt (14)->AsDouble ());
2825 matrix->SetM44 (values->GetValueAt (15)->AsDouble ());
2827 values->unref ();
2829 return matrix;
2832 bool
2833 grid_length_from_str (const char *str, GridLength *grid_length)
2835 if (IS_NULL_OR_EMPTY (str)) {
2836 *grid_length = GridLength (0.0, GridUnitTypePixel);
2837 return true;
2840 if (str [0] == '*') {
2841 *grid_length = GridLength (1.0, GridUnitTypeStar);
2842 return true;
2845 // unit tests shows that "Auto", "auto", "aUtO"... all works
2846 if (!g_ascii_strcasecmp (str, "Auto")) {
2847 *grid_length = GridLength ();
2848 return true;
2851 char *endptr;
2852 errno = 0;
2853 double d = g_ascii_strtod (str, &endptr);
2855 if (errno || endptr == str)
2856 return false;
2858 *grid_length = GridLength (d, *endptr == '*' ? GridUnitTypeStar : GridUnitTypePixel);
2859 return true;
2862 static void
2863 advance (char **in)
2865 char *inptr = *in;
2867 while (*inptr && !g_ascii_isalnum (*inptr) && *inptr != '.' && *inptr != '-' && *inptr != '+')
2868 inptr = g_utf8_next_char (inptr);
2870 *in = inptr;
2873 static bool
2874 get_point (Point *p, char **in)
2876 char *end, *inptr = *in;
2877 double x, y;
2879 x = g_ascii_strtod (inptr, &end);
2880 if (end == inptr)
2881 return false;
2883 inptr = end;
2884 while (g_ascii_isspace (*inptr))
2885 inptr++;
2887 if (*inptr == ',')
2888 inptr++;
2890 while (g_ascii_isspace (*inptr))
2891 inptr++;
2893 y = g_ascii_strtod (inptr, &end);
2894 if (end == inptr)
2895 return false;
2897 p->x = x;
2898 p->y = y;
2900 *in = end;
2902 return true;
2905 static void
2906 make_relative (const Point *cp, Point *mv)
2908 mv->x += cp->x;
2909 mv->y += cp->y;
2912 static bool
2913 more_points_available (char **in)
2915 char *inptr = *in;
2917 while (g_ascii_isspace (*inptr) || *inptr == ',')
2918 inptr++;
2920 *in = inptr;
2922 return (g_ascii_isdigit (*inptr) || *inptr == '.' || *inptr == '-' || *inptr == '+');
2925 Geometry *
2926 geometry_from_str (const char *str)
2928 char *inptr = (char *) str;
2929 Point cp = Point (0, 0);
2930 Point cp1, cp2, cp3;
2931 Point start;
2932 char *end;
2933 PathGeometry *pg = NULL;
2934 FillRule fill_rule = FillRuleEvenOdd;
2935 bool cbz = false; // last figure is a cubic bezier curve
2936 bool qbz = false; // last figure is a quadratic bezier curve
2937 Point cbzp, qbzp; // points needed to create "smooth" beziers
2939 moon_path *path = moon_path_new (10);
2941 while (*inptr) {
2942 if (g_ascii_isspace (*inptr))
2943 inptr++;
2945 if (!inptr[0])
2946 break;
2948 bool relative = false;
2950 char c = *inptr;
2951 inptr = g_utf8_next_char (inptr);
2953 switch (c) {
2954 case 'f':
2955 case 'F':
2956 advance (&inptr);
2958 if (*inptr == '0')
2959 fill_rule = FillRuleEvenOdd;
2960 else if (*inptr == '1')
2961 fill_rule = FillRuleNonzero;
2962 else
2963 // FIXME: else it's a bad value and nothing should be rendered
2964 goto bad_pml; // partial: only this Path won't be rendered
2966 inptr = g_utf8_next_char (inptr);
2967 break;
2968 case 'm':
2969 relative = true;
2970 case 'M':
2971 if (!get_point (&cp1, &inptr))
2972 break;
2974 if (relative)
2975 make_relative (&cp, &cp1);
2977 // start point
2978 moon_move_to (path, cp1.x, cp1.y);
2980 start.x = cp.x = cp1.x;
2981 start.y = cp.y = cp1.y;
2983 advance (&inptr);
2984 while (more_points_available (&inptr)) {
2985 if (!get_point (&cp1, &inptr))
2986 break;
2988 if (relative)
2989 make_relative (&cp, &cp1);
2991 moon_line_to (path, cp1.x, cp1.y);
2994 cp.x = cp1.x;
2995 cp.y = cp1.y;
2996 cbz = qbz = false;
2997 break;
2999 case 'l':
3000 relative = true;
3001 case 'L':
3003 while (more_points_available (&inptr)) {
3004 if (!get_point (&cp1, &inptr))
3005 break;
3007 if (relative)
3008 make_relative (&cp, &cp1);
3010 moon_line_to (path, cp1.x, cp1.y);
3012 cp.x = cp1.x;
3013 cp.y = cp1.y;
3015 advance (&inptr);
3017 cbz = qbz = false;
3018 break;
3021 case 'h':
3022 relative = true;
3023 case 'H':
3025 double x = g_ascii_strtod (inptr, &end);
3026 if (end == inptr)
3027 break;
3029 inptr = end;
3031 if (relative)
3032 x += cp.x;
3033 cp = Point (x, cp.y);
3035 moon_line_to (path, cp.x, cp.y);
3036 cbz = qbz = false;
3037 break;
3040 case 'v':
3041 relative = true;
3042 case 'V':
3044 double y = g_ascii_strtod (inptr, &end);
3045 if (end == inptr)
3046 break;
3048 inptr = end;
3050 if (relative)
3051 y += cp.y;
3052 cp = Point (cp.x, y);
3054 moon_line_to (path, cp.x, cp.y);
3055 cbz = qbz = false;
3056 break;
3059 case 'c':
3060 relative = true;
3061 case 'C':
3063 while (more_points_available (&inptr)) {
3064 if (!get_point (&cp1, &inptr))
3065 break;
3067 if (relative)
3068 make_relative (&cp, &cp1);
3070 advance (&inptr);
3072 if (!get_point (&cp2, &inptr))
3073 break;
3075 if (relative)
3076 make_relative (&cp, &cp2);
3078 advance (&inptr);
3080 if (!get_point (&cp3, &inptr))
3081 break;
3083 if (relative)
3084 make_relative (&cp, &cp3);
3086 advance (&inptr);
3088 moon_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y, cp3.x, cp3.y);
3090 cp1.x = cp3.x;
3091 cp1.y = cp3.y;
3093 cp.x = cp3.x;
3094 cp.y = cp3.y;
3095 cbz = true;
3096 cbzp.x = cp2.x;
3097 cbzp.y = cp2.y;
3098 qbz = false;
3099 break;
3101 case 's':
3102 relative = true;
3103 case 'S':
3105 while (more_points_available (&inptr)) {
3106 if (!get_point (&cp2, &inptr))
3107 break;
3109 if (relative)
3110 make_relative (&cp, &cp2);
3112 advance (&inptr);
3114 if (!get_point (&cp3, &inptr))
3115 break;
3117 if (relative)
3118 make_relative (&cp, &cp3);
3120 if (cbz) {
3121 cp1.x = 2 * cp.x - cbzp.x;
3122 cp1.y = 2 * cp.y - cbzp.y;
3123 } else
3124 cp1 = cp;
3126 moon_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y, cp3.x, cp3.y);
3127 cbz = true;
3128 cbzp.x = cp2.x;
3129 cbzp.y = cp2.y;
3131 cp.x = cp3.x;
3132 cp.y = cp3.y;
3134 advance (&inptr);
3136 qbz = false;
3137 break;
3139 case 'q':
3140 relative = true;
3141 case 'Q':
3143 while (more_points_available (&inptr)) {
3144 if (!get_point (&cp1, &inptr))
3145 break;
3147 if (relative)
3148 make_relative (&cp, &cp1);
3150 advance (&inptr);
3152 if (!get_point (&cp2, &inptr))
3153 break;
3155 if (relative)
3156 make_relative (&cp, &cp2);
3158 advance (&inptr);
3160 moon_quad_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y);
3162 cp.x = cp2.x;
3163 cp.y = cp2.y;
3165 qbz = true;
3166 qbzp.x = cp1.x;
3167 qbzp.y = cp1.y;
3168 cbz = false;
3169 break;
3171 case 't':
3172 relative = true;
3173 case 'T':
3175 while (more_points_available (&inptr)) {
3176 if (!get_point (&cp2, &inptr))
3177 break;
3179 if (relative)
3180 make_relative (&cp, &cp2);
3182 if (qbz) {
3183 cp1.x = 2 * cp.x - qbzp.x;
3184 cp1.y = 2 * cp.y - qbzp.y;
3185 } else
3186 cp1 = cp;
3188 moon_quad_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y);
3189 qbz = true;
3190 qbzp.x = cp1.x;
3191 qbzp.y = cp1.y;
3193 cp.x = cp2.x;
3194 cp.y = cp2.y;
3196 advance (&inptr);
3198 cbz = false;
3199 break;
3201 case 'a':
3202 relative = true;
3203 case 'A':
3205 while (more_points_available (&inptr)) {
3206 if (!get_point (&cp1, &inptr))
3207 break;
3209 advance (&inptr);
3211 double angle = g_ascii_strtod (inptr, &end);
3212 if (end == inptr)
3213 break;
3215 inptr = end;
3216 advance (&inptr);
3218 int is_large = strtol (inptr, &end, 10);
3219 if (end == inptr)
3220 break;
3222 inptr = end;
3223 advance (&inptr);
3225 int sweep = strtol (inptr, &end, 10);
3226 if (end == inptr)
3227 break;
3229 inptr = end;
3230 advance (&inptr);
3232 if (!get_point (&cp2, &inptr))
3233 break;
3235 if (relative)
3236 make_relative (&cp, &cp2);
3238 moon_arc_to (path, cp1.x, cp1.y, angle, is_large, sweep, cp2.x, cp2.y);
3240 cp.x = cp2.x;
3241 cp.y = cp2.y;
3243 advance (&inptr);
3245 cbz = qbz = false;
3246 break;
3248 case 'z':
3249 case 'Z':
3250 moon_line_to (path, start.x, start.y);
3251 moon_close_path (path);
3252 moon_move_to (path, start.x, start.y);
3254 cp.x = start.x;
3255 cp.y = start.y;
3256 cbz = qbz = false;
3257 break;
3258 default:
3259 break;
3263 pg = new PathGeometry (path);
3264 pg->SetFillRule (fill_rule);
3265 return pg;
3267 bad_pml:
3268 moon_path_destroy (path);
3269 return NULL;
3272 static bool
3273 value_is_explicit_null (const char *str)
3275 return !strcmp ("{x:Null}", str);
3278 static bool
3279 is_managed_kind (Type::Kind kind)
3282 if (kind == Type::MANAGED ||
3283 kind == Type::OBJECT ||
3284 kind == Type::URI ||
3285 kind == Type::MANAGEDTYPEINFO ||
3286 kind == Type::DEPENDENCYPROPERTY)
3287 return true;
3289 return false;
3292 static bool
3293 kind_requires_managed_load (Type::Kind kind)
3295 if (kind == Type::USERCONTROL) {
3296 return true;
3299 return false;
3302 static bool
3303 is_legal_top_level_kind (Type::Kind kind)
3305 if (kind == Type::MANAGED || kind == Type::OBJECT || Type::IsSubclassOf (Deployment::GetCurrent (), kind, Type::DEPENDENCY_OBJECT))
3306 return true;
3307 return false;
3310 // NOTE: Keep definition in sync with class/System.Windows/Mono/NativeMethods.cs
3311 bool
3312 value_from_str_with_typename (const char *type_name, const char *prop_name, const char *str, Value **v)
3314 Type *t = Type::Find (Deployment::GetCurrent (), type_name);
3315 if (!t)
3316 return false;
3318 return value_from_str (t->GetKind (), prop_name, str, v);
3321 char *
3322 expand_property_path (XamlParserInfo *p, PropertyPath *path)
3324 if (!path->path)
3325 return NULL;
3327 bool expanded = false;
3328 GString *res = g_string_new (path->path);
3330 int len = strlen (res->str);
3331 for (int i = 0; i < len; i++) {
3332 if (res->str [i] == ':') {
3333 int e = i;
3334 int s = i - 1;
3335 int te = i + 1;
3336 for ( ; s > 0; s--) {
3337 if (!g_ascii_isalnum (res->str [s]))
3338 break;
3341 for ( ; te < len; te++) {
3342 if (!g_ascii_isalpha (res->str [te]) || res->str [te] == '_')
3343 break;
3346 char *prefix = g_strndup (res->str + s + 1, e - s - 1);
3347 char *type = g_strndup (res->str + e + 1, te - e - 1);
3349 res = g_string_erase (res, s + 1, te - s - 1);
3351 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
3352 if (!ns) {
3353 g_free (prefix);
3354 g_free (type);
3355 g_string_free (res, true);
3356 return NULL;
3359 XamlElementInfo *info = ns->FindElement (p, type, NULL, false);
3361 if (!info) {
3362 g_free (prefix);
3363 g_free (type);
3364 g_string_free (res, true);
3365 return NULL;
3368 char *uri = g_strdup_printf ("'%s'", Type::Find (p->deployment, info->GetKind ())->GetName ());
3370 res = g_string_insert (res, s + 1, uri);
3371 i = s + 1 + strlen (uri);
3372 len = strlen (res->str);
3374 delete info;
3375 g_free (uri);
3376 g_free (prefix);
3377 g_free (type);
3379 expanded = true;
3383 if (!expanded) {
3384 g_string_free (res, true);
3385 return NULL;
3388 char *expanded_str = res->str;
3389 g_string_free (res, false);
3391 return expanded_str;
3394 bool
3395 value_from_str (Type::Kind type, const char *prop_name, const char *str, Value **v)
3397 bool v_set = false;
3399 value_from_str_with_parser (NULL, type, prop_name, str, v, &v_set);
3401 return v_set;
3404 bool
3405 xaml_bool_from_str (const char *s, bool *res)
3407 bool b;
3408 char *endptr;
3410 if (!g_ascii_strcasecmp ("true", s))
3411 b = true;
3412 else if (!g_ascii_strcasecmp ("false", s))
3413 b = false;
3414 else {
3415 // Check if it's a string representing a decimal value
3416 gint64 l;
3418 errno = 0;
3419 l = strtol (s, &endptr, 10);
3421 if (errno || endptr == s || *endptr || l > G_MAXINT32 || l < G_MININT32)
3422 return false;;
3424 if (l == 0)
3425 b = false;
3426 else
3427 b = true;
3430 *res = b;
3431 return true;
3434 static bool
3435 value_from_str_with_parser (XamlParserInfo *p, Type::Kind type, const char *prop_name, const char *str, Value **v, bool *v_set)
3437 char *endptr;
3438 *v = NULL;
3440 if (value_is_explicit_null (str)) {
3441 *v = NULL;
3442 *v_set = true;
3443 return true;
3446 char *s = g_strdup (str);
3448 if (type == Type::OBJECT || type == Type::STRING) {
3449 // object and string use the literal string
3451 else {
3452 // everything else depends on the string being stripped
3453 s = g_strstrip (s);
3456 switch (type) {
3457 case Type::OBJECT: {
3458 // not much more can do here, unless we want to try to
3459 // probe str to see if it's actually meant to be a
3460 // specific type. just assume it's a string.
3461 *v = new Value (s);
3462 *v_set = true;
3463 break;
3466 case Type::BOOL: {
3467 bool b;
3469 if (!xaml_bool_from_str (s, &b))
3470 break;
3472 *v = new Value (b);
3473 *v_set = true;
3474 break;
3476 case Type::DOUBLE: {
3477 double d;
3479 // empty string should not reset default values with 0
3481 // FIXME: this causes a 2.0 unit test to fail (PrimitiveTest.ParseEmptyDouble)
3482 if (IS_NULL_OR_EMPTY(s)) {
3483 g_free (s);
3484 return false;
3487 bool is_nan = false;
3488 if (!g_ascii_strcasecmp (s, "NAN"))
3489 is_nan = true;
3490 else {
3491 errno = 0;
3492 d = g_ascii_strtod (s, &endptr);
3495 if (is_nan || errno || endptr == s || *endptr) {
3496 if (prop_name
3497 && (!strcmp (prop_name, "Width") || !strcmp (prop_name, "Height"))
3498 && (!g_ascii_strcasecmp (s, "Auto") || is_nan))
3499 d = NAN;
3500 else
3501 break;
3504 *v = new Value (d);
3505 *v_set = true;
3506 break;
3508 case Type::INT64: {
3509 gint64 l;
3511 errno = 0;
3512 l = strtol (s, &endptr, 10);
3514 if (errno || endptr == s)
3515 break;
3517 *v = new Value (l, Type::INT64);
3518 *v_set = true;
3519 break;
3521 case Type::TIMESPAN: {
3522 TimeSpan ts;
3524 if (!time_span_from_str (s, &ts))
3525 break;
3527 *v = new Value (ts, Type::TIMESPAN);
3528 *v_set = true;
3529 break;
3531 case Type::INT32: {
3532 int i;
3534 if (IS_NULL_OR_EMPTY(s))
3535 i = 0;
3536 else if (g_ascii_isalpha (s[0]) && prop_name) {
3537 i = enums_str_to_int (prop_name, s);
3538 if (i == -1) {
3539 // g_warning ("'%s' enum is not valid on '%s' property", str, prop_name);
3540 break;
3542 } else {
3543 errno = 0;
3544 long l = strtol (s, &endptr, 10);
3546 if (errno || endptr == s)
3547 break;
3549 i = (int) l;
3552 *v = new Value (i);
3553 *v_set = true;
3554 break;
3556 case Type::CHAR: {
3557 gunichar unichar = g_utf8_get_char_validated (str, -1);
3558 const char *next;
3560 if ((int) unichar < 0)
3561 break;
3563 if (!(next = g_utf8_next_char (str)) || *next != '\0')
3564 break;
3566 *v = new Value (unichar, Type::CHAR);
3567 *v_set = true;
3568 break;
3570 case Type::STRING: {
3571 *v = new Value (str);
3572 *v_set = true;
3573 break;
3575 case Type::COLOR: {
3576 Color *c = color_from_str (s);
3577 if (c == NULL)
3578 break;
3579 *v = new Value (*c);
3580 *v_set = true;
3581 delete c;
3582 break;
3584 case Type::REPEATBEHAVIOR: {
3585 RepeatBehavior rb = RepeatBehavior::Forever;
3587 if (!repeat_behavior_from_str (s, &rb))
3588 break;
3590 *v = new Value (rb);
3591 *v_set = true;
3592 break;
3594 case Type::DURATION: {
3595 Duration d = Duration::Forever;
3597 if (!duration_from_str (s, &d))
3598 break;
3600 *v = new Value (d);
3601 *v_set = true;
3602 break;
3604 case Type::KEYTIME: {
3605 KeyTime kt = KeyTime::Paced;
3607 if (!keytime_from_str (s, &kt))
3608 break;
3610 *v = new Value (kt);
3611 *v_set = true;
3612 break;
3614 case Type::KEYSPLINE: {
3615 KeySpline *ks;
3617 if (!key_spline_from_str (s, &ks))
3618 break;
3620 *v = Value::CreateUnrefPtr (ks);
3621 *v_set = true;
3622 break;
3624 case Type::BRUSH:
3625 case Type::SOLIDCOLORBRUSH: {
3626 // Only solid color brushes can be specified using attribute syntax
3627 Color *c = color_from_str (s);
3629 if (c == NULL)
3630 break;
3632 SolidColorBrush *scb = new SolidColorBrush ();
3634 scb->SetColor (c);
3635 delete c;
3637 *v = Value::CreateUnrefPtr (scb);
3638 *v_set = true;
3639 break;
3641 case Type::POINT: {
3642 Point p;
3644 if (!Point::FromStr (s, &p))
3645 break;
3647 *v = new Value (p);
3648 *v_set = true;
3649 break;
3651 case Type::SIZE: {
3652 Size size;
3654 if (!Size::FromStr (s, &size))
3655 break;
3657 *v = new Value (size);
3658 *v_set = true;
3659 break;
3661 case Type::RECT: {
3662 Rect rect;
3664 if (!Rect::FromStr (s, &rect))
3665 break;
3667 *v = new Value (rect);
3668 *v_set = true;
3669 break;
3671 case Type::URI: {
3672 Uri uri;
3674 if (!uri.Parse (s)) {
3675 break;
3678 *v = new Value (uri);
3679 *v_set = true;
3680 break;
3682 case Type::DOUBLE_COLLECTION: {
3683 DoubleCollection *doubles = DoubleCollection::FromStr (s);
3684 if (!doubles) {
3685 *v = Value::CreateUnrefPtr (new DoubleCollection ());
3686 *v_set = true;
3687 break;
3690 *v = Value::CreateUnrefPtr (doubles);
3691 *v_set = true;
3692 break;
3694 case Type::POINT_COLLECTION: {
3695 PointCollection *points = PointCollection::FromStr (s);
3696 if (!points) {
3697 *v = Value::CreateUnrefPtr (new PointCollection ());
3698 *v_set = true;
3699 break;
3702 *v = Value::CreateUnrefPtr (points);
3703 *v_set = true;
3704 break;
3706 case Type::TRANSFORMGROUP: {
3707 if (IS_NULL_OR_EMPTY(s))
3708 break;
3710 Matrix *mv = matrix_from_str (s);
3711 if (!mv)
3712 break;
3714 TransformGroup *tg = new TransformGroup ();
3715 MatrixTransform *t = new MatrixTransform ();
3716 t->SetValue (MatrixTransform::MatrixProperty, Value (mv));
3718 tg->GetChildren()->Add (t);
3719 t->unref ();
3721 *v = new Value (tg);
3722 *v_set = true;
3723 tg->unref ();
3724 mv->unref ();
3725 break;
3727 case Type::TRANSFORM:
3729 if (!g_ascii_strcasecmp ("Identity", str)) {
3730 *v = NULL;
3731 *v_set = true;
3732 break;
3735 // Intentional fall through, you can create a matrix from a TRANSFORM property, but not using Identity
3736 case Type::MATRIXTRANSFORM:
3738 if (IS_NULL_OR_EMPTY(s))
3739 break;
3741 Matrix *mv = matrix_from_str (s);
3742 if (!mv)
3743 break;
3745 MatrixTransform *t = new MatrixTransform ();
3746 t->SetValue (MatrixTransform::MatrixProperty, Value (mv));
3748 *v = new Value (t);
3749 *v_set = true;
3750 t->unref ();
3751 mv->unref ();
3752 break;
3754 case Type::UNMANAGEDMATRIX:
3755 case Type::MATRIX: {
3756 // note: unlike TRANSFORM this creates an empty, identity, matrix for an empty string
3757 Matrix *matrix = matrix_from_str (s);
3758 if (!matrix)
3759 break;
3761 *v = new Value (matrix);
3762 *v_set = true;
3763 matrix->unref ();
3764 break;
3766 case Type::PROJECTION:
3768 if (!g_ascii_strcasecmp ("Identity", str)) {
3769 *v = NULL;
3770 *v_set = true;
3771 break;
3774 // Intentional fall through, you can create a matrix from a PROJECTION property, but not using Identity
3775 case Type::MATRIX3DPROJECTION:
3777 if (IS_NULL_OR_EMPTY(s))
3778 break;
3780 Matrix3D *mv = matrix3d_from_str (s);
3781 if (!mv)
3782 break;
3784 Matrix3DProjection *p = new Matrix3DProjection ();
3785 p->SetValue (Matrix3DProjection::ProjectionMatrixProperty, Value (mv));
3787 *v = new Value (p);
3788 *v_set = true;
3789 p->unref ();
3790 mv->unref ();
3791 break;
3793 case Type::UNMANAGEDMATRIX3D:
3794 case Type::MATRIX3D: {
3795 Matrix3D *matrix = matrix3d_from_str (s);
3796 if (!matrix)
3797 break;
3799 *v = new Value (matrix);
3800 *v_set = true;
3801 matrix->unref ();
3802 break;
3804 case Type::PATHGEOMETRY:
3805 case Type::GEOMETRY: {
3806 Geometry *geometry = geometry_from_str (s);
3808 if (!geometry)
3809 break;
3811 *v = new Value (geometry);
3812 *v_set = true;
3813 geometry->unref ();
3814 break;
3816 case Type::THICKNESS: {
3817 Thickness t;
3819 if (!Thickness::FromStr (s, &t))
3820 break;
3822 *v = new Value (t);
3823 *v_set = true;
3824 break;
3826 case Type::CORNERRADIUS: {
3827 CornerRadius c;
3829 if (!CornerRadius::FromStr (s, &c))
3830 break;
3832 *v = new Value (c);
3833 *v_set = true;
3834 break;
3836 case Type::GRIDLENGTH: {
3837 GridLength grid_length;
3839 if (!grid_length_from_str (s, &grid_length))
3840 break;
3842 *v = new Value (grid_length);
3843 *v_set = true;
3844 break;
3846 case Type::IMAGESOURCE:
3847 case Type::BITMAPIMAGE: {
3848 Uri uri;
3850 if (!uri.Parse (s))
3851 break;
3853 BitmapImage *bi = new BitmapImage ();
3855 bi->SetUriSource (&uri);
3857 *v = Value::CreateUnrefPtr (bi);
3858 *v_set = true;
3860 break;
3862 case Type::MULTISCALETILESOURCE:
3863 case Type::DEEPZOOMIMAGETILESOURCE: {
3864 // As far as I know the only thing you can create here is a URI based DeepZoomImageTileSource
3865 Uri uri;
3866 if (!uri.Parse (s))
3867 break;
3868 *v = Value::CreateUnrefPtr (new DeepZoomImageTileSource (&uri));
3869 *v_set = true;
3871 break;
3873 case Type::FONTFAMILY: {
3874 *v = new Value (FontFamily (s));
3875 *v_set = true;
3876 break;
3878 case Type::FONTWEIGHT: {
3879 int fw = enums_str_to_int ("FontWeight", s);
3880 if (fw != -1) {
3881 *v = new Value (FontWeight ((FontWeights)fw));
3882 *v_set = true;
3884 break;
3886 case Type::FONTSTYLE: {
3887 int fs = enums_str_to_int ("FontStyle", s);
3888 if (fs != -1) {
3889 *v = new Value (FontStyle ((FontStyles)fs));
3890 *v_set = true;
3892 break;
3894 case Type::FONTSTRETCH: {
3895 int fs = enums_str_to_int ("FontStretch", s);
3896 if (fs != -1) {
3897 *v = new Value (FontStretch ((FontStretches)fs));
3898 *v_set = true;
3900 break;
3902 case Type::PROPERTYPATH: {
3903 PropertyPath path (s);
3904 path.expanded_path = expand_property_path (p, &path);
3905 *v = new Value (path);
3906 *v_set = true;
3907 break;
3909 default:
3910 // we don't care about NULL or empty values
3911 if (!IS_NULL_OR_EMPTY (s)) {
3912 g_free (s);
3913 return true;
3917 g_free (s);
3918 return true;
3921 bool
3922 XamlElementInstance::TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value)
3924 const char* prop_name = info->GetContentProperty (p);
3926 if (!prop_name)
3927 return false;
3929 DependencyProperty *dep = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, info->GetKind ()), prop_name);
3930 if (!dep)
3931 return false;
3933 bool is_collection = Type::IsSubclassOf (p->deployment, dep->GetPropertyType(), Type::DEPENDENCY_OBJECT_COLLECTION);
3935 if (!is_collection && Type::IsSubclassOf (p->deployment, value->info->GetKind (), dep->GetPropertyType())) {
3936 MoonError err;
3937 if (!item->SetValueWithError (dep, value->GetAsValue (), &err)) {
3938 parser_error (p, value->element_name, NULL, err.code, err.message);
3939 return false;
3941 return true;
3944 // We only want to enter this if statement if we are NOT dealing with the content property element,
3945 // otherwise, attempting to use explicit property setting, would add the content property element
3946 // to the content property element collection
3947 if (is_collection && dep->GetPropertyType() != value->info->GetKind ()) {
3948 Value *col_v = item->GetValue (dep);
3949 Collection *col;
3951 if (!col_v) {
3952 col = collection_new (dep->GetPropertyType ());
3953 item->SetValue (dep, Value (col));
3954 col->unref ();
3955 } else {
3956 col = (Collection *) col_v->AsCollection ();
3959 MoonError err;
3960 if (-1 == col->AddWithError (value->GetAsValue (), &err)) {
3961 parser_error (p, value->element_name, NULL, err.code, err.message);
3962 return false;
3965 return true;
3968 return false;
3971 bool
3972 XamlElementInstance::TrySetContentProperty (XamlParserInfo *p, const char *value)
3974 const char* prop_name = info->GetContentProperty (p);
3976 if (!prop_name) {
3977 if (info->GetKind () == Type::ICON) {
3978 printf ("getting the text content of the icon\n");
3979 prop_name = "Source";
3980 } else
3981 return false;
3984 Type::Kind prop_type = p->current_element->info->GetKind ();
3985 DependencyProperty *content = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, prop_type), prop_name);
3987 // TODO: There might be other types that can be specified here,
3988 // but string is all i have found so far. If you can specify other
3989 // types, i should pull the property setting out of set_attributes
3990 // and use that code
3992 if (content && (content->GetPropertyType ()) == Type::STRING && value) {
3993 item->SetValue (content, Value (g_strstrip (p->cdata->str)));
3994 return true;
3995 } else if (content && (content->GetPropertyType ()) == Type::URI && value) {
3996 Uri uri;
3998 if (!uri.Parse (g_strstrip (p->cdata->str)))
3999 return false;
4001 item->SetValue (content, Value (uri));
4002 return true;
4003 } else if (Type::IsSubclassOf (p->deployment, info->GetKind (), Type::TEXTBLOCK)) {
4004 TextBlock *textblock = (TextBlock *) item;
4005 InlineCollection *inlines = textblock->GetInlines ();
4006 Inline *last = NULL;
4008 if (inlines && inlines->GetCount () > 0)
4009 last = inlines->GetValueAt (inlines->GetCount () - 1)->AsInline ();
4011 if (!p->cdata_content) {
4012 if (p->next_element && !strcmp (p->next_element, "Run") && last && last->GetObjectType () == Type::RUN &&
4013 !last->GetAutogenerated ()) {
4014 // LWSP between <Run> elements is to be treated as a single-SPACE <Run> element
4015 // Note: p->cdata is already canonicalized
4016 } else {
4017 // This is one of the following cases:
4019 // 1. LWSP before the first <Run> element
4020 // 2. LWSP after the last <Run> element
4021 // 3. LWSP between <Run> and <LineBreak> elements
4022 return true;
4024 } else {
4025 if (!p->next_element || !strcmp (p->next_element, "LineBreak"))
4026 g_strchomp (p->cdata->str);
4028 if (!last || last->GetObjectType () != Type::RUN || last->GetAutogenerated ())
4029 g_strchug (p->cdata->str);
4032 Run *run = new Run ();
4033 run->SetText (p->cdata->str);
4035 if (!inlines) {
4036 inlines = new InlineCollection ();
4037 textblock->SetInlines (inlines);
4038 inlines->unref ();
4041 inlines->Add (run);
4042 run->unref ();
4043 return true;
4046 return false;
4049 bool
4050 XamlElementInstance::SetUnknownAttribute (XamlParserInfo *p, const char *name, const char *value)
4052 if (!p->loader)
4053 return false;
4055 Value v = Value (value);
4056 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, name, &v, NULL)) {
4057 return false;
4059 return true;
4062 void
4063 XamlElementInstance::SetDelayedProperties (XamlParserInfo *p)
4065 GSList *walk = delayed_properties;
4067 while (walk) {
4068 DelayedProperty *prop = (DelayedProperty *) walk->data;
4070 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), prop->xmlns, prop->name, prop->value, NULL, XamlCallbackData::SETTING_DELAYED_PROPERTY)) {
4071 parser_error (p, element_name, prop->name, 2012,
4072 "Unknown property %s on element %s.",
4073 prop->name, element_name);
4074 return;
4077 walk = walk->next;
4082 XamlElementInfo *
4083 XamlElementInstance::FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot)
4085 // We didn't find anything so try looking up in managed
4086 if (!p->loader)
4087 return NULL;
4089 Value *v = new Value ();
4090 if (p->loader->LookupObject (p, p->GetTopElementPtr (), GetAsValue (), p->current_namespace->GetUri (), el, false, true, v)) {
4091 char *type_name = g_strndup (el, dot - el);
4093 XamlElementInfoManaged *res = new XamlElementInfoManaged (g_strdup (p->current_namespace->GetUri ()), el, info, v->GetKind (), v);
4094 XamlElementInfo *container = p->current_namespace->FindElement (p, type_name, NULL, false);
4095 info->SetPropertyOwnerKind (container->GetKind ());
4096 g_free (type_name);
4097 return res;
4100 delete v;
4101 return NULL;
4104 static XamlElementInfo *
4105 create_element_info_from_imported_managed_type (XamlParserInfo *p, const char *name, const char **attr, bool create)
4107 if (!p->loader)
4108 return NULL;
4110 char* type_name = NULL;
4111 char* type_xmlns = NULL;
4112 const char* use_xmlns = NULL;
4114 if (x_namespace) {
4115 // We might have an x:Class attribute specified, so we need to use that for the
4116 // type_name that we pass to LookupObject
4117 if (strcmp ("Application", name)) {
4118 type_name = x_namespace->FindTypeName (attr, &type_xmlns);
4119 if (type_name) {
4120 name = type_name;
4121 use_xmlns = type_xmlns;
4123 if (!p->hydrating) {
4124 parser_error (p, name, "x:Class", 4005, "Cannot specify x:Class in xaml files outside of a xap.");
4125 return NULL;
4131 Value *v = new Value ();
4132 if (!p->loader->LookupObject (p, use_xmlns ? p->GetTopElementPtr () : NULL, NULL, use_xmlns, name, create, false, v)) {
4133 delete v;
4134 if (type_name)
4135 g_free (type_name);
4136 if (type_xmlns)
4137 g_free (type_xmlns);
4138 return NULL;
4141 XamlElementInfoImportedManaged *info = new XamlElementInfoImportedManaged (g_strdup (name), NULL, v);
4143 if (create) {
4144 if (v->Is (p->deployment, Type::DEPENDENCY_OBJECT))
4145 p->AddCreatedElement (v->AsDependencyObject());
4148 return info;
4152 const char *
4153 XamlElementInfoNative::GetContentProperty (XamlParserInfo *p)
4155 return type->GetContentPropertyName ();
4158 XamlElementInstance *
4159 XamlElementInfoNative::CreateElementInstance (XamlParserInfo *p)
4161 if (type->IsValueType ())
4162 return new XamlElementInstanceValueType (this, p, GetName (), XamlElementInstance::ELEMENT);
4163 else if (type->IsSubclassOf (Type::FRAMEWORKTEMPLATE))
4164 return new XamlElementInstanceTemplate (this, p, GetName (), XamlElementInstance::ELEMENT);
4165 else
4166 return new XamlElementInstanceNative (this, p, GetName (), XamlElementInstance::ELEMENT);
4169 XamlElementInstance *
4170 XamlElementInfoNative::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4172 XamlElementInstance *res = new XamlElementInstanceNative (this, p, GetName (), XamlElementInstance::ELEMENT, false);
4173 res->SetDependencyObject (o->AsDependencyObject ());
4175 return res;
4178 XamlElementInfo *
4179 XamlElementInstanceNative::FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot)
4181 if (IsDependencyObject ()) {
4182 const char *prop_name = dot + 1;
4183 DependencyProperty *prop = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, info->GetKind ()), prop_name);
4184 if (prop) {
4185 XamlElementInfoNative *info = new XamlElementInfoNative (Type::Find (p->deployment, prop->GetPropertyType ()));
4186 info->SetPropertyOwnerKind (prop->GetOwnerType ());
4187 return info;
4191 return XamlElementInstance::FindPropertyElement (p, el, dot);
4194 XamlElementInstance *
4195 XamlElementInfoNative::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4197 return new XamlElementInstanceNative (this, p, name, XamlElementInstance::PROPERTY, false);
4200 XamlElementInstanceNative::XamlElementInstanceNative (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item) :
4201 XamlElementInstance (element_info, name, type)
4203 this->element_info = element_info;
4204 this->parser_info = parser_info;
4205 if (create_item)
4206 SetDependencyObject (CreateItem ());
4211 DependencyObject *
4212 XamlElementInstanceNative::CreateItem ()
4214 XamlElementInstance *walk = parser_info->current_element;
4215 Type *type = element_info->GetType ();
4217 DependencyObject *item = NULL;
4218 DependencyProperty *dep = NULL;
4220 if (type->IsSubclassOf (Type::COLLECTION) || type->IsSubclassOf (Type::RESOURCE_DICTIONARY)) {
4221 // If we are creating a collection, try walking up the element tree,
4222 // to find the parent that we belong to and using that instance for
4223 // our collection, instead of creating a new one
4225 // We attempt to advance past the property setter, because we might be dealing with a
4226 // content element
4228 if (walk && walk->element_type == XamlElementInstance::PROPERTY) {
4229 char **prop_name = g_strsplit (walk->element_name, ".", -1);
4231 walk = walk->parent;
4232 dep = DependencyProperty::GetDependencyProperty (Type::Find (parser_info->deployment, walk->info->GetKind ()), prop_name [1]);
4234 g_strfreev (prop_name);
4235 } else if (walk && walk->info->GetContentProperty (parser_info)) {
4236 dep = DependencyProperty::GetDependencyProperty (Type::Find (parser_info->deployment, walk->info->GetKind ()),
4237 (char *) walk->info->GetContentProperty (parser_info));
4240 if (dep && Type::IsSubclassOf (parser_info->deployment, dep->GetPropertyType(), type->GetKind ())) {
4241 Value *v = ((DependencyObject * ) walk->GetAsDependencyObject ())->GetValue (dep);
4242 if (v) {
4243 item = v->AsDependencyObject ();
4244 dep = NULL;
4246 // note: if !v then the default collection is NULL (e.g. PathFigureCollection)
4250 if (!item) {
4251 item = element_info->GetType()->IsCtorVisible() ? element_info->GetType ()->CreateInstance () : NULL;
4253 if (item) {
4254 parser_info->AddCreatedElement (item);
4256 // in case we must store the collection into the parent
4257 if (dep && dep->GetPropertyType() == type->GetKind ()) {
4258 MoonError err;
4259 Value item_value (item);
4260 if (!((DependencyObject * ) walk->GetAsDependencyObject ())->SetValueWithError (dep, &item_value, &err))
4261 parser_error (parser_info, element_name, NULL, err.code, err.message);
4263 } else {
4264 parser_error (parser_info, element_name, NULL, 2007, "Unknown element: %s.", element_name);
4268 return item;
4271 bool
4272 XamlElementInstanceNative::SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value)
4274 if (property->info->RequiresManagedSet () || value->info->RequiresManagedSet ())
4275 return p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, value->GetAsValue (), NULL);
4277 return dependency_object_set_property (p, this, property, value, true);
4280 bool
4281 XamlElementInstanceNative::SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value)
4283 char **prop_name = g_strsplit (property->element_name, ".", -1);
4284 Type *owner = Type::Find (p->deployment, prop_name [0]);
4285 DependencyProperty *dep;
4287 if (!owner)
4288 return false;
4290 dep = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, owner->GetKind ()), prop_name [1]);
4291 if (!dep)
4292 return false;
4294 return xaml_set_property_from_str (item, dep, value, NULL/*XXX*/);
4297 void
4298 XamlElementInstanceNative::AddChild (XamlParserInfo *p, XamlElementInstance *child)
4300 dependency_object_add_child (p, this, child, true);
4303 void
4304 XamlElementInstanceNative::SetAttributes (XamlParserInfo *p, const char **attr)
4306 dependency_object_set_attributes (p, this, attr);
4310 XamlElementInstanceValueType::XamlElementInstanceValueType (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type) :
4311 XamlElementInstance (element_info, name, type)
4313 this->element_info = element_info;
4314 this->parser_info = parser_info;
4317 bool
4318 XamlElementInstanceValueType::CreateValueItemFromString (const char* str)
4321 bool res = value_from_str (element_info->GetType ()->GetKind (), NULL, str, &value);
4322 return res;
4325 void
4326 XamlElementInstanceValueType::SetAttributes (XamlParserInfo *p, const char **attr)
4328 value_type_set_attributes (p, this, attr);
4331 XamlElementInstanceEnum::XamlElementInstanceEnum (XamlElementInfoEnum *element_info, const char *name, ElementType type) :
4332 XamlElementInstance (element_info, name, type)
4336 bool
4337 XamlElementInstanceEnum::CreateEnumFromString (const char* str)
4339 int i = enums_str_to_int (element_name, str);
4340 if (i == -1)
4341 return false;
4343 value = new Value (i);
4344 return true;
4347 void
4348 XamlElementInstanceEnum::SetAttributes (XamlParserInfo *p, const char **attr)
4350 value_type_set_attributes (p, this, attr);
4353 XamlElementInstance *
4354 XamlElementInfoEnum::CreateElementInstance (XamlParserInfo *p)
4356 return new XamlElementInstanceEnum (this, name, XamlElementInstance::ELEMENT);
4359 XamlElementInstance *
4360 XamlElementInfoEnum::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4362 XamlElementInstance *res = new XamlElementInstanceEnum (this, name, XamlElementInstance::ELEMENT);
4363 return res;
4366 const char *
4367 XamlElementInfoManaged::GetContentProperty (XamlParserInfo *p)
4369 if (!p->loader)
4370 return NULL;
4372 // TODO: We could cache this, but for now lets keep things as simple as possible.
4373 const char *res = p->loader->GetContentPropertyName (p, p->GetTopElementPtr (), obj);
4374 if (res)
4375 return res;
4376 return XamlElementInfo::GetContentProperty (p);
4379 XamlElementInstance *
4380 XamlElementInfoManaged::CreateElementInstance (XamlParserInfo *p)
4382 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, GetName (), XamlElementInstance::ELEMENT, obj);
4384 if (obj->Is (p->deployment, Type::DEPENDENCY_OBJECT))
4385 p->AddCreatedElement (inst->GetAsDependencyObject ());
4387 return inst;
4390 XamlElementInstance *
4391 XamlElementInfoManaged::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4393 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, GetName (), XamlElementInstance::ELEMENT, o);
4395 return inst;
4398 XamlElementInstance *
4399 XamlElementInfoManaged::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4401 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::PROPERTY, obj);
4403 return inst;
4406 XamlElementInstanceManaged::XamlElementInstanceManaged (XamlElementInfo *info, const char *name, ElementType type, Value *obj) :
4407 XamlElementInstance (info, name, type)
4409 // The managed code owns our Value objects
4410 cleanup_value = false;
4412 this->value = obj;
4414 if (obj->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT)) {
4415 this->is_dependency_object = true;
4416 this->SetDependencyObject (obj->AsDependencyObject ());
4418 else
4419 this->is_dependency_object = false;
4422 void *
4423 XamlElementInstanceManaged::GetManagedPointer ()
4425 if (value->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT))
4426 return value->AsDependencyObject ();
4427 return value->AsManagedObject ();
4430 Value *
4431 XamlElementInstanceManaged::GetParentPointer ()
4433 XamlElementInstance *walk = parent;
4434 while (walk && walk->element_type != XamlElementInstance::ELEMENT)
4435 walk = walk->parent;
4437 if (!walk) {
4438 return NULL;
4441 return walk->GetAsValue ();
4444 bool
4445 XamlElementInstanceManaged::SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value)
4447 if (GetAsDependencyObject () != NULL && dependency_object_set_property (p, this, property, value, false))
4448 return true;
4449 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, value->GetAsValue (), value);
4452 bool
4453 XamlElementInstanceManaged::SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value)
4455 Value v = Value (value);
4456 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, &v, NULL);
4459 void
4460 XamlElementInstanceManaged::AddChild (XamlParserInfo *p, XamlElementInstance *child)
4462 if (element_type == XamlElementInstance::PROPERTY) {
4463 Value *prop = new Value (element_name);
4464 p->loader->AddChild (p, p->GetTopElementPtr (), GetParentPointer (), true, info->xmlns, prop, this, child->GetAsValue (), child);
4465 delete prop;
4466 return;
4469 p->loader->AddChild (p, p->GetTopElementPtr (), GetParentPointer (), false, info->xmlns, GetAsValue (), this, child->GetAsValue (), child);
4472 void
4473 XamlElementInstanceManaged::SetAttributes (XamlParserInfo *p, const char **attr)
4475 dependency_object_set_attributes (p, this, attr);
4478 bool
4479 XamlElementInstanceManaged::TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value)
4481 Value *v = value->GetAsValue ();
4482 const char* prop_name = info->GetContentProperty (p);
4484 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, prop_name, v, value);
4487 bool
4488 XamlElementInstanceManaged::TrySetContentProperty (XamlParserInfo *p, const char *value)
4490 if (Type::IsSubclassOf (p->deployment, info->GetKind (), Type::CONTENTCONTROL)) {
4491 // Content controls are not allowed to have their content set as text, they need to have a child element
4492 // if you want to set the content of a contentcontrol to text you need to use attribute syntax
4493 return false;
4496 if (!XamlElementInstance::TrySetContentProperty (p, value)) {
4497 const char* prop_name = info->GetContentProperty (p);
4498 if (!p->cdata_content)
4499 return false;
4500 Value v = Value (value);
4501 bool res = p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, prop_name, &v, NULL);
4502 return res;
4505 return false;
4508 XamlElementInstance *
4509 XamlElementInfoImportedManaged::CreateElementInstance (XamlParserInfo *p)
4511 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::ELEMENT, obj);
4513 return inst;
4516 const char *
4517 XamlElementInfoImportedManaged::GetContentProperty (XamlParserInfo *p)
4519 if (!p->loader)
4520 return NULL;
4522 // TODO: Test, it's possible that managed objects that aren't DOs are allowed to have content properties.
4523 if (!obj->Is (p->deployment, Type::DEPENDENCY_OBJECT))
4524 return XamlElementInfo::GetContentProperty (p);
4527 // TODO: We could cache this, but for now lets keep things as simple as possible.
4528 const char *res = p->loader->GetContentPropertyName (p, p->GetTopElementPtr (), obj);
4529 if (res)
4530 return res;
4532 return XamlElementInfo::GetContentProperty (p);
4535 XamlElementInstance *
4536 XamlElementInfoImportedManaged::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4538 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, Type::Find (p->deployment, o->GetKind ())->GetName (), XamlElementInstance::ELEMENT, o);
4540 return inst;
4543 XamlElementInstance *
4544 XamlElementInfoImportedManaged::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4546 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::PROPERTY, obj);
4548 return inst;
4553 /// Add Child funcs
4556 static const char*
4557 get_key_from_child (XamlElementInstance *child)
4559 const char *key = child->GetKey ();
4560 if (key)
4561 return key;
4563 key = child->GetName ();
4564 if (key)
4565 return key;
4567 if (child->IsDependencyObject ()) {
4568 DependencyObject *c = child->GetAsDependencyObject();
4570 if (Type::IsSubclassOf (c->GetDeployment (), Type::STYLE, child->info->GetKind ())) {
4571 Value *v = c->GetValue (Style::TargetTypeProperty);
4572 if (v && v->GetKind () == Type::MANAGEDTYPEINFO)
4573 key = v->AsManagedTypeInfo ()->full_name;
4575 if (key)
4576 return key;
4580 return NULL;
4583 static void
4584 dependency_object_add_child (XamlParserInfo *p, XamlElementInstance *parent, XamlElementInstance *child, bool fail_if_no_prop)
4586 Types *types = Deployment::GetCurrent ()->GetTypes ();
4587 if (parent->element_type == XamlElementInstance::PROPERTY) {
4589 if (parent->info->RequiresManagedSet ())
4590 return;
4592 char **prop_name = g_strsplit (parent->element_name, ".", -1);
4593 Type *owner = types->Find (prop_name [0]);
4595 if (owner) {
4596 DependencyProperty *dep = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, owner->GetKind ()), prop_name [1]);
4598 g_strfreev (prop_name);
4600 if (!dep) {
4601 g_warning ("Unknown element: %s.", parent->element_name);
4602 if (fail_if_no_prop)
4603 parser_error (p, parent->element_name, NULL, 2007, "Unknown element: %s.", parent->element_name);
4604 return;
4607 // XamlElementInfoEnum has Type::INVALID as
4608 // its kind, which is why that first check is
4609 // here.
4610 if (child->info->GetKind() != Type::MANAGED &&
4611 !types->Find (child->info->GetKind())->IsCtorVisible()) {
4612 // we can't instantiate this type
4613 return parser_error (p, child->element_name, NULL, 2007,
4614 "Unknown element: %s.", child->element_name);
4617 // Don't add the child element, if it is the entire collection
4618 if (dep->GetPropertyType() == child->info->GetKind ())
4619 return;
4621 Type::Kind prop_type = dep->GetPropertyType ();
4622 if (!types->IsSubclassOf (prop_type, Type::DEPENDENCY_OBJECT_COLLECTION)
4623 && !types->IsSubclassOf (prop_type, Type::RESOURCE_DICTIONARY))
4624 return;
4626 // Most common case, we will have a parent that we can snag the collection from
4627 DependencyObject *obj = (DependencyObject *) parent->parent->GetAsDependencyObject ();
4628 if (!obj)
4629 return;
4631 Value *col_v = obj->GetValue (dep);
4632 if (!col_v) {
4633 Type *col_type = types->Find (prop_type);
4634 DependencyObject *c_obj = col_type->CreateInstance ();
4635 obj->SetValue (dep, Value::CreateUnrefPtr (c_obj));
4636 col_v = obj->GetValue (dep);
4637 c_obj->unref ();
4639 Collection *col = col_v->AsCollection ();
4640 MoonError err;
4642 if (types->IsSubclassOf (prop_type, Type::DEPENDENCY_OBJECT_COLLECTION)) {
4643 Value child_val (child->GetAsDependencyObject ());
4644 if (-1 == col->AddWithError (&child_val, &err))
4645 return parser_error (p, child->element_name, NULL, err.code, err.message);
4647 else if (types->IsSubclassOf (prop_type, Type::RESOURCE_DICTIONARY)) {
4648 ResourceDictionary *dict = (ResourceDictionary *)col;
4650 const char *key = get_key_from_child (child);
4652 if (key == NULL) {
4653 // XXX don't know the proper values here...
4654 return parser_error (p, child->element_name, NULL, 2007,
4655 "You must specify an x:Key or x:Name for elements in a ResourceDictionary");
4658 Value *child_as_value = child->GetAsValue ();
4660 if (!child_as_value) {
4661 // XXX don't know the proper values here...
4662 return parser_error (p, child->element_name, NULL, 2007,
4663 "Error adding child to ResourceDictionary");
4666 bool added = dict->AddWithError (key, child_as_value, &err);
4667 if (!added)
4668 return parser_error (p, child->element_name, NULL, err.code, err.message);
4671 return;
4674 return;
4677 if (types->IsSubclassOf (parent->info->GetKind (), Type::DEPENDENCY_OBJECT_COLLECTION)) {
4678 Collection *col = (Collection *) parent->GetAsDependencyObject ();
4679 MoonError err;
4680 Value child_val ((DependencyObject*)child->GetAsDependencyObject ());
4682 if (-1 == col->AddWithError (&child_val, &err))
4683 return parser_error (p, child->element_name, NULL, err.code, err.message);
4684 return;
4686 else if (types->IsSubclassOf (parent->info->GetKind (), Type::RESOURCE_DICTIONARY)) {
4687 ResourceDictionary *dict = (ResourceDictionary *) parent->GetAsDependencyObject ();
4689 MoonError err;
4690 const char *key = get_key_from_child (child);
4692 if (key == NULL) {
4693 // XXX don't know the proper values here...
4694 return parser_error (p, child->element_name, NULL, 2007,
4695 "You must specify an x:Key or x:Name for elements in a ResourceDictionary");
4698 Value *child_as_value = child->GetAsValue ();
4699 bool added = dict->AddWithError (key, child_as_value, &err);
4700 if (!added)
4701 return parser_error (p, child->element_name, NULL, err.code, err.message);
4705 if (parent->element_type != XamlElementInstance::PROPERTY) {
4706 parent->TrySetContentProperty (p, child);
4709 // Do nothing if we aren't adding to a collection, or a content property collection
4714 /// set property funcs
4717 // these are just a bunch of special cases
4718 static void
4719 dependency_object_missed_property (XamlElementInstance *item, XamlElementInstance *prop, XamlElementInstance *value, char **prop_name)
4724 static bool
4725 set_managed_attached_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *prop, XamlElementInstance *value)
4727 if (!p->loader)
4728 return false;
4730 return p->loader->SetProperty (p, p->GetTopElementPtr (), item->info->xmlns, item->GetAsValue (), item, item->GetParentPointer (), prop->info->xmlns, prop->element_name, value->GetAsValue (), value);
4733 static bool
4734 dependency_object_set_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *property, XamlElementInstance *value, bool raise_errors)
4736 char **prop_name = g_strsplit (property->element_name, ".", -1);
4737 DependencyObject *dep = item->GetAsDependencyObject ();
4738 DependencyProperty *prop = NULL;
4739 bool res;
4740 Types *types = Deployment::GetCurrent ()->GetTypes ();
4742 if (types->Find (item->info->GetKind ())->IsValueType ()) {
4743 if (raise_errors) parser_error (p, item->element_name, NULL, -1, "Value types (%s) do not have properties.", property->element_name);
4744 g_strfreev (prop_name);
4745 return false;
4748 if (types->Find (property->info->GetPropertyOwnerKind ())->IsCustomType ()) {
4749 g_strfreev (prop_name);
4750 return set_managed_attached_property (p, item, property, value);
4753 if (!dep) {
4754 // FIXME is this really where this check should live
4755 if (raise_errors)
4756 parser_error (p, item->element_name, NULL, 2030,
4757 "Property element %s cannot be used inside another property element.",
4758 property->element_name);
4760 g_strfreev (prop_name);
4761 return false;
4764 prop = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, item->info->GetKind ()), prop_name [1]);
4766 if (prop) {
4767 if (prop->IsReadOnly ()) {
4768 if (raise_errors)
4769 parser_error (p, item->element_name, NULL, 2014,
4770 "The attribute %s is read only and cannot be set.", prop->GetName ());
4771 res = false;
4772 } else if (types->IsSubclassOf (value->info->GetKind (), prop->GetPropertyType())) {
4773 // an empty collection can be NULL and valid
4774 if (item->IsPropertySet (prop->GetName())) {
4775 if (raise_errors)
4776 parser_error (p, item->element_name, NULL, 2033,
4777 "Cannot specify the value multiple times for property: %s.",
4778 property->element_name);
4779 res = false;
4780 } else {
4781 MoonError err;
4783 // HACK - since the Setter is added to the collection *before* its properties are set
4784 // we find ourselves with a sealed Setter - which should not be possible at the parse time
4785 SetterBase *sb = NULL;
4786 if (types->IsSubclassOf (dep->GetObjectType (), Type::SETTERBASE)) {
4787 sb = (SetterBase*) dep;
4788 sb->SetIsSealed (false);
4791 if (!is_managed_kind (value->info->GetKind ()) && !value->info->RequiresManagedSet()) {
4792 if (!dep->SetValueWithError (prop, value->GetAsValue (), &err)) {
4793 if (raise_errors)
4794 parser_error (p, item->element_name, NULL, err.code, err.message);
4795 res = false;
4796 goto cleanup;
4799 } else {
4800 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, item->GetAsValue (), item, item->GetParentPointer (), NULL, prop_name [1], value->GetAsValue (), NULL)) {
4801 if (raise_errors)
4802 parser_error (p, item->element_name, NULL, err.code, err.message);
4803 res = false;
4804 goto cleanup;
4809 // re-seal the Setter (end-HACK)
4810 if (sb)
4811 sb->SetIsSealed (true);
4813 item->MarkPropertyAsSet (prop->GetName());
4814 res = true;
4816 } else if (types->IsSubclassOf (prop->GetPropertyType (), Type::COLLECTION) || types->IsSubclassOf (prop->GetPropertyType (), Type::RESOURCE_DICTIONARY)) {
4817 // The items were added in add_child
4818 return true;
4819 } else {
4820 if (raise_errors)
4821 parser_error (p, item->element_name, NULL, 2010, "does not support %s as content.", value->element_name);
4822 res = false;
4824 } else {
4825 dependency_object_missed_property (item, property, value, prop_name);
4826 res = false;
4829 cleanup:
4830 g_strfreev (prop_name);
4831 return res;
4834 bool
4835 xaml_set_property_from_str (DependencyObject *obj, DependencyProperty *prop, const char *value, MoonError *error)
4837 Value *v = NULL;
4838 bool rv = true;
4840 if (!value_from_str (prop->GetPropertyType(), prop->GetName(), value, &v))
4841 return false;
4843 // it's possible for (a valid) value to be NULL (and we must keep the default value)
4844 if (v) {
4845 rv = obj->SetValueWithError (prop, v, error);
4846 delete v;
4849 return rv;
4852 bool
4853 xaml_is_valid_event_name (Deployment *deployment, Type::Kind kind, const char *name, bool allow_desktop_events)
4855 Type *type = Type::Find (deployment, kind);
4856 if (!type)
4857 return false;
4859 int event_id = type->LookupEvent (name);
4860 if (event_id == -1)
4861 return false;
4863 if (!allow_desktop_events || (moonlight_flags & RUNTIME_INIT_DESKTOP_EXTENSIONS) == 0) {
4864 // if we're not allowing desktop-only events, or if the user hasn't allowed them,
4865 // return false if the name corresponds to one of them.
4866 if (!strcmp (name, "MouseRightButtonDown") ||
4867 !strcmp (name, "MouseRightButtonUp") ||
4868 !strcmp (name, "MouseWheel"))
4869 return false;
4872 return true;
4875 static void
4876 value_type_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr)
4878 // the only attributes value on value types seem to be x:Key
4879 // and x:Name, but reuse the generic namespace attribute stuff
4880 // anyway.
4882 for (int i = 0; attr [i]; i += 2) {
4883 // Skip empty attrs
4884 if (attr[i + 1] == NULL || attr[i + 1][0] == '\0')
4885 continue;
4887 char **attr_name = g_strsplit (attr [i], "|", -1);
4889 if (attr_name [1]) {
4891 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
4893 if (!ns)
4894 return parser_error (p, item->element_name, attr[i], 7055, "undeclared prefix");
4896 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
4898 g_strfreev (attr_name);
4900 // Setting managed attributes can cause errors galore
4901 if (p->error_args)
4902 return;
4904 continue;
4907 g_strfreev (attr_name);
4911 static void
4912 dependency_object_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr)
4914 Types *types = Deployment::GetCurrent ()->GetTypes ();
4915 GList *delay_att = NULL;
4917 for (int i = 0; attr [i]; i += 2) {
4919 if (p->error_args)
4920 return;
4922 // Setting attributes like x:Class can change item->item, so we
4923 // need to make sure we have an up to date pointer
4924 DependencyObject *dep = item->GetAsDependencyObject ();
4925 char **attr_name = g_strsplit (attr [i], "|", -1);
4927 if (attr_name [1]) {
4928 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
4930 if (ns != x_namespace) {
4931 delay_att = g_list_append (delay_att, GINT_TO_POINTER (i));
4932 g_strfreev (attr_name);
4933 continue;
4936 if (!ns) {
4937 g_strfreev (attr_name);
4938 return parser_error (p, item->element_name, attr[i], 5055, "undeclared prefix");
4941 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
4943 g_strfreev (attr_name);
4945 // Setting managed attributes can cause errors galore
4946 if (p->error_args)
4947 return;
4949 continue;
4952 g_strfreev (attr_name);
4954 const char *pname = attr [i];
4955 char *atchname = NULL;
4956 for (int a = 0; attr [i][a]; a++) {
4957 if (attr [i][a] != '.')
4958 continue;
4959 atchname = g_strndup (attr [i], a);
4960 pname = attr [i] + a + 1;
4961 break;
4964 DependencyProperty *prop = NULL;
4965 if (atchname) {
4966 Type *attached_type = types->Find (atchname);
4967 if (attached_type)
4968 prop = DependencyProperty::GetDependencyProperty (attached_type, pname);
4969 } else {
4970 prop = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, item->info->GetKind ()), pname);
4973 if (prop) {
4974 if (prop->GetId () == DependencyObject::NameProperty) {
4976 if (item->GetName ()) {
4977 parser_error (p, item->element_name, NULL, 2016, "Cannot specify both Name and x:Name attributes.");
4978 return;
4981 // XXX toshok - I don't like doing this here... but it fixes airlines.
4982 item->SetKey (p, attr[i+1]);
4984 NameScope *scope = p->namescope;
4985 if (!item->GetAsDependencyObject ()->SetName (attr [i+1], scope)) {
4986 parser_error (p, item->element_name, NULL, 2028,
4987 "The name already exists in the tree: %s.", attr [i+1]);
4988 g_free (atchname);
4989 g_list_free (delay_att);
4990 return;
4992 continue;
4995 if (prop->IsReadOnly ()) {
4996 parser_error (p, item->element_name, NULL, 2014,
4997 "The attribute %s is read only and cannot be set.", prop->GetName ());
4998 g_free (atchname);
4999 g_list_free (delay_att);
5000 return;
5003 if (item->IsPropertySet (prop->GetName())) {
5004 parser_error (p, item->element_name, attr [i], 2033,
5005 "Cannot specify the value multiple times for property: %s.", prop->GetName ());
5006 g_free (atchname);
5007 g_list_free (delay_att);
5008 return;
5011 Value *v = NULL;
5012 bool v_set = false;
5013 char *attr_value = g_strdup (attr [i+1]);
5015 bool need_managed = false;
5016 if (attr[i+1][0] == '{') {
5017 if (attr[i+1][1] == '}') {
5018 // {} is an escape sequence so you can have strings like {StaticResource}
5019 char *nv = attr_value;
5020 attr_value = g_strdup (attr_value + 2);
5021 g_free (nv);
5023 else if (attr[i+1][strlen(attr[i+1]) - 1] == '}') {
5024 need_managed = true;
5028 if (!need_managed) {
5029 if (!value_from_str_with_parser (p, prop->GetPropertyType(), prop->GetName(), attr_value, &v, &v_set)) {
5030 delete v;
5031 g_free (attr_value);
5032 continue;
5036 Type::Kind propKind = prop->GetPropertyType ();
5038 if (need_managed || is_managed_kind (propKind) || types->Find (prop->GetOwnerType ())->IsCustomType () || (v && is_managed_kind (v->GetKind ()))) {
5039 bool str_value = false;
5040 if (!v_set) {
5041 v = new Value (attr [i + 1]); // Note that we passed the non escaped value, not attr_value
5042 v_set = true;
5043 str_value = true;
5046 // printf ("setting managed property: %s::%s to %s=%s\n", dep->GetType ()->GetName (), prop->GetName (), attr [i], attr [i + 1]);
5047 if (p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, item->GetAsValue (), item, item->GetParentPointer (), NULL, g_strdup (attr [i]), v, NULL)) {
5048 delete v;
5049 g_free (attr_value);
5050 continue;
5051 } else {
5052 if (str_value) {
5053 delete v;
5054 v = NULL;
5056 if (!value_from_str_with_parser (p, prop->GetPropertyType(), prop->GetName(), attr_value, &v, &v_set)) {
5057 delete v;
5058 g_free (attr_value);
5059 continue;
5065 if (!v_set && !value_is_explicit_null (attr [i + 1])) { // Check the non escaped value
5066 parser_error (p, item->element_name, attr [i], 2024, "Invalid attribute value %s for property %s.", attr [i+1], attr [i]);
5068 g_free (attr_value);
5069 g_free (atchname);
5070 g_list_free (delay_att);
5071 return;
5074 MoonError err;
5075 // 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 ());
5076 if (!dep->SetValueWithError (prop, v, &err))
5077 parser_error (p, item->element_name, attr [i], err.code, err.message);
5078 else
5079 item->MarkPropertyAsSet (prop->GetName());
5081 delete v;
5082 g_free (attr_value);
5083 } else {
5084 delay_att = g_list_append (delay_att, GINT_TO_POINTER (i));
5087 if (atchname)
5088 g_free (atchname);
5091 GList *walk = g_list_first (delay_att);
5092 while (walk) {
5093 int i = GPOINTER_TO_INT (walk->data);
5095 if (p->error_args)
5096 return;
5098 char **attr_name = g_strsplit (attr [i], "|", -1);
5100 if (attr_name [1]) {
5101 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
5103 if (ns == x_namespace) {
5104 // Skip these, they are handled earlier
5105 g_strfreev (attr_name);
5106 walk = walk->prev;
5109 if (!ns) {
5110 g_strfreev (attr_name);
5111 parser_error (p, item->element_name, attr[i], 5055, "undeclared prefix");
5112 break;
5115 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
5117 g_strfreev (attr_name);
5119 // Setting managed attributes can cause errors galore
5120 if (p->error_args)
5121 break;
5122 } else {
5123 if (!item->SetUnknownAttribute (p, attr [i], attr [i + 1])) {
5124 parser_error (p, item->element_name, attr [i], 2012,
5125 "Unknown attribute %s on element %s.",
5126 attr [i], item->element_name);
5127 break;
5131 walk = walk->next;
5134 g_list_free (delay_att);
5138 static Value *
5139 lookup_named_item (XamlElementInstance *top, const char *name)
5141 Types *types = Deployment::GetCurrent ()->GetTypes ();
5142 XamlElementInstance *inst = top;
5144 while (inst) {
5145 if (inst->element_type == XamlElementInstance::ELEMENT) {
5146 ResourceDictionary *rd = NULL;
5147 Type::Kind kind = inst->info->GetKind ();
5149 if (types->IsSubclassOf (kind, Type::FRAMEWORKELEMENT)) {
5150 rd = inst->GetAsDependencyObject ()->GetValue (UIElement::ResourcesProperty)->AsResourceDictionary ();
5151 } else if (types->IsSubclassOf (kind, Type::RESOURCE_DICTIONARY)) {
5152 rd = (ResourceDictionary*) inst->GetAsDependencyObject ();
5155 if (rd) {
5156 bool exists;
5157 Value *res = lookup_resource_dictionary (rd, name, &exists);
5158 if (exists)
5159 return res;
5163 inst = inst->parent;
5166 return NULL;
5169 static Value *
5170 lookup_resource_dictionary (ResourceDictionary *rd, const char *name, bool *exists)
5172 *exists = false;
5173 Value *resource_value = rd->Get (name, exists);
5174 return *exists ? new Value (*resource_value) : NULL;
5177 Value *
5178 xaml_lookup_named_item (void *parser, void *instance, const char* name)
5180 XamlParserInfo *p = (XamlParserInfo *) parser;
5181 XamlElementInstance *inst = (XamlElementInstance *) instance;
5182 Value *res = NULL;
5184 if (inst)
5185 res = lookup_named_item (inst, name);
5187 XamlContext *context = p->loader->GetContext ();
5188 if (!res && context)
5189 context->internal->LookupNamedItem (name, &res);
5191 if (!res) {
5192 Application *app = Application::GetCurrent ();
5193 if (app) {
5194 ResourceDictionary *rd = app->GetResources ();
5196 bool exists = false;
5197 res = lookup_resource_dictionary (rd, name, &exists);
5199 if (res && Type::IsSubclassOf (p->deployment, res->GetKind (), Type::DEPENDENCY_OBJECT)) {
5200 DependencyObject *dob = res->AsDependencyObject ();
5201 NameScope::SetNameScope (dob, dob->FindNameScope ());
5206 return res;
5209 void *
5210 xaml_get_template_parent (void *parser, void *element_instance)
5212 XamlParserInfo *p = (XamlParserInfo *) parser;
5213 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5215 return p->GetTemplateParent (item);
5218 char *
5219 xaml_get_element_key (void *parser, void *element_instance)
5221 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5222 const char *key = item->GetKey ();
5223 if (!key)
5224 key = item->GetName ();
5225 return g_strdup (key);
5228 char *
5229 xaml_get_element_name (void *parser, void *element_instance)
5231 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5232 return g_strdup (item->element_name);
5235 bool
5236 xaml_is_property_set (void *parser, void *element_instance, char *name)
5238 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5239 return item->IsPropertySet (name);
5242 void
5243 xaml_mark_property_as_set (void *parser, void *element_instance, char *name)
5245 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5246 item->MarkPropertyAsSet (g_strdup (name));
5249 void
5250 xaml_delay_set_property (void *parser, void *element_instance, const char *xmlns, const char *name, const Value *value)
5252 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5253 item->DelaySetProperty (xmlns, name, value);
5256 void
5257 xaml_init (void)
5259 default_namespace = new DefaultNamespace ();
5260 x_namespace = new XNamespace ();
5261 xml_namespace = new XmlNamespace ();