1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * xaml.cpp: xaml parser
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.
30 #include "animation.h"
31 #include "bitmapimage.h"
33 #include "projection.h"
34 #include "textblock.h"
42 #include "namescope.h"
49 #include "application.h"
50 #include "thickness.h"
51 #include "cornerradius.h"
52 #include "deployment.h"
54 #include "deepzoomimagetilesource.h"
55 #include "managedtypeinfo.h"
58 class XamlElementInfo
;
59 class XamlElementInstance
;
62 class DefaultNamespace
;
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",
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
);
117 BUFFER_MODE_TEMPLATE
,
122 class XamlNamespace
{
138 GSList
*w
= prefixes
;
141 char *p
= (char *) w
->data
;
147 g_slist_free (prefixes
);
152 virtual XamlElementInfo
* FindElement (XamlParserInfo
*p
, const char *el
, const char **attr
, bool create
) = 0;
153 virtual bool SetAttribute (XamlParserInfo
*p
, XamlElementInstance
*item
, const char *attr
, const char *value
) = 0;
156 virtual const char* GetUri () = 0;
158 void AddPrefix (const char *prefix
)
160 prefixes
= g_slist_append (prefixes
, g_strdup (prefix
));
163 bool HasPrefix (const char *prefix
)
165 return g_slist_find_custom (prefixes
, prefix
, (GCompareFunc
) strcmp
) != NULL
;
168 GSList
* GetPrefixes ()
175 add_namespace_data (gpointer key
, gpointer value
, gpointer user_data
)
177 XamlNamespace
*ns
= (XamlNamespace
*) value
;
178 GHashTable
*table
= (GHashTable
*) user_data
;
180 if ((void *)ns
!= (void *)default_namespace
) {
181 GSList
*p
= ns
->GetPrefixes ();
184 g_hash_table_insert (table
, g_strdup ((char *)p
->data
), g_strdup (ns
->GetUri ()));
192 add_namespace_to_ignorable (gpointer key
, gpointer value
, gpointer user_data
)
194 char *prefix
= (char *) key
;
195 char *uri
= (char *) value
;
196 GString
*str
= (GString
*) user_data
;
198 g_string_append_printf (str
, "xmlns:%s=\"%s\" ", prefix
, uri
);
201 class XamlContextInternal
{
205 FrameworkTemplate
*template_parent
;
206 GHashTable
*imported_namespaces
;
207 XamlLoaderCallbacks callbacks
;
209 XamlContextInternal
*parent_context
;
211 DependencyObject
*source
;
213 XamlContextInternal (XamlLoaderCallbacks callbacks
, Value
*top_element
, FrameworkTemplate
*template_parent
, GHashTable
*namespaces
, GSList
*resources
, XamlContextInternal
*parent_context
)
215 this->callbacks
= callbacks
;
216 this->top_element
= new Value (*top_element
);
217 this->template_parent
= template_parent
;
218 this->resources
= resources
;
219 this->parent_context
= parent_context
;
221 if (this->callbacks
.create_gchandle
)
222 this->callbacks
.create_gchandle ();
223 imported_namespaces
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
224 g_hash_table_foreach (namespaces
, add_namespace_data
, imported_namespaces
);
228 ~XamlContextInternal ()
230 if (imported_namespaces
)
231 g_hash_table_destroy (imported_namespaces
);
233 g_slist_free (resources
);
237 char *CreateIgnorableTagOpen ()
239 GString
*str
= g_string_new ("<" INTERNAL_IGNORABLE_ELEMENT
" ");
240 g_hash_table_foreach (imported_namespaces
, add_namespace_to_ignorable
, str
);
242 str
= g_string_append (str
, ">");
244 char *res
= str
->str
;
245 g_string_free (str
, false);
250 char *CreateIgnorableTagClose ()
252 return g_strdup ("</" INTERNAL_IGNORABLE_ELEMENT
">");
255 bool LookupNamedItem (const char* name
, Value
**v
)
261 GSList
*walk
= resources
;
263 DependencyObject
*dob
= (DependencyObject
*)walk
->data
;
264 if (dob
->Is (Type::RESOURCE_DICTIONARY
))
265 *v
= lookup_resource_dictionary ((ResourceDictionary
*) walk
->data
, name
, &exists
);
266 else /* dob->Is (Type::FRAMEWORKELEMENT) */ {
267 ResourceDictionary
*rd
= dob
->GetValue (UIElement::ResourcesProperty
)->AsResourceDictionary();
268 *v
= lookup_resource_dictionary (rd
, name
, &exists
);
278 else if (!parent_context
)
281 return parent_context
->LookupNamedItem (name
, v
);
284 void SetTemplateBindingSource (DependencyObject
*source
)
286 this->source
= source
;
289 DependencyObject
* GetTemplateBindingSource ()
296 XamlContext::XamlContext (XamlContextInternal
*internal
)
298 this->internal
= internal
;
301 XamlContext::~XamlContext ()
307 XamlContext::SetTemplateBindingSource (DependencyObject
*source
)
309 internal
->SetTemplateBindingSource (source
);
313 XamlContext::GetTemplateBindingSource ()
315 return internal
->GetTemplateBindingSource ();
318 class XamlElementInfo
{
321 Type::Kind property_owner_kind
;
325 XamlElementInfo
*parent
;
329 XamlElementInfo (const char *xmlns
, const char *name
, Type::Kind kind
)
335 this->cdata_verbatim
= false;
337 this->property_owner_kind
= Type::INVALID
;
344 virtual Type::Kind
GetKind () { return kind
; }
346 virtual void SetPropertyOwnerKind (Type::Kind value
) { property_owner_kind
= value
; }
347 virtual Type::Kind
GetPropertyOwnerKind () { return property_owner_kind
; }
349 virtual const char *GetContentProperty (XamlParserInfo
*p
)
351 Type
*t
= Type::Find (Deployment::GetCurrent (), kind
);
353 return t
->GetContentPropertyName ();
357 void SetIsCDataVerbatim (bool flag
)
359 cdata_verbatim
= flag
;
362 bool IsCDataVerbatim ()
364 return cdata_verbatim
;
367 virtual bool RequiresManagedSet () { return false; }
369 virtual XamlElementInstance
*CreateElementInstance (XamlParserInfo
*p
) = 0;
370 virtual XamlElementInstance
*CreateWrappedElementInstance (XamlParserInfo
*p
, Value
*o
) = 0;
371 virtual XamlElementInstance
*CreatePropertyElementInstance (XamlParserInfo
*p
, const char *name
) = 0;
375 struct DelayedProperty
{
380 DelayedProperty (const char *xmlns
, const char *name
, const Value
*value
)
382 this->xmlns
= g_strdup (xmlns
);
383 this->name
= g_strdup (name
);
384 this->value
= new Value (*value
);
396 free_property_list (GSList
*list
)
401 DelayedProperty
*prop
= (DelayedProperty
*) walk
->data
;
410 class XamlElementInstance
: public List::Node
{
413 DependencyObject
*item
;
416 GSList
*delayed_properties
;
419 const char *element_name
;
420 XamlElementInfo
*info
;
422 XamlElementInstance
*parent
;
432 bool requires_managed
;
436 GHashTable
*set_properties
;
438 XamlElementInstance (XamlElementInfo
*info
, const char* element_name
, ElementType type
, bool requires_managed
= false)
440 this->element_name
= element_name
;
441 this->set_properties
= NULL
;
442 this->element_type
= type
;
449 this->cleanup_value
= true;
450 this->requires_managed
= requires_managed
;
451 this->delayed_properties
= NULL
;
453 children
= new List ();
456 virtual ~XamlElementInstance ()
458 children
->Clear (true);
469 g_hash_table_destroy (set_properties
);
471 if (element_name
&& element_type
== PROPERTY
)
472 g_free ((void*) element_name
);
474 free_property_list (delayed_properties
);
477 virtual bool SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, XamlElementInstance
*value
) = 0;
478 virtual bool SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, const char* value
) = 0;
479 virtual void AddChild (XamlParserInfo
*p
, XamlElementInstance
*child
) = 0;
480 virtual void SetAttributes (XamlParserInfo
*p
, const char **attr
) = 0;
482 virtual bool TrySetContentProperty (XamlParserInfo
*p
, XamlElementInstance
*value
);
483 virtual bool TrySetContentProperty (XamlParserInfo
*p
, const char *value
);
486 char *GetKey () { return x_key
; }
487 char *GetName () { return x_name
; }
489 void SetName (XamlParserInfo
*p
, const char *name
)
491 this->x_name
= g_strdup (name
);
494 void SetKey (XamlParserInfo
*p
, const char *key
)
496 this->x_key
= g_strdup (key
);
499 virtual bool IsDependencyObject ()
504 virtual bool SetUnknownAttribute (XamlParserInfo
*p
, const char* name
, const char* value
);
506 void SetValue (Value
*v
)
508 if (value
&& cleanup_value
)
513 virtual Value
*GetAsValue ()
516 value
= new Value (item
);
521 virtual DependencyObject
*GetAsDependencyObject ()
526 virtual void SetDependencyObject (DependencyObject
*value
)
531 virtual void* GetManagedPointer ()
536 virtual Value
* GetParentPointer ()
538 XamlElementInstance
*walk
= parent
;
539 while (walk
&& walk
->element_type
!= XamlElementInstance::ELEMENT
)
545 return walk
->GetAsValue ();
548 virtual bool IsTemplate ()
553 virtual XamlElementInfo
* FindPropertyElement (XamlParserInfo
*p
, const char *el
, const char *dot
);
555 void SetDelayedProperties (XamlParserInfo
*p
);
557 void DelaySetProperty (const char *xmlns
, const char *name
, const Value
*value
)
559 DelayedProperty
*prop
= new DelayedProperty (xmlns
, name
, value
);
561 delayed_properties
= g_slist_append (delayed_properties
, prop
);
564 bool IsPropertySet (const char *name
)
569 return g_hash_table_lookup (set_properties
, name
) != NULL
;
572 void MarkPropertyAsSet (const char *name
)
575 set_properties
= g_hash_table_new (g_str_hash
, g_str_equal
);
577 g_hash_table_insert (set_properties
, (void *) name
, GINT_TO_POINTER (TRUE
));
582 unref_xaml_element (gpointer data
, gpointer user_data
)
584 DependencyObject
* dob
= (DependencyObject
*) data
;
585 //printf ("unref_xaml_element: %i\n", dob->id);
590 class XamlParserInfo
{
594 const char *file_name
;
596 NameScope
*namescope
;
597 XamlElementInstance
*top_element
;
598 XamlNamespace
*current_namespace
;
599 XamlElementInstance
*current_element
;
600 const char *next_element
;
601 Deployment
*deployment
;
603 GHashTable
*namespace_map
;
607 bool implicit_default_namespace
;
609 ParserErrorEventArgs
*error_args
;
615 // If set, this is used to hydrate an existing object, not to create a new toplevel one
617 Value
*hydrate_expecting
;
620 char* buffer_until_element
;
622 BufferMode buffer_mode
;
624 bool validate_templates
;
627 GList
*created_elements
;
628 GList
*created_namespaces
;
629 const char* xml_buffer
;
630 int multi_buffer_offset
;
631 int xml_buffer_start_index
;
634 XamlParserInfo (XML_Parser parser
, const char *file_name
)
636 this->deployment
= Deployment::GetCurrent ();
637 this->parser
= parser
;
638 this->file_name
= file_name
;
639 this->namescope
= new NameScope ();
642 current_namespace
= NULL
;
643 current_element
= NULL
;
644 cdata_content
= false;
646 implicit_default_namespace
= false;
649 created_elements
= NULL
;
650 created_namespaces
= NULL
;
651 hydrate_expecting
= NULL
;
654 buffer_until_element
= NULL
;
658 multi_buffer_offset
= 0;
659 validate_templates
= false;
661 namespace_map
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
664 void AddCreatedElement (DependencyObject
* element
)
666 // if we have a loader, set the surface and base resource location
668 element
->SetIsAttached (true); /* Some glyphs (DRT 0/Test5, 58) do not show up without this */
669 element
->SetResourceBase (loader
->GetResourceBase());
672 // When instantiating a template, some elements are created which are not explicitly
673 // mentioned in the xaml. Therefore we need to keep walking up the tree until we find
674 // the last element which we set a value for Control::IsTemplateItem and propagate
676 XamlElementInstance
*instance
= current_element
;
678 if (!instance
->IsDependencyObject () || !instance
->GetAsDependencyObject ()) {
679 instance
= instance
->parent
;
682 if (!instance
->GetAsDependencyObject ()->ReadLocalValue (Control::IsTemplateItemProperty
)) {
683 instance
= instance
->parent
;
686 Control::SetIsTemplateItem (element
, Control::GetIsTemplateItem (instance
->GetAsDependencyObject ()));
687 if (DependencyObject
*e
= instance
->GetAsDependencyObject ()->GetTemplateOwner ())
688 element
->SetTemplateOwner (e
);
692 if (instance
== NULL
) {
693 Control::SetIsTemplateItem (element
, loader
->GetExpandingTemplate ());
694 element
->SetTemplateOwner (loader
->GetTemplateOwner ());
697 if (Control::GetIsTemplateItem (element
))
698 NameScope::SetNameScope (element
, namescope
);
699 created_elements
= g_list_prepend (created_elements
, element
);
702 void AddCreatedNamespace (XamlNamespace
* ns
)
704 created_namespaces
= g_list_prepend (created_namespaces
, ns
);
707 void QueueBeginBuffering (char* buffer_until
, BufferMode mode
)
709 buffer_until_element
= buffer_until
;
713 xml_buffer_start_index
= -1;
716 void BeginBuffering ()
718 xml_buffer_start_index
= XML_GetCurrentByteIndex (parser
) - multi_buffer_offset
;
719 buffer
= g_string_new (NULL
);
722 bool ShouldBeginBuffering ()
724 return InBufferingMode () && xml_buffer_start_index
== -1;
727 bool InBufferingMode ()
729 return buffer_until_element
!= NULL
;
732 void AppendCurrentXml ()
736 int pos
= XML_GetCurrentByteIndex (parser
) - multi_buffer_offset
;
737 g_string_append_len (buffer
, xml_buffer
+ xml_buffer_start_index
, pos
- xml_buffer_start_index
);
745 buffer_until_element
= NULL
;
748 return g_strdup ("");
750 char* res
= buffer
->str
;
751 g_string_free (buffer
, FALSE
);
756 void SetXmlBuffer (const char* xml_buffer
)
758 if (InBufferingMode ())
761 if (this->xml_buffer
)
762 multi_buffer_offset
+= strlen (this->xml_buffer
);
764 this->xml_buffer
= xml_buffer
;
765 xml_buffer_start_index
= 0;
768 void ValidateTemplate (const char* buffer
, XamlContext
* context
, FrameworkTemplate
*binding_source
)
770 XamlLoader
*loader
= new XamlLoader (NULL
, buffer
, NULL
, context
);
773 context
->SetTemplateBindingSource (binding_source
);
775 loader
->SetImportDefaultXmlns (true);
778 Value
*result
= loader
->CreateFromStringWithError (buffer
, true, &dummy
, XamlLoader::IMPORT_DEFAULT_XMLNS
| XamlLoader::VALIDATE_TEMPLATES
, &error
);
783 if (error
.number
!= MoonError::NO_ERROR
) {
784 int line_number
= error
.line_number
+ XML_GetCurrentLineNumber (parser
);
785 error_args
= new ParserErrorEventArgs (error
.message
, file_name
, line_number
, error
.char_position
, error
.code
, NULL
, NULL
);
789 FrameworkTemplate
*GetTemplateParent (XamlElementInstance
*item
)
791 XamlElementInstance
*parent
= item
->parent
;
793 while (parent
&& !parent
->IsTemplate ())
794 parent
= parent
->parent
;
797 return (FrameworkTemplate
*) parent
->GetManagedPointer ();
802 XamlContext
*context
= loader
->GetContext ();
806 return context
->internal
->template_parent
;
809 Value
*GetTopElementPtr ()
811 XamlContext
*context
= loader
->GetContext ();
813 return context
->internal
->top_element
;
816 return top_element
->GetAsValue ();
823 created_elements
= g_list_reverse (created_elements
);
824 g_list_foreach (created_elements
, unref_xaml_element
, NULL
);
825 g_list_free (created_elements
);
827 g_list_foreach (created_namespaces
, destroy_created_namespace
, NULL
);
828 g_list_free (created_namespaces
);
830 g_hash_table_destroy (namespace_map
);
833 g_string_free (cdata
, TRUE
);
843 class XamlElementInfoNative
: public XamlElementInfo
{
847 XamlElementInfoNative (Type
*t
) : XamlElementInfo (NULL
, t
->GetName (), t
->GetKind ())
857 const char* GetName ()
859 return type
->GetName ();
862 const char* GetContentProperty (XamlParserInfo
*p
);
864 XamlElementInstance
* CreateElementInstance (XamlParserInfo
*p
);
865 XamlElementInstance
* CreateWrappedElementInstance (XamlParserInfo
*p
, Value
*o
);
866 XamlElementInstance
* CreatePropertyElementInstance (XamlParserInfo
*p
, const char *name
);
870 class XamlElementInstanceNative
: public XamlElementInstance
{
871 XamlElementInfoNative
*element_info
;
872 XamlParserInfo
*parser_info
;
875 XamlElementInstanceNative (XamlElementInfoNative
*element_info
, XamlParserInfo
*parser_info
, const char *name
, ElementType type
, bool create_item
= true);
877 virtual DependencyObject
*CreateItem ();
879 virtual XamlElementInfo
* FindPropertyElement (XamlParserInfo
*p
, const char *el
, const char *dot
);
881 virtual bool SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, XamlElementInstance
*value
);
882 virtual bool SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, const char* value
);
883 virtual void AddChild (XamlParserInfo
*p
, XamlElementInstance
*child
);
884 virtual void SetAttributes (XamlParserInfo
*p
, const char **attr
);
888 class XamlElementInstanceValueType
: public XamlElementInstance
{
889 XamlElementInfoNative
*element_info
;
890 XamlParserInfo
*parser_info
;
893 XamlElementInstanceValueType (XamlElementInfoNative
*element_info
, XamlParserInfo
*parser_info
, const char *name
, ElementType type
);
895 virtual bool IsDependencyObject ()
900 virtual Value
*GetAsValue ()
903 // we are an empty element (e.g. <sys:String></sys:String>). do type specific magic here.
904 CreateValueItemFromString ("");
910 bool CreateValueItemFromString (const char* str
);
912 // A Value type doesn't really support anything. It's just here so people can do <SolidColorBrush.Color><Color>#FF00FF</Color></SolidColorBrush.Color>
913 virtual DependencyObject
*CreateItem () { return NULL
; }
914 virtual bool SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, XamlElementInstance
*value
) { return false; }
915 virtual bool SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, const char *value
) { return false; }
916 virtual void AddChild (XamlParserInfo
*p
, XamlElementInstance
*child
) { }
917 virtual void SetAttributes (XamlParserInfo
*p
, const char **attr
);
919 virtual bool TrySetContentProperty (XamlParserInfo
*p
, XamlElementInstance
*value
) { return false; }
920 virtual bool TrySetContentProperty (XamlParserInfo
*p
, const char *value
) { return CreateValueItemFromString (value
); }
923 class XamlElementInfoEnum
: public XamlElementInfo
{
925 XamlElementInfoEnum (const char *name
) : XamlElementInfo (NULL
, name
, Type::INT32
)
929 XamlElementInstance
* CreateElementInstance (XamlParserInfo
*p
);
930 XamlElementInstance
* CreateWrappedElementInstance (XamlParserInfo
*p
, Value
*o
);
931 XamlElementInstance
* CreatePropertyElementInstance (XamlParserInfo
*p
, const char *name
) { return NULL
; }
934 class XamlElementInstanceEnum
: public XamlElementInstance
{
937 XamlElementInstanceEnum (XamlElementInfoEnum
*element_info
, const char *name
, ElementType type
);
939 virtual bool IsDependencyObject ()
944 virtual Value
*GetAsValue ()
949 bool CreateEnumFromString (const char* str
);
951 // An enum type doesn't really support anything. It's just here so people can do <Visibility>Visible</Visibility>
952 virtual DependencyObject
*CreateItem () { return NULL
; }
953 virtual bool SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, XamlElementInstance
*value
) { return false; }
954 virtual bool SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, const char *value
) { return false; }
955 virtual void AddChild (XamlParserInfo
*p
, XamlElementInstance
*child
) { }
956 virtual void SetAttributes (XamlParserInfo
*p
, const char **attr
);
958 virtual bool TrySetContentProperty (XamlParserInfo
*p
, XamlElementInstance
*value
) { return false; }
959 virtual bool TrySetContentProperty (XamlParserInfo
*p
, const char *value
) { return CreateEnumFromString (value
); }
962 class XamlElementInstanceTemplate
: public XamlElementInstanceNative
{
964 XamlElementInstanceTemplate (XamlElementInfoNative
*element_info
, XamlParserInfo
*parser_info
, const char *name
, ElementType type
, bool create_item
= true)
965 : XamlElementInstanceNative (element_info
, parser_info
, name
, type
, create_item
)
969 virtual bool IsTemplate ()
976 class DefaultNamespace
: public XamlNamespace
{
983 virtual ~DefaultNamespace () { }
985 virtual XamlElementInfo
* FindElement (XamlParserInfo
*p
, const char *el
, const char **attr
, bool create
)
987 Type
* t
= Type::Find (p
->deployment
, el
, false);
988 if (t
&& !kind_requires_managed_load (t
->GetKind ()))
989 return new XamlElementInfoNative (t
);
991 if (enums_is_enum_name (el
))
992 return new XamlElementInfoEnum (g_strdup (el
));
994 XamlElementInfo
* managed_element
= create_element_info_from_imported_managed_type (p
, el
, attr
, create
);
996 return managed_element
;
1002 virtual bool SetAttribute (XamlParserInfo
*p
, XamlElementInstance
*item
, const char *attr
, const char *value
)
1007 virtual const char* GetUri () { return "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; }
1010 class XmlNamespace
: public XamlNamespace
{
1017 virtual ~XmlNamespace () { }
1019 virtual XamlElementInfo
* FindElement (XamlParserInfo
*p
, const char *el
, const char **attr
, bool create
)
1024 virtual bool SetAttribute (XamlParserInfo
*p
, XamlElementInstance
*item
, const char *attr
, const char *value
)
1026 if (!strcmp ("lang", attr
)) {
1027 if (item
->IsDependencyObject ()) {
1028 DependencyObject
*dob
= item
->GetAsDependencyObject ();
1029 if (dob
->Is(Type::FRAMEWORKELEMENT
)) {
1030 ((FrameworkElement
*)dob
)->SetLanguage (value
);
1039 virtual const char* GetUri () { return "http://www.w3.org/XML/1998/namespace"; }
1042 class XNamespace
: public XamlNamespace
{
1049 virtual ~XNamespace () { }
1051 virtual XamlElementInfo
* FindElement (XamlParserInfo
*p
, const char *el
, const char **attr
, bool create
)
1056 virtual char *FindTypeName (const char **attr
, char **xmlns
)
1063 for (int i
= 0; attr
[i
]; i
+= 2) {
1064 const char *ns
= strchr (attr
[i
], '|');
1068 if (strncmp (GetUri (), attr
[i
], ns
- attr
[i
]) || strcmp ("Class", ns
+ 1))
1071 ns
= strchr (attr
[i
+ 1], ';');
1073 *xmlns
= g_strdup ("");
1074 res
= g_strdup (attr
[i
+ 1]);
1076 *xmlns
= g_strdup (ns
+ 1);
1077 res
= g_strndup (attr
[i
+ 1], attr
[i
+ 1] - ns
);
1084 bool IsParentResourceDictionary (XamlElementInstance
*parent
)
1089 return Type::IsSubclassOf (Deployment::GetCurrent (), parent
->info
->GetKind (), Type::RESOURCE_DICTIONARY
);
1092 virtual bool SetAttribute (XamlParserInfo
*p
, XamlElementInstance
*item
, const char *attr
, const char *value
)
1094 if (!strcmp ("Name", attr
)) {
1096 // Causes breakage in airlines
1097 // Maybe x:Name overwrites but Name does not?
1099 // if (p->namescope->FindName (value)) {
1100 // parser_error (p, p->current_element->element_name, "x:Name", 2028, "The name already exists in the tree: %s.", value);
1105 if (IsParentResourceDictionary (p
->current_element
)) {
1106 if (item
->GetKey ()) {
1107 // XXX don't know the proper values here...
1108 parser_error (p
, item
->element_name
, NULL
, 2028,
1109 "The name already exists in the tree: %s.", value
);
1114 if (item
->GetName ()) {
1115 parser_error (p
, item
->element_name
, NULL
, 2016, "Cannot specify both Name and x:Name attributes.");
1119 item
->SetName (p
, value
);
1121 if (item
->IsDependencyObject ()) {
1122 NameScope
*scope
= p
->namescope
;
1123 if (!item
->GetAsDependencyObject ()->SetName (value
, scope
)) {
1124 if (IsParentResourceDictionary (p
->current_element
)) {
1125 // FIXME: inside of a resource dictionary this has an extremly
1126 // strange behavior. this isn't exactly right, since not only
1127 // does the exception get swallowed, but the name seems to also
1131 parser_error (p
, item
->element_name
, NULL
, 2028,
1132 "The name already exists in the tree: %s.", value
);
1142 if (!strcmp ("Key", attr
)) {
1143 if (item
->GetKey () && IsParentResourceDictionary (p
->current_element
) && !Type::IsSubclassOf (p
->deployment
, item
->info
->GetKind (), Type::STORYBOARD
)) {
1144 // XXX don't know the proper values here...
1145 parser_error (p
, item
->element_name
, NULL
, 2028,
1146 "The name already exists in the tree: %s.", value
);
1149 item
->SetKey (p
, value
);
1153 if (!strcmp ("Class", attr
)) {
1154 if (!is_legal_top_level_kind (item
->info
->GetKind ())) {
1155 // XXX don't know the proper values here...
1156 parser_error (p
, item
->element_name
, attr
, -1,
1157 "Cannot specify x:Class type '%s' on value type element (%s).", value
, item
->element_name
);
1161 if (p
->top_element
!= item
) {
1162 // HAH: what a useless error message
1163 parser_error (p
, item
->element_name
, attr
, 2012,
1164 "Unknown attribute %s on element %s.", attr
, item
->element_name
);
1168 // While hydrating, we do not need to create the toplevel class, its created already
1172 parser_error (p
, item
->element_name
, attr
, 4005,
1173 "Cannot specify x:Class in xaml files outside of a xap.");
1181 virtual const char* GetUri () { return X_NAMESPACE_URI
; }
1185 class PrimitiveNamespace
: public XamlNamespace
{
1188 PrimitiveNamespace (char *prefix
)
1193 virtual ~PrimitiveNamespace ()
1197 virtual XamlElementInfo
* FindElement (XamlParserInfo
*p
, const char *el
, const char **attr
, bool create
)
1199 if (!strcmp ("String", el
)) {
1200 Type
* t
= Type::Find (p
->deployment
, Type::STRING
);
1201 // it's not as easy in this case, because primitive clr strings require that the
1202 // character data be read in verbatim, including all whitespace.
1203 XamlElementInfo
*info
= new XamlElementInfoNative (t
);
1204 info
->SetIsCDataVerbatim (true);
1206 } else if (!strcmp ("Int32", el
)) {
1207 Type
* t
= Type::Find (p
->deployment
, Type::INT32
);
1208 return new XamlElementInfoNative (t
);
1209 } else if (!strcmp ("Double", el
)) {
1210 Type
* t
= Type::Find (p
->deployment
, Type::DOUBLE
);
1211 return new XamlElementInfoNative (t
);
1212 } else if (!strcmp ("Boolean", el
)) {
1213 Type
* t
= Type::Find (p
->deployment
, Type::BOOL
);
1214 return new XamlElementInfoNative (t
);
1215 } else if (!strcmp ("TimeSpan", el
)) {
1216 Type
* t
= Type::Find (p
->deployment
, Type::TIMESPAN
);
1217 return new XamlElementInfoNative (t
);
1223 virtual bool SetAttribute (XamlParserInfo
*p
, XamlElementInstance
*item
, const char *attr
, const char *value
)
1228 virtual const char* GetUri () { return PRIMITIVE_NAMESPACE_URI
; }
1232 class MCIgnorableNamespace
: public XamlNamespace
{
1235 MCIgnorableNamespace (char *prefix
)
1240 virtual ~MCIgnorableNamespace ()
1244 virtual XamlElementInfo
* FindElement (XamlParserInfo
*p
, const char *el
, const char **attr
, bool create
)
1249 virtual bool SetAttribute (XamlParserInfo
*p
, XamlElementInstance
*item
, const char *attr
, const char *value
)
1251 if (!strcmp ("Ignorable", attr
)) {
1252 const char *start
= value
;
1254 const char *space
= strchr (start
, ' ');
1257 prefix
= g_strndup (start
, space
- start
);
1260 prefix
= g_strdup (start
);
1264 XamlNamespace
*ns
= (XamlNamespace
*) g_hash_table_find (p
->namespace_map
, namespace_for_prefix
, prefix
);
1266 ns
->is_ignored
= true;
1276 virtual const char* GetUri () { return MC_IGNORABLE_NAMESPACE_URI
; }
1281 destroy_created_namespace (gpointer data
, gpointer user_data
)
1283 XamlNamespace
* ns
= (XamlNamespace
*) data
;
1288 class XamlElementInfoManaged
: public XamlElementInfo
{
1290 XamlElementInfoManaged (const char *xmlns
, const char *name
, XamlElementInfo
*parent
, Type::Kind dependency_type
, Value
*obj
) : XamlElementInfo (xmlns
, name
, dependency_type
)
1297 const char* GetName () { return name
; }
1299 const char* GetContentProperty (XamlParserInfo
*p
);
1301 virtual bool RequiresManagedSet () { return true; }
1303 XamlElementInstance
* CreateElementInstance (XamlParserInfo
*p
);
1304 XamlElementInstance
* CreateWrappedElementInstance (XamlParserInfo
*p
, Value
*o
);
1305 XamlElementInstance
* CreatePropertyElementInstance (XamlParserInfo
*p
, const char *name
);
1309 class XamlElementInstanceManaged
: public XamlElementInstance
{
1311 XamlElementInstanceManaged (XamlElementInfo
*info
, const char *name
, ElementType type
, Value
*obj
);
1313 virtual bool IsDependencyObject ()
1315 return is_dependency_object
;
1318 virtual bool SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, XamlElementInstance
*value
);
1319 virtual bool SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, const char* value
);
1320 virtual void AddChild (XamlParserInfo
*p
, XamlElementInstance
*child
);
1321 virtual void SetAttributes (XamlParserInfo
*p
, const char **attr
);
1323 virtual bool TrySetContentProperty (XamlParserInfo
*p
, XamlElementInstance
*value
);
1324 virtual bool TrySetContentProperty (XamlParserInfo
*p
, const char *value
);
1326 virtual void* GetManagedPointer ();
1327 virtual Value
* GetParentPointer ();
1329 bool is_dependency_object
;
1333 class XamlElementInfoImportedManaged
: public XamlElementInfoManaged
{
1335 XamlElementInfoImportedManaged (const char *name
, XamlElementInfo
*parent
, Value
*obj
) : XamlElementInfoManaged (NULL
, name
, parent
, obj
->GetKind (), obj
)
1339 const char* GetContentProperty (XamlParserInfo
*p
);
1341 XamlElementInstance
* CreateElementInstance (XamlParserInfo
*p
);
1342 XamlElementInstance
* CreateWrappedElementInstance (XamlParserInfo
*p
, Value
*o
);
1343 XamlElementInstance
* CreatePropertyElementInstance (XamlParserInfo
*p
, const char *name
);
1348 class ManagedNamespace
: public XamlNamespace
{
1352 ManagedNamespace (char *xmlns
, char *prefix
)
1354 this->xmlns
= xmlns
;
1358 virtual ~ManagedNamespace ()
1363 virtual XamlElementInfo
* FindElement (XamlParserInfo
*p
, const char *el
, const char **attr
, bool create
)
1365 char* type_name
= NULL
;
1366 char* type_xmlns
= NULL
;
1367 const char* use_xmlns
= xmlns
;
1373 // We might have an x:Class attribute specified, so we need to use that for the
1374 // type_name that we pass to LookupObject
1375 if (strcmp ("Application", el
)) {
1376 type_name
= x_namespace
->FindTypeName (attr
, &type_xmlns
);
1379 use_xmlns
= type_xmlns
;
1381 if (!p
->hydrating
) {
1382 parser_error (p
, el
, "x:Class", 4005, "Cannot specify x:Class in xaml files outside of a xap.");
1389 Value
*value
= new Value ();
1390 if (!p
->loader
->LookupObject (p
, p
->GetTopElementPtr (), p
->current_element
? p
->current_element
->GetAsValue () : NULL
, use_xmlns
, el
, create
, false, value
)) {
1391 parser_error (p
, el
, NULL
, 2007, "Unable to resolve managed type %s.", el
);
1396 g_free (type_xmlns
);
1400 if (p
->hydrate_expecting
) {
1402 // If we are hydrating a top level managed object, use the Value* passed
1403 // to Hydrate as our value
1406 value
= p
->hydrate_expecting
;
1410 XamlElementInfoManaged
*info
= new XamlElementInfoManaged (xmlns
, g_strdup (el
), NULL
, value
->GetKind (), value
);
1414 g_free (type_xmlns
);
1418 virtual bool SetAttribute (XamlParserInfo
*p
, XamlElementInstance
*item
, const char *attr
, const char *value
)
1424 Value v
= Value (value
);
1425 return p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), item
->info
->xmlns
, item
->GetAsValue (), item
, item
->GetParentPointer (), xmlns
, attr
, &v
, NULL
);
1431 virtual const char* GetUri () { return xmlns
; }
1435 XamlLoader::LookupObject (void *p
, Value
*top_level
, Value
*parent
, const char* xmlns
, const char* type_name
, bool create
, bool is_property
, Value
*value
)
1437 if (callbacks
.lookup_object
) {
1438 if (!vm_loaded
&& !LoadVM ())
1441 XamlCallbackData data
= XamlCallbackData (this, p
, top_level
);
1442 bool res
= callbacks
.lookup_object (&data
, parent
, xmlns
, type_name
, create
, is_property
, value
, &error
);
1450 XamlLoader::GetContentPropertyName (void *p
, Value
*top_level
, Value
*object
)
1452 if (callbacks
.get_content_property_name
) {
1454 XamlCallbackData data
= XamlCallbackData (this, p
, top_level
);
1455 return callbacks
.get_content_property_name (&data
, object
, &error
);
1461 XamlLoader::SetProperty (void *p
, Value
*top_level
, const char* xmlns
, Value
*target
, void *target_data
, Value
*target_parent
, const char* prop_xmlns
, const char *name
, Value
*value
, void* value_data
, int flags
)
1463 if (callbacks
.set_property
) {
1465 XamlCallbackData data
= XamlCallbackData (this, p
, top_level
, flags
);
1466 bool res
= callbacks
.set_property (&data
, xmlns
, target
, target_data
, target_parent
, prop_xmlns
, name
, value
, value_data
, &error
);
1468 if (error
.number
!= MoonError::NO_ERROR
) {
1469 parser_error ((XamlParserInfo
*) p
, ((XamlElementInstance
*) target_data
)->element_name
, NULL
, error
.code
, error
.message
);
1480 XamlLoader::AddChild (void *p
, Value
*top_level
, Value
*parent_parent
, bool parent_is_property
, const char* parent_xmlns
, Value
*parent
, void *parent_data
, Value
*child
, void *child_data
)
1482 if (callbacks
.add_child
) {
1484 XamlCallbackData data
= XamlCallbackData (this, p
, top_level
);
1485 bool res
= callbacks
.add_child (&data
, parent_parent
, parent_is_property
, parent_xmlns
, parent
, parent_data
, child
, child_data
, &error
);
1487 if (error
.number
!= MoonError::NO_ERROR
) {
1488 parser_error ((XamlParserInfo
*) p
, ((XamlElementInstance
*) child_data
)->element_name
, NULL
, error
.code
, error
.message
);
1497 XamlLoader::XamlLoader (const char *resourceBase
, const char* filename
, const char* str
, Surface
* surface
, XamlContext
*context
)
1499 Initialize (resourceBase
, filename
, str
, surface
, context
);
1502 XamlLoader::XamlLoader (const char* filename
, const char* str
, Surface
* surface
, XamlContext
*context
)
1504 Initialize (NULL
, filename
, str
, surface
, context
);
1508 XamlLoader::Initialize (const char *resourceBase
, const char* filename
, const char* str
, Surface
* surface
, XamlContext
*context
)
1510 this->filename
= g_strdup (filename
);
1511 this->resource_base
= g_strdup (resourceBase
);
1512 this->str
= g_strdup (str
);
1513 this->surface
= surface
;
1516 this->context
= context
;
1517 this->vm_loaded
= false;
1518 this->error_args
= NULL
;
1519 this->expanding_template
= false;
1520 this->template_owner
= NULL
;
1521 this->import_default_xmlns
= false;
1524 callbacks
= context
->internal
->callbacks
;
1525 this->vm_loaded
= true;
1528 if (!surface
&& debug_flags
& RUNTIME_DEBUG_XAML
) {
1529 printf ("XamlLoader::XamlLoader ('%s', '%s', %p): Initializing XamlLoader without a surface.\n",
1530 filename
, str
, surface
);
1535 XamlLoader::~XamlLoader ()
1538 g_free (resource_base
);
1546 error_args
->unref();
1550 XamlLoader::LoadVM ()
1556 xaml_loader_new (const char *resourceBase
, const char* filename
, const char* str
, Surface
* surface
)
1558 return new XamlLoader (resourceBase
, filename
, str
, surface
);
1562 xaml_loader_free (XamlLoader
* loader
)
1568 xaml_loader_set_callbacks (XamlLoader
* loader
, XamlLoaderCallbacks callbacks
)
1571 LOG_XAML ("Trying to set callbacks for a null object\n");
1575 loader
->callbacks
= callbacks
;
1576 loader
->vm_loaded
= true;
1580 namespace_for_prefix (gpointer key
, gpointer value
, gpointer user_data
)
1582 XamlNamespace
*ns
= (XamlNamespace
*) value
;
1583 const char *prefix
= (const char *) user_data
;
1585 return ns
->HasPrefix (prefix
);
1589 xaml_uri_for_prefix (void *parser
, char* prefix
)
1591 XamlParserInfo
*p
= (XamlParserInfo
*) parser
;
1593 XamlNamespace
*ns
= (XamlNamespace
*) g_hash_table_find (p
->namespace_map
, namespace_for_prefix
, prefix
);
1597 return g_strdup (ns
->GetUri ());
1601 // Called when we encounter an error. Note that memory ownership is taken for everything
1602 // except the message, this allows you to use g_strdup_printf when creating the error message
1605 parser_error (XamlParserInfo
*p
, const char *el
, const char *attr
, int error_code
, const char *format
, ...)
1614 // if parsing fails too early it's not safe (i.e. sigsegv) to call some functions, e.g. XML_GetCurrentLineNumber
1615 bool report_line_col
= (error_code
!= XML_ERROR_XML_DECL
);
1616 int line_number
= report_line_col
? XML_GetCurrentLineNumber (p
->parser
) : 0;
1617 int char_position
= report_line_col
? XML_GetCurrentColumnNumber (p
->parser
) : 0;
1619 va_start (args
, format
);
1620 message
= g_strdup_vprintf (format
, args
);
1623 p
->error_args
= new ParserErrorEventArgs (message
, p
->file_name
, line_number
, char_position
, error_code
, el
, attr
);
1627 LOG_XAML ("PARSER ERROR, STOPPING PARSING: (%d) %s line: %d char: %d\n", error_code
, message
,
1628 line_number
, char_position
);
1630 XML_StopParser (p
->parser
, FALSE
);
1634 expat_parser_error (XamlParserInfo
*p
, XML_Error expat_error
)
1636 // Already had an error
1640 LOG_XAML ("expat error is: %d\n", expat_error
);
1642 switch (expat_error
) {
1643 case XML_ERROR_DUPLICATE_ATTRIBUTE
:
1644 parser_error (p
, NULL
, NULL
, 7031, "wfc: unique attribute spec");
1646 case XML_ERROR_UNBOUND_PREFIX
:
1647 parser_error (p
, NULL
, NULL
, 7055, "undeclared prefix");
1649 case XML_ERROR_NO_ELEMENTS
:
1650 parser_error (p
, NULL
, NULL
, 7000, "unexpected end of input");
1652 case XML_ERROR_SYNTAX
:
1653 parser_error (p
, NULL
, NULL
, 2103, "syntax error");
1656 parser_error (p
, NULL
, NULL
, expat_error
, "Unhandled XML error %s", XML_ErrorString (expat_error
));
1662 start_element (void *data
, const char *el
, const char **attr
)
1664 XamlParserInfo
*p
= (XamlParserInfo
*) data
;
1665 XamlElementInfo
*elem
= NULL
;
1666 XamlElementInstance
*inst
;
1667 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
1669 if (!strcmp (el
, INTERNAL_IGNORABLE_ELEMENT
))
1672 if (p
->ShouldBeginBuffering ()) {
1673 p
->BeginBuffering ();
1677 if (p
->InBufferingMode ()) {
1678 if (!strcmp (p
->buffer_until_element
, el
))
1683 const char *dot
= strchr (el
, '.');
1685 elem
= p
->current_namespace
->FindElement (p
, el
, attr
, p
->hydrate_expecting
== NULL
);
1692 if (p
->hydrate_expecting
){
1694 Type::Kind expecting_type = p->hydrate_expecting->GetObjectType ();
1696 if (!types->IsSubclassOf (expecting_type, elem->GetKind ())) {
1697 parser_error (p, el, NULL, -1, "Invalid top-level element found %s, expecting %s", el,
1698 types->Find (expecting_type)->GetName ());
1703 inst
= elem
->CreateWrappedElementInstance (p
, p
->hydrate_expecting
);
1704 p
->hydrate_expecting
= NULL
;
1706 inst
= elem
->CreateElementInstance (p
);
1711 inst
->parent
= p
->current_element
;
1713 if (!p
->top_element
) {
1714 p
->top_element
= inst
;
1715 if (inst
->GetAsDependencyObject ())
1716 NameScope::SetNameScope (inst
->GetAsDependencyObject (), p
->namescope
);
1719 if (inst
->GetAsDependencyObject ())
1720 inst
->GetAsDependencyObject ()->SetIsBeingParsed (true);
1722 inst
->SetAttributes (p
, attr
);
1726 if (inst
->IsDependencyObject ()) {
1727 if (p
->current_element
){
1728 if (p
->current_element
->info
) {
1729 p
->current_element
->AddChild (p
, inst
);
1736 // it's actually valid (from SL point of view) to have <Ellipse.Triggers> inside a <Rectangle>
1737 // however we can't add properties to something bad, like a <Recta.gle> element
1738 XamlElementInfo
*prop_info
= NULL
;
1740 gchar
*prop_elem
= g_strndup (el
, dot
- el
);
1741 prop_info
= p
->current_element
->FindPropertyElement (p
, el
, dot
);
1745 if (prop_info
!= NULL
) {
1746 inst
= prop_info
->CreatePropertyElementInstance (p
, g_strdup (el
));
1747 inst
->parent
= p
->current_element
;
1749 if (attr
[0] != NULL
) {
1750 // It appears there is a bug in the error string but it matches the MS runtime
1751 parser_error (p
, el
, NULL
, 2018, "The element %s does not support attributes.", attr
[0]);
1755 if (prop_info
&& !strcmp (el
, "TextBox.Text"))
1756 prop_info
->SetIsCDataVerbatim (true);
1758 if (!p
->top_element
) {
1759 if (types
->IsSubclassOf (prop_info
->GetKind (), Type::COLLECTION
)) {
1760 XamlElementInstance
*wrap
= prop_info
->CreateElementInstance (p
);
1761 NameScope::SetNameScope (wrap
->GetAsDependencyObject (), p
->namescope
);
1762 p
->top_element
= wrap
;
1763 p
->current_element
= wrap
;
1768 g_warning ("Unknown element: %s.", el
);
1769 parser_error (p
, el
, NULL
, 2007, "Unknown element: %s.", el
);
1774 if (p
->current_element
) {
1775 p
->current_element
->children
->Append (inst
);
1777 p
->current_element
= inst
;
1779 if (elem
&& element_begins_buffering (elem
->GetKind ())) {
1780 p
->QueueBeginBuffering (g_strdup (el
), BUFFER_MODE_TEMPLATE
);
1785 allow_value_from_str_in_flush (XamlParserInfo
*p
, XamlElementInstance
*parent
)
1787 if (parent
== NULL
|| parent
->element_type
!= XamlElementInstance::PROPERTY
|| parent
->parent
== NULL
|| !parent
->parent
->IsDependencyObject ())
1790 if (parent
->info
->GetKind () == Type::OBJECT
)
1797 flush_char_data (XamlParserInfo
*p
)
1799 if (p
->InBufferingMode ())
1802 if (!p
->cdata
|| !p
->current_element
)
1805 if (p
->current_element
->info
->IsCDataVerbatim()) {
1806 p
->cdata
->str
= g_strstrip (p
->cdata
->str
);
1809 if (p
->current_element
->element_type
== XamlElementInstance::ELEMENT
) {
1810 if (!p
->current_element
->TrySetContentProperty (p
, p
->cdata
->str
) && p
->cdata_content
) {
1811 if (allow_value_from_str_in_flush (p
, p
->current_element
->parent
)) {
1813 if (value_from_str (p
->current_element
->info
->GetKind (), NULL
, p
->cdata
->str
, &v
)) {
1814 p
->current_element
->SetValue (v
);
1818 parser_error (p
, p
->current_element
->element_name
, NULL
, 2011,
1819 "%s does not support text content.", p
->current_element
->element_name
);
1821 } else if (p
->current_element
->element_type
== XamlElementInstance::PROPERTY
) {
1822 if (p
->cdata_content
&& p
->current_element
->parent
&& !p
->current_element
->parent
->SetProperty (p
, p
->current_element
, p
->cdata
->str
)) {
1823 parser_error (p
, p
->current_element
->element_name
, NULL
, 2011,
1824 "%s does not support text content.", p
->current_element
->element_name
);
1830 g_string_free (p
->cdata
, TRUE
);
1831 p
->cdata_content
= false;
1837 element_begins_buffering (Type::Kind kind
)
1839 return Type::IsSubclassOf (Deployment::GetCurrent (), kind
, Type::FRAMEWORKTEMPLATE
);
1843 is_default_namespace (gpointer key
, gpointer value
, gpointer user_data
)
1845 return value
== default_namespace
;
1849 start_element_handler (void *data
, const char *el
, const char **attr
)
1851 XamlParserInfo
*p
= (XamlParserInfo
*) data
;
1856 char **name
= g_strsplit (el
, "|", -1);
1857 XamlNamespace
*next_namespace
= NULL
;
1858 char *element
= NULL
;
1860 if (g_strv_length (name
) == 2) {
1861 // Find the proper namespace for our next element
1862 next_namespace
= (XamlNamespace
*) g_hash_table_lookup (p
->namespace_map
, name
[0]);
1866 if (!next_namespace
&& p
->implicit_default_namespace
) {
1867 // Use the default namespace for the next element
1868 next_namespace
= default_namespace
;
1870 } else if (!next_namespace
) {
1871 if (!g_hash_table_find (p
->namespace_map
, is_default_namespace
, NULL
))
1872 return parser_error (p
, el
, NULL
, 2263, "AG_E_PARSER_MISSING_DEFAULT_NAMESPACE");
1875 if (next_namespace
&& next_namespace
->is_ignored
) {
1876 p
->current_namespace
= next_namespace
;
1877 if (!p
->InBufferingMode ())
1878 p
->QueueBeginBuffering (g_strdup (element
), BUFFER_MODE_IGNORE
);
1880 start_element (data
, element
, attr
); // This will force the buffering to start/build depth if needed
1884 p
->next_element
= element
;
1886 flush_char_data (p
);
1888 // Now update our namespace
1889 p
->current_namespace
= next_namespace
;
1891 if (!p
->current_namespace
&& !p
->InBufferingMode ()) {
1893 parser_error (p
, name
[1], NULL
, -1, "No handlers available for namespace: '%s' (%s)\n", name
[0], el
);
1895 parser_error (p
, name
[1], NULL
, -1, "No namespace mapping available for element: '%s'\n", el
);
1901 p
->next_element
= NULL
;
1902 start_element (data
, element
, attr
);
1908 get_element_name (XamlParserInfo
* p
, const char *el
)
1910 char **names
= g_strsplit (el
, "|", -1);
1911 char *name
= g_strdup (names
[g_strv_length (names
) - 1]);
1919 create_resource_list (XamlParserInfo
*p
)
1921 GSList
*list
= NULL
;
1922 XamlElementInstance
*walk
= p
->current_element
;
1924 Types
* types
= Deployment::GetCurrent ()->GetTypes ();
1926 if (walk
->element_type
== XamlElementInstance::ELEMENT
&& types
->IsSubclassOf (walk
->info
->GetKind (), Type::FRAMEWORKELEMENT
)) {
1927 FrameworkElement
*fwe
= (FrameworkElement
*)walk
->GetAsDependencyObject ();
1928 if (g_slist_index (list
, fwe
) == -1)
1929 list
= g_slist_prepend (list
, fwe
);
1931 if (walk
->element_type
== XamlElementInstance::ELEMENT
&& types
->IsSubclassOf (walk
->info
->GetKind (), Type::RESOURCE_DICTIONARY
)) {
1932 ResourceDictionary
*rd
= (ResourceDictionary
*) walk
->GetAsDependencyObject ();
1933 if (g_slist_index (list
, rd
) == -1)
1934 list
= g_slist_prepend (list
, walk
->GetAsDependencyObject ());
1936 walk
= walk
->parent
;
1939 list
= g_slist_reverse (list
);
1943 static XamlContext
*
1944 create_xaml_context (XamlParserInfo
*p
, FrameworkTemplate
*template_
, XamlContext
*parent_context
)
1946 GSList
*resources
= create_resource_list (p
);
1947 XamlContextInternal
*ic
= new XamlContextInternal (p
->loader
->callbacks
, p
->GetTopElementPtr (), template_
, p
->namespace_map
, resources
, parent_context
? parent_context
->internal
: NULL
);
1948 return new XamlContext (ic
);
1952 end_element_handler (void *data
, const char *el
)
1954 XamlParserInfo
*p
= (XamlParserInfo
*) data
;
1955 DependencyObject
*obj
;
1957 if (!strcmp (el
, INTERNAL_IGNORABLE_ELEMENT
))
1963 if (!p
->current_element
) {
1964 g_warning ("p->current_element == NULL, current_element = %p (%s)\n",
1965 p
->current_element
, p
->current_element
? p
->current_element
->element_name
: "<NULL>");
1969 if (p
->InBufferingMode ()) {
1970 char* name
= get_element_name (p
, el
);
1971 if (!strcmp (p
->buffer_until_element
, name
)) {
1974 if (p
->buffer_depth
== 0) {
1975 if (p
->buffer_mode
== BUFFER_MODE_TEMPLATE
) {
1976 // OK we are done buffering, the element we are buffering for
1977 FrameworkTemplate
* template_
= (FrameworkTemplate
*) p
->current_element
->GetAsDependencyObject ();
1979 char* buffer
= p
->ClearBuffer ();
1981 XamlContext
*context
= create_xaml_context (p
, template_
, p
->loader
->GetContext());
1983 if (p
->validate_templates
) {
1984 p
->ValidateTemplate (buffer
, context
, template_
);
1990 template_
->SetXamlBuffer (context
, buffer
);
1991 p
->current_element
= p
->current_element
->parent
;
1992 } else if (p
->buffer_mode
== BUFFER_MODE_IGNORE
) {
1993 // For now we'll actually keep/clear this buffer because it makes testing easier
1994 char *buffer
= p
->ClearBuffer ();
2004 switch (p
->current_element
->element_type
) {
2005 case XamlElementInstance::ELEMENT
:
2007 p
->current_element
->SetDelayedProperties (p
);
2008 flush_char_data (p
);
2010 // according to http://blogs.msdn.com/devdave/archive/2008/10/11/control-lifecycle.aspx
2011 // default styles are apply when the end tag is read.
2013 if (p
->current_element
->IsDependencyObject () &&
2014 p
->current_element
->GetAsDependencyObject() &&
2015 p
->current_element
->GetAsDependencyObject()->Is(Type::CONTROL
)) {
2017 Control
*control
= (Control
*)p
->current_element
->GetAsDependencyObject();
2018 ManagedTypeInfo
*key
= control
->GetDefaultStyleKey ();
2021 if (Application::GetCurrent () == NULL
)
2022 g_warning ("attempting to use a null application applying default style while parsing.");
2024 Application::GetCurrent()->ApplyDefaultStyle (control
, key
);
2027 else if (!p
->current_element
->IsDependencyObject ()) {
2029 if (p
->current_element
->parent
)
2030 p
->current_element
->parent
->AddChild (p
, p
->current_element
);
2033 case XamlElementInstance::PROPERTY
: {
2034 List::Node
*walk
= p
->current_element
->children
->First ();
2036 XamlElementInstance
*child
= (XamlElementInstance
*) walk
;
2037 if (p
->current_element
->parent
) {
2038 p
->current_element
->parent
->SetProperty (p
, p
->current_element
, child
);
2042 flush_char_data (p
);
2047 if ((obj
= p
->current_element
->GetAsDependencyObject ()))
2048 obj
->SetIsBeingParsed (false);
2050 p
->current_element
= p
->current_element
->parent
;
2054 char_data_handler (void *data
, const char *in
, int inlen
)
2056 XamlParserInfo
*p
= (XamlParserInfo
*) data
;
2057 register const char *inptr
= in
;
2058 const char *inend
= in
+ inlen
;
2061 if (p
->InBufferingMode ())
2067 if (p
->current_element
&& p
->current_element
->info
->IsCDataVerbatim()) {
2069 p
->cdata
= g_string_new ("");
2071 g_string_append_len (p
->cdata
, inptr
, inlen
);
2072 p
->cdata_content
= true;
2077 p
->cdata
= g_string_new ("");
2079 if (g_ascii_isspace (*inptr
)) {
2080 g_string_append_c (p
->cdata
, ' ');
2083 while (inptr
< inend
&& g_ascii_isspace (*inptr
))
2089 } else if (g_ascii_isspace (p
->cdata
->str
[p
->cdata
->len
- 1])) {
2090 // previous cdata chunk ended with lwsp, skip over leading lwsp for this chunk
2091 while (inptr
< inend
&& g_ascii_isspace (*inptr
))
2095 while (inptr
< inend
) {
2097 while (inptr
< inend
&& !g_ascii_isspace (*inptr
))
2100 if (inptr
> start
) {
2101 g_string_append_len (p
->cdata
, start
, inptr
- start
);
2102 p
->cdata_content
= true;
2105 if (inptr
< inend
) {
2106 g_string_append_c (p
->cdata
, ' ');
2109 while (inptr
< inend
&& g_ascii_isspace (*inptr
))
2116 start_namespace_handler (void *data
, const char *prefix
, const char *uri
)
2118 XamlParserInfo
*p
= (XamlParserInfo
*) data
;
2120 if (p
->InBufferingMode ())
2126 if (p
->loader
!= NULL
&& p
->loader
->callbacks
.import_xaml_xmlns
!= NULL
) {
2128 XamlCallbackData data
= XamlCallbackData (p
->loader
, p
, p
->GetTopElementPtr ());
2129 if (!p
->loader
->callbacks
.import_xaml_xmlns (&data
, uri
, &error
))
2130 return parser_error (p
, p
->current_element
? p
->current_element
->element_name
: NULL
, prefix
, 2005, "Unknown namespace %s", uri
);
2133 for (int i
= 0; default_namespace_names
[i
]; i
++) {
2134 if (!strcmp (default_namespace_names
[i
], uri
)) {
2135 g_hash_table_insert (p
->namespace_map
, g_strdup (uri
), default_namespace
);
2140 if (!strcmp (X_NAMESPACE_URI
, uri
)){
2141 g_hash_table_insert (p
->namespace_map
, g_strdup (uri
), x_namespace
);
2142 } else if (!strcmp (PRIMITIVE_NAMESPACE_URI
, uri
)) {
2143 PrimitiveNamespace
*pn
= new PrimitiveNamespace (g_strdup (prefix
));
2144 g_hash_table_insert (p
->namespace_map
, g_strdup (uri
), pn
);
2145 p
->AddCreatedNamespace (pn
);
2146 } else if (!strcmp (MC_IGNORABLE_NAMESPACE_URI
, uri
)) {
2147 MCIgnorableNamespace
*mc
= new MCIgnorableNamespace (g_strdup (prefix
));
2148 g_hash_table_insert (p
->namespace_map
, g_strdup (uri
), mc
);
2149 p
->AddCreatedNamespace (mc
);
2152 return parser_error (p
, (p
->current_element
? p
->current_element
->element_name
: NULL
), prefix
, -1,
2153 "No managed element callback installed to handle %s", uri
);
2157 parser_error (p
, (p
->current_element
? p
->current_element
->element_name
: NULL
), NULL
, 2262,
2158 "AG_E_PARSER_NAMESPACE_NOT_SUPPORTED");
2162 XamlNamespace
*ns
= (XamlNamespace
*) g_hash_table_lookup (p
->namespace_map
, uri
);
2165 ns
->AddPrefix (prefix
);
2169 ManagedNamespace
*c
= new ManagedNamespace (g_strdup (uri
), g_strdup (prefix
));
2170 g_hash_table_insert (p
->namespace_map
, g_strdup (c
->xmlns
), c
);
2171 p
->AddCreatedNamespace (c
);
2176 start_doctype_handler (void *data
,
2177 const XML_Char
*doctype_name
,
2178 const XML_Char
*sysid
,
2179 const XML_Char
*pubid
,
2180 int has_internal_subset
)
2182 XamlParserInfo
*p
= (XamlParserInfo
*) data
;
2184 if (p
->InBufferingMode ())
2188 return parser_error (p
, NULL
, NULL
, 7050, "DTD was found but is prohibited");
2191 return parser_error (p
, NULL
, NULL
, 7016, "incorrect document syntax.");
2195 add_default_namespaces (XamlParserInfo
*p
, bool sl_xmlns
)
2198 p
->implicit_default_namespace
= true;
2199 g_hash_table_insert (p
->namespace_map
, g_strdup ("http://schemas.microsoft.com/winfx/2006/xaml/presentation"), default_namespace
);
2200 g_hash_table_insert (p
->namespace_map
, g_strdup (X_NAMESPACE_URI
), x_namespace
);
2202 g_hash_table_insert (p
->namespace_map
, g_strdup (XML_NAMESPACE_URI
), xml_namespace
);
2206 print_tree (XamlElementInstance
*el
, int depth
)
2209 if (debug_flags
& RUNTIME_DEBUG_XAML
) {
2210 for (int i
= 0; i
< depth
; i
++)
2213 const char *name
= NULL
;
2216 printf (" -null- \n");
2220 if (el
->element_type
== XamlElementInstance::ELEMENT
&& el
->IsDependencyObject ())
2221 name
= el
->GetAsDependencyObject ()->GetName ();
2222 printf ("%s (%s) (%p) (%s)\n", el
->element_name
, name
? name
: "-no name-", el
->parent
, el
->element_type
== XamlElementInstance::PROPERTY
? "PROPERTY" : "ELEMENT");
2224 for (List::Node
*walk
= el
->children
->First (); walk
!= NULL
; walk
= walk
->next
) {
2225 XamlElementInstance
*el
= (XamlElementInstance
*) walk
;
2226 print_tree (el
, depth
+ 1);
2233 xaml_parse_xmlns (const char* xmlns
, char** type_name
, char** ns
, char** assembly
)
2235 const char delimiters
[] = ";";
2237 char* buffer
= g_strdup (xmlns
);
2243 decl
= strtok (buffer
, delimiters
);
2244 while (decl
!= NULL
) {
2245 if (strstr (decl
, "clr-namespace:") == decl
) {
2248 *ns
= g_strdup (decl
+ 14);
2249 } else if (strstr (decl
, "assembly=") == decl
) {
2252 *assembly
= g_strdup (decl
+ 9);
2255 g_free (*type_name
);
2256 *type_name
= g_strdup (decl
);
2259 decl
= strtok (NULL
, delimiters
);
2265 XamlLoader::CreateFromFile (const char *xaml_file
, bool create_namescope
,
2266 Type::Kind
*element_type
)
2269 XamlParserInfo
*parser_info
= NULL
;
2270 XML_Parser p
= NULL
;
2271 bool first_read
= true;
2272 const char *inptr
, *inend
;
2277 LOG_XAML ("attemtping to load xaml file: %s\n", xaml_file
);
2279 stream
= new TextStream ();
2280 if (!stream
->OpenFile (xaml_file
, false)) {
2281 LOG_XAML ("can not open file\n");
2282 goto cleanup_and_return
;
2285 if (!(p
= XML_ParserCreateNS ("UTF-8", '|'))) {
2286 LOG_XAML ("can not create parser\n");
2287 goto cleanup_and_return
;
2290 parser_info
= new XamlParserInfo (p
, xaml_file
);
2292 parser_info
->namescope
->SetTemporary (!create_namescope
);
2294 parser_info
->loader
= this;
2296 // TODO: This is just in here temporarily, to make life less difficult for everyone
2297 // while we are developing.
2298 add_default_namespaces (parser_info
, false);
2300 XML_SetUserData (p
, parser_info
);
2302 XML_SetElementHandler (p
, start_element_handler
, end_element_handler
);
2303 XML_SetCharacterDataHandler (p
, char_data_handler
);
2304 XML_SetNamespaceDeclHandler(p
, start_namespace_handler
, NULL
);
2305 XML_SetDoctypeDeclHandler(p
, start_doctype_handler
, NULL
);
2308 XML_SetProcessingInstructionHandler (p, proc_handler);
2311 while ((nread
= stream
->Read (buffer
, sizeof (buffer
))) >= 0) {
2315 if (first_read
&& nread
> 0) {
2316 // Remove preceding white space
2317 inend
= buffer
+ nread
;
2319 while (inptr
< inend
&& g_ascii_isspace (*inptr
))
2325 n
= (inend
- inptr
);
2329 parser_info
->SetXmlBuffer (inptr
);
2330 if (!XML_Parse (p
, inptr
, n
, nread
== 0)) {
2331 expat_parser_error (parser_info
, XML_GetErrorCode (p
));
2332 goto cleanup_and_return
;
2339 print_tree (parser_info
->top_element
, 0);
2341 if (parser_info
->top_element
) {
2342 res
= parser_info
->top_element
->GetAsValue ();
2343 // We want a copy because the old one is going to be deleted
2344 res
= new Value (*res
);
2347 *element_type
= parser_info
->top_element
->info
->GetKind ();
2349 if (parser_info
->error_args
) {
2350 *element_type
= Type::INVALID
;
2351 goto cleanup_and_return
;
2358 error_args
= new ParserErrorEventArgs ("Error opening xaml file", xaml_file
, 0, 0, 1, "", "");
2359 else if (parser_info
->error_args
) {
2360 error_args
= parser_info
->error_args
;
2376 XamlLoader::CreateFromString (const char *xaml
, bool create_namescope
, Type::Kind
*element_type
, int flags
)
2378 return HydrateFromString (xaml
, NULL
, create_namescope
, element_type
, flags
);
2382 value_to_dependency_object (Value
*value
)
2384 if (!value
|| !value
->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT
))
2386 return value
->AsDependencyObject ();
2390 XamlLoader::CreateDependencyObjectFromFile (const char *xaml
, bool create_namescope
, Type::Kind
*element_type
)
2392 return value_to_dependency_object (CreateFromFile (xaml
, create_namescope
, element_type
));
2396 XamlLoader::CreateDependencyObjectFromString (const char *xaml
, bool create_namescope
, Type::Kind
*element_type
)
2398 return value_to_dependency_object (CreateFromString (xaml
, create_namescope
, element_type
, IMPORT_DEFAULT_XMLNS
));
2402 * Hydrates an existing DependencyObject (@object) with the contents from the @xaml
2406 XamlLoader::HydrateFromString (const char *xaml
, Value
*object
, bool create_namescope
, Type::Kind
*element_type
, int flags
)
2408 XML_Parser p
= XML_ParserCreateNS ("utf-8", '|');
2409 XamlParserInfo
*parser_info
= NULL
;
2411 char *start
= (char*)xaml
;
2412 char *prepend
= NULL
;
2413 char *append
= NULL
;
2414 char * inputs
[4] = {NULL
, NULL
, NULL
, NULL
};
2419 LOG_XAML ("can not create parser\n");
2420 goto cleanup_and_return
;
2429 sprintf (filename
, "createFromXaml.%d.xaml", id
++);
2430 if ((fp
= fopen (filename
, "wt")) != NULL
) {
2431 fwrite (xaml
, strlen (xaml
), 1, fp
);
2437 parser_info
= new XamlParserInfo (p
, NULL
);
2439 parser_info
->namescope
->SetTemporary (!create_namescope
);
2441 parser_info
->loader
= this;
2442 parser_info
->validate_templates
= (flags
& VALIDATE_TEMPLATES
) == VALIDATE_TEMPLATES
;
2445 // If we are hydrating, we are not null
2447 if (object
!= NULL
) {
2448 parser_info
->hydrate_expecting
= object
;
2449 parser_info
->hydrating
= true;
2450 if (Type::IsSubclassOf (parser_info
->deployment
, object
->GetKind (), Type::DEPENDENCY_OBJECT
)) {
2451 DependencyObject
*dob
= object
->AsDependencyObject ();
2452 dob
->SetIsAttached (true);
2453 dob
->SetResourceBase (GetResourceBase());
2456 parser_info
->hydrate_expecting
= NULL
;
2457 parser_info
->hydrating
= false;
2460 // from_str gets the default namespaces implictly added
2461 add_default_namespaces (parser_info
, (flags
& IMPORT_DEFAULT_XMLNS
) == IMPORT_DEFAULT_XMLNS
);
2463 XML_SetUserData (p
, parser_info
);
2465 XML_SetElementHandler (p
, start_element_handler
, end_element_handler
);
2466 XML_SetCharacterDataHandler (p
, char_data_handler
);
2467 XML_SetNamespaceDeclHandler(p
, start_namespace_handler
, NULL
);
2468 XML_SetDoctypeDeclHandler(p
, start_doctype_handler
, NULL
);
2471 XML_SetProcessingInstructionHandler (p, proc_handler);
2475 prepend
= context
->internal
->CreateIgnorableTagOpen ();
2476 append
= context
->internal
->CreateIgnorableTagClose ();
2478 inputs
[0] = prepend
;
2480 inputs
[2] = append
;
2483 for (int i
= 0; inputs
[i
]; i
++) {
2484 char *start
= inputs
[i
];
2486 // don't freak out if the <?xml ... ?> isn't on the first line (see #328907)
2487 while (g_ascii_isspace (*start
))
2490 parser_info
->SetXmlBuffer (start
);
2491 if (!XML_Parse (p
, start
, strlen (start
), inputs
[i
+ 1] == NULL
)) {
2492 expat_parser_error (parser_info
, XML_GetErrorCode (p
));
2493 LOG_XAML ("error parsing: %s\n\n", xaml
);
2494 goto cleanup_and_return
;
2498 print_tree (parser_info
->top_element
, 0);
2500 if (parser_info
->top_element
) {
2501 if (is_legal_top_level_kind (parser_info
->top_element
->info
->GetKind ())) {
2502 res
= parser_info
->top_element
->GetAsValue ();
2503 res
= new Value (*res
);
2504 if (res
->Is (parser_info
->deployment
, Type::DEPENDENCY_OBJECT
) && object
) {
2505 DependencyObject
*dob
= res
->AsDependencyObject ();
2507 dob
->SetIsHydratedFromXaml (parser_info
->hydrating
);
2512 *element_type
= parser_info
->top_element
->info
->GetKind ();
2514 if (!res
&& !parser_info
->error_args
)
2515 parser_info
->error_args
= new ParserErrorEventArgs ("No DependencyObject found", "", 0, 0, 1, "", "");
2517 if (parser_info
->error_args
) {
2521 *element_type
= Type::INVALID
;
2522 goto cleanup_and_return
;
2528 if (parser_info
->error_args
) {
2529 error_args
= parser_info
->error_args
;
2530 printf ("Could not parse element %s, attribute %s, error: %s\n",
2531 error_args
->xml_element
,
2532 error_args
->xml_attribute
,
2533 error_args
->GetErrorMessage());
2549 XamlLoader::CreateFromFileWithError (const char *xaml_file
, bool create_namescope
, Type::Kind
*element_type
, MoonError
*error
)
2551 Value
*res
= CreateFromFile (xaml_file
, create_namescope
, element_type
);
2552 if (error_args
&& error_args
->GetErrorCode () != -1)
2553 MoonError::FillIn (error
, error_args
);
2558 XamlLoader::CreateFromStringWithError (const char *xaml
, bool create_namescope
, Type::Kind
*element_type
, int flags
, MoonError
*error
)
2560 Value
*res
= CreateFromString (xaml
, create_namescope
, element_type
, flags
);
2561 if (error_args
&& error_args
->GetErrorCode () != -1)
2562 MoonError::FillIn (error
, error_args
);
2567 XamlLoader::HydrateFromStringWithError (const char *xaml
, Value
*object
, bool create_namescope
, Type::Kind
*element_type
, int flags
, MoonError
*error
)
2569 Value
*res
= HydrateFromString (xaml
, object
, create_namescope
, element_type
, flags
);
2570 if (error_args
&& error_args
->GetErrorCode () != -1)
2571 MoonError::FillIn (error
, error_args
);
2576 parse_int (const char **pp
, const char *end
)
2578 const char *p
= *pp
;
2580 if (optional
&& AtEnd
)
2587 while (p
<= end
&& g_ascii_isdigit (*p
)) {
2588 res
= res
* 10 + *p
- '0';
2603 parse_ticks (const char **pp
, const char *end
)
2605 gint64 mag
= 1000000;
2607 bool digitseen
= false;
2609 const char *p
= *pp
;
2611 while (mag
> 0 && p
<= end
&& g_ascii_isdigit (*p
)) {
2612 res
= res
+ (*p
- '0') * mag
;
2628 time_span_from_str (const char *str
, TimeSpan
*res
)
2630 const char *end
= str
+ strlen (str
);
2633 bool negative
= false;
2647 days
= parse_int (&p
, end
);
2651 hours
= parse_int (&p
, end
);
2659 minutes
= parse_int (&p
, end
);
2661 seconds
= parse_int (&p
, end
);
2664 ticks
= parse_ticks (&p
, end
);
2670 gint64 t
= (days
* 86400) + (hours
* 3600) + (minutes
* 60) + seconds
;
2673 *res
= negative
? (-t
- ticks
) : (t
+ ticks
);
2679 repeat_behavior_from_str (const char *str
, RepeatBehavior
*res
)
2681 if (!g_ascii_strcasecmp ("Forever", str
)) {
2682 *res
= RepeatBehavior::Forever
;
2686 // check for "<float>x".
2688 // XXX more validation work is needed here.. but how do we
2690 const char *x
= strchr (str
, 'x');
2692 if (*(x
+ 1) != '\0') {
2698 double d
= g_ascii_strtod (str
, &endptr
);
2700 if (errno
|| endptr
== str
)
2703 *res
= RepeatBehavior (d
);
2708 /* XXX RepeatBehavior='XX:XX:XX' syntax is NOT correctly supported by
2709 Silverlight 1.0 (most likely a bug). It works fine in Silverlight 2.0
2710 though. We currently stick to the 2.0 behavior, not replicating the bug
2714 if (!time_span_from_str (str
, &t
))
2717 *res
= RepeatBehavior (t
);
2723 duration_from_str (const char *str
, Duration
*res
)
2725 if (!g_ascii_strcasecmp ("Automatic", str
)) {
2726 *res
= Duration::Automatic
;
2730 if (!g_ascii_strcasecmp ("Forever", str
)) {
2731 *res
= Duration::Forever
;
2736 if (!time_span_from_str (str
, &ts
))
2739 *res
= Duration (ts
);
2744 keytime_from_str (const char *str
, KeyTime
*res
)
2746 if (!g_ascii_strcasecmp ("Uniform", str
)) {
2747 *res
= KeyTime::Uniform
;
2751 if (!g_ascii_strcasecmp ("Paced", str
)) {
2752 *res
= KeyTime::Paced
;
2756 /* check for a percentage first */
2757 const char *last
= str
+ strlen(str
) - 1;
2760 double pct
= g_ascii_strtod (str
, &ep
);
2762 *res
= KeyTime (pct
);
2768 if (!time_span_from_str (str
, &ts
))
2771 *res
= KeyTime (ts
);
2776 key_spline_from_str (const char *str
, KeySpline
**res
)
2778 PointCollection
*pts
= PointCollection::FromStr (str
);
2783 if (pts
->GetCount () != 2) {
2788 *res
= new KeySpline (*pts
->GetValueAt (0)->AsPoint (), *pts
->GetValueAt (1)->AsPoint ());
2796 matrix_from_str (const char *str
)
2798 if (!g_ascii_strcasecmp ("Identity", str
)) {
2799 return new Matrix ();
2802 DoubleCollection
*values
= DoubleCollection::FromStr (str
);
2806 return new Matrix ();
2808 if (values
->GetCount () < 6) {
2813 matrix
= new Matrix ();
2814 matrix
->SetM11 (values
->GetValueAt (0)->AsDouble ());
2815 matrix
->SetM12 (values
->GetValueAt (1)->AsDouble ());
2816 matrix
->SetM21 (values
->GetValueAt (2)->AsDouble ());
2817 matrix
->SetM22 (values
->GetValueAt (3)->AsDouble ());
2818 matrix
->SetOffsetX (values
->GetValueAt (4)->AsDouble ());
2819 matrix
->SetOffsetY (values
->GetValueAt (5)->AsDouble ());
2827 matrix3d_from_str (const char *str
)
2829 if (!g_ascii_strcasecmp ("Identity", str
)) {
2830 return new Matrix3D ();
2833 DoubleCollection
*values
= DoubleCollection::FromStr (str
);
2837 return new Matrix3D ();
2839 if (values
->GetCount () < 12) {
2844 matrix
= new Matrix3D ();
2845 matrix
->SetM11 (values
->GetValueAt (0)->AsDouble ());
2846 matrix
->SetM12 (values
->GetValueAt (1)->AsDouble ());
2847 matrix
->SetM13 (values
->GetValueAt (2)->AsDouble ());
2848 matrix
->SetM13 (values
->GetValueAt (3)->AsDouble ());
2849 matrix
->SetM21 (values
->GetValueAt (4)->AsDouble ());
2850 matrix
->SetM22 (values
->GetValueAt (5)->AsDouble ());
2851 matrix
->SetM23 (values
->GetValueAt (6)->AsDouble ());
2852 matrix
->SetM24 (values
->GetValueAt (7)->AsDouble ());
2853 matrix
->SetM31 (values
->GetValueAt (8)->AsDouble ());
2854 matrix
->SetM32 (values
->GetValueAt (9)->AsDouble ());
2855 matrix
->SetM33 (values
->GetValueAt (10)->AsDouble ());
2856 matrix
->SetM34 (values
->GetValueAt (11)->AsDouble ());
2857 matrix
->SetOffsetX (values
->GetValueAt (12)->AsDouble ());
2858 matrix
->SetOffsetY (values
->GetValueAt (13)->AsDouble ());
2859 matrix
->SetOffsetZ (values
->GetValueAt (14)->AsDouble ());
2860 matrix
->SetM44 (values
->GetValueAt (15)->AsDouble ());
2868 grid_length_from_str (const char *str
, GridLength
*grid_length
)
2870 if (IS_NULL_OR_EMPTY (str
)) {
2871 *grid_length
= GridLength (0.0, GridUnitTypePixel
);
2875 if (str
[0] == '*') {
2876 *grid_length
= GridLength (1.0, GridUnitTypeStar
);
2880 // unit tests shows that "Auto", "auto", "aUtO"... all works
2881 if (!g_ascii_strcasecmp (str
, "Auto")) {
2882 *grid_length
= GridLength ();
2888 double d
= g_ascii_strtod (str
, &endptr
);
2890 if (errno
|| endptr
== str
)
2893 *grid_length
= GridLength (d
, *endptr
== '*' ? GridUnitTypeStar
: GridUnitTypePixel
);
2902 while (*inptr
&& !g_ascii_isalnum (*inptr
) && *inptr
!= '.' && *inptr
!= '-' && *inptr
!= '+')
2903 inptr
= g_utf8_next_char (inptr
);
2909 get_point (Point
*p
, char **in
)
2911 char *end
, *inptr
= *in
;
2914 x
= g_ascii_strtod (inptr
, &end
);
2919 while (g_ascii_isspace (*inptr
))
2925 while (g_ascii_isspace (*inptr
))
2928 y
= g_ascii_strtod (inptr
, &end
);
2941 make_relative (const Point
*cp
, Point
*mv
)
2948 more_points_available (char **in
)
2952 while (g_ascii_isspace (*inptr
) || *inptr
== ',')
2957 return (g_ascii_isdigit (*inptr
) || *inptr
== '.' || *inptr
== '-' || *inptr
== '+');
2961 geometry_from_str (const char *str
)
2963 char *inptr
= (char *) str
;
2964 Point cp
= Point (0, 0);
2965 Point cp1
, cp2
, cp3
;
2968 PathGeometry
*pg
= NULL
;
2969 FillRule fill_rule
= FillRuleEvenOdd
;
2970 bool cbz
= false; // last figure is a cubic bezier curve
2971 bool qbz
= false; // last figure is a quadratic bezier curve
2972 Point cbzp
, qbzp
; // points needed to create "smooth" beziers
2974 moon_path
*path
= moon_path_new (10);
2977 if (g_ascii_isspace (*inptr
))
2983 bool relative
= false;
2986 inptr
= g_utf8_next_char (inptr
);
2994 fill_rule
= FillRuleEvenOdd
;
2995 else if (*inptr
== '1')
2996 fill_rule
= FillRuleNonzero
;
2998 // FIXME: else it's a bad value and nothing should be rendered
2999 goto bad_pml
; // partial: only this Path won't be rendered
3001 inptr
= g_utf8_next_char (inptr
);
3006 if (!get_point (&cp1
, &inptr
))
3010 make_relative (&cp
, &cp1
);
3013 moon_move_to (path
, cp1
.x
, cp1
.y
);
3015 start
.x
= cp
.x
= cp1
.x
;
3016 start
.y
= cp
.y
= cp1
.y
;
3019 while (more_points_available (&inptr
)) {
3020 if (!get_point (&cp1
, &inptr
))
3024 make_relative (&cp
, &cp1
);
3026 moon_line_to (path
, cp1
.x
, cp1
.y
);
3038 while (more_points_available (&inptr
)) {
3039 if (!get_point (&cp1
, &inptr
))
3043 make_relative (&cp
, &cp1
);
3045 moon_line_to (path
, cp1
.x
, cp1
.y
);
3060 double x
= g_ascii_strtod (inptr
, &end
);
3068 cp
= Point (x
, cp
.y
);
3070 moon_line_to (path
, cp
.x
, cp
.y
);
3079 double y
= g_ascii_strtod (inptr
, &end
);
3087 cp
= Point (cp
.x
, y
);
3089 moon_line_to (path
, cp
.x
, cp
.y
);
3098 while (more_points_available (&inptr
)) {
3099 if (!get_point (&cp1
, &inptr
))
3103 make_relative (&cp
, &cp1
);
3107 if (!get_point (&cp2
, &inptr
))
3111 make_relative (&cp
, &cp2
);
3115 if (!get_point (&cp3
, &inptr
))
3119 make_relative (&cp
, &cp3
);
3123 moon_curve_to (path
, cp1
.x
, cp1
.y
, cp2
.x
, cp2
.y
, cp3
.x
, cp3
.y
);
3140 while (more_points_available (&inptr
)) {
3141 if (!get_point (&cp2
, &inptr
))
3145 make_relative (&cp
, &cp2
);
3149 if (!get_point (&cp3
, &inptr
))
3153 make_relative (&cp
, &cp3
);
3156 cp1
.x
= 2 * cp
.x
- cbzp
.x
;
3157 cp1
.y
= 2 * cp
.y
- cbzp
.y
;
3161 moon_curve_to (path
, cp1
.x
, cp1
.y
, cp2
.x
, cp2
.y
, cp3
.x
, cp3
.y
);
3178 while (more_points_available (&inptr
)) {
3179 if (!get_point (&cp1
, &inptr
))
3183 make_relative (&cp
, &cp1
);
3187 if (!get_point (&cp2
, &inptr
))
3191 make_relative (&cp
, &cp2
);
3195 moon_quad_curve_to (path
, cp1
.x
, cp1
.y
, cp2
.x
, cp2
.y
);
3210 while (more_points_available (&inptr
)) {
3211 if (!get_point (&cp2
, &inptr
))
3215 make_relative (&cp
, &cp2
);
3218 cp1
.x
= 2 * cp
.x
- qbzp
.x
;
3219 cp1
.y
= 2 * cp
.y
- qbzp
.y
;
3223 moon_quad_curve_to (path
, cp1
.x
, cp1
.y
, cp2
.x
, cp2
.y
);
3240 while (more_points_available (&inptr
)) {
3241 if (!get_point (&cp1
, &inptr
))
3246 double angle
= g_ascii_strtod (inptr
, &end
);
3253 int is_large
= strtol (inptr
, &end
, 10);
3260 int sweep
= strtol (inptr
, &end
, 10);
3267 if (!get_point (&cp2
, &inptr
))
3271 make_relative (&cp
, &cp2
);
3273 moon_arc_to (path
, cp1
.x
, cp1
.y
, angle
, is_large
, sweep
, cp2
.x
, cp2
.y
);
3285 moon_line_to (path
, start
.x
, start
.y
);
3286 moon_close_path (path
);
3287 moon_move_to (path
, start
.x
, start
.y
);
3298 pg
= new PathGeometry (path
);
3299 pg
->SetFillRule (fill_rule
);
3303 moon_path_destroy (path
);
3308 value_is_explicit_null (const char *str
)
3310 return !strcmp ("{x:Null}", str
);
3314 is_managed_kind (Type::Kind kind
)
3317 if (kind
== Type::MANAGED
||
3318 kind
== Type::OBJECT
||
3319 kind
== Type::URI
||
3320 kind
== Type::MANAGEDTYPEINFO
||
3321 kind
== Type::DEPENDENCYPROPERTY
)
3328 kind_requires_managed_load (Type::Kind kind
)
3330 if (kind
== Type::USERCONTROL
) {
3338 is_legal_top_level_kind (Type::Kind kind
)
3340 if (kind
== Type::MANAGED
|| kind
== Type::OBJECT
|| Type::IsSubclassOf (Deployment::GetCurrent (), kind
, Type::DEPENDENCY_OBJECT
))
3345 // NOTE: Keep definition in sync with class/System.Windows/Mono/NativeMethods.cs
3347 value_from_str_with_typename (const char *type_name
, const char *prop_name
, const char *str
, Value
**v
)
3349 Type
*t
= Type::Find (Deployment::GetCurrent (), type_name
);
3353 return value_from_str (t
->GetKind (), prop_name
, str
, v
);
3357 expand_property_path (XamlParserInfo
*p
, PropertyPath
*path
)
3362 bool expanded
= false;
3363 GString
*res
= g_string_new (path
->path
);
3365 int len
= strlen (res
->str
);
3366 for (int i
= 0; i
< len
; i
++) {
3367 if (res
->str
[i
] == ':') {
3371 for ( ; s
> 0; s
--) {
3372 if (!g_ascii_isalnum (res
->str
[s
]))
3376 for ( ; te
< len
; te
++) {
3377 if (!g_ascii_isalpha (res
->str
[te
]) || res
->str
[te
] == '_')
3381 char *prefix
= g_strndup (res
->str
+ s
+ 1, e
- s
- 1);
3382 char *type
= g_strndup (res
->str
+ e
+ 1, te
- e
- 1);
3384 res
= g_string_erase (res
, s
+ 1, te
- s
- 1);
3386 XamlNamespace
*ns
= (XamlNamespace
*) g_hash_table_find (p
->namespace_map
, namespace_for_prefix
, prefix
);
3390 g_string_free (res
, true);
3394 XamlElementInfo
*info
= ns
->FindElement (p
, type
, NULL
, false);
3399 g_string_free (res
, true);
3403 char *uri
= g_strdup_printf ("'%s'", Type::Find (p
->deployment
, info
->GetKind ())->GetName ());
3405 res
= g_string_insert (res
, s
+ 1, uri
);
3406 i
= s
+ 1 + strlen (uri
);
3407 len
= strlen (res
->str
);
3419 g_string_free (res
, true);
3423 char *expanded_str
= res
->str
;
3424 g_string_free (res
, false);
3426 return expanded_str
;
3430 value_from_str (Type::Kind type
, const char *prop_name
, const char *str
, Value
**v
)
3434 value_from_str_with_parser (NULL
, type
, prop_name
, str
, v
, &v_set
);
3440 xaml_bool_from_str (const char *s
, bool *res
)
3445 if (!g_ascii_strcasecmp ("true", s
))
3447 else if (!g_ascii_strcasecmp ("false", s
))
3450 // Check if it's a string representing a decimal value
3454 l
= strtol (s
, &endptr
, 10);
3456 if (errno
|| endptr
== s
|| *endptr
|| l
> G_MAXINT32
|| l
< G_MININT32
)
3470 value_from_str_with_parser (XamlParserInfo
*p
, Type::Kind type
, const char *prop_name
, const char *str
, Value
**v
, bool *v_set
)
3475 if (value_is_explicit_null (str
)) {
3481 char *s
= g_strdup (str
);
3483 if (type
== Type::OBJECT
|| type
== Type::STRING
) {
3484 // object and string use the literal string
3487 // everything else depends on the string being stripped
3492 case Type::OBJECT
: {
3493 // not much more can do here, unless we want to try to
3494 // probe str to see if it's actually meant to be a
3495 // specific type. just assume it's a string.
3504 if (!xaml_bool_from_str (s
, &b
))
3511 case Type::DOUBLE
: {
3514 // empty string should not reset default values with 0
3516 // FIXME: this causes a 2.0 unit test to fail (PrimitiveTest.ParseEmptyDouble)
3517 if (IS_NULL_OR_EMPTY(s
)) {
3522 bool is_nan
= false;
3523 if (!g_ascii_strcasecmp (s
, "NAN"))
3527 d
= g_ascii_strtod (s
, &endptr
);
3530 if (is_nan
|| errno
|| endptr
== s
|| *endptr
) {
3532 && (!strcmp (prop_name
, "Width") || !strcmp (prop_name
, "Height"))
3533 && (!g_ascii_strcasecmp (s
, "Auto") || is_nan
))
3547 l
= strtol (s
, &endptr
, 10);
3549 if (errno
|| endptr
== s
)
3552 *v
= new Value (l
, Type::INT64
);
3556 case Type::TIMESPAN
: {
3559 if (!time_span_from_str (s
, &ts
))
3562 *v
= new Value (ts
, Type::TIMESPAN
);
3569 if (IS_NULL_OR_EMPTY(s
))
3571 else if (g_ascii_isalpha (s
[0]) && prop_name
) {
3572 i
= enums_str_to_int (prop_name
, s
);
3574 // g_warning ("'%s' enum is not valid on '%s' property", str, prop_name);
3579 long l
= strtol (s
, &endptr
, 10);
3581 if (errno
|| endptr
== s
)
3592 gunichar unichar
= g_utf8_get_char_validated (str
, -1);
3595 if ((int) unichar
< 0)
3598 if (!(next
= g_utf8_next_char (str
)) || *next
!= '\0')
3601 *v
= new Value (unichar
, Type::CHAR
);
3605 case Type::STRING
: {
3606 *v
= new Value (str
);
3611 Color
*c
= color_from_str (s
);
3614 *v
= new Value (*c
);
3619 case Type::REPEATBEHAVIOR
: {
3620 RepeatBehavior rb
= RepeatBehavior::Forever
;
3622 if (!repeat_behavior_from_str (s
, &rb
))
3625 *v
= new Value (rb
);
3629 case Type::DURATION
: {
3630 Duration d
= Duration::Forever
;
3632 if (!duration_from_str (s
, &d
))
3639 case Type::KEYTIME
: {
3640 KeyTime kt
= KeyTime::Paced
;
3642 if (!keytime_from_str (s
, &kt
))
3645 *v
= new Value (kt
);
3649 case Type::KEYSPLINE
: {
3652 if (!key_spline_from_str (s
, &ks
))
3655 *v
= Value::CreateUnrefPtr (ks
);
3660 case Type::SOLIDCOLORBRUSH
: {
3661 // Only solid color brushes can be specified using attribute syntax
3662 Color
*c
= color_from_str (s
);
3667 SolidColorBrush
*scb
= new SolidColorBrush ();
3672 *v
= Value::CreateUnrefPtr (scb
);
3679 if (!Point::FromStr (s
, &p
))
3689 if (!Size::FromStr (s
, &size
))
3692 *v
= new Value (size
);
3699 if (!Rect::FromStr (s
, &rect
))
3702 *v
= new Value (rect
);
3709 if (!uri
.Parse (s
)) {
3713 *v
= new Value (uri
);
3717 case Type::DOUBLE_COLLECTION
: {
3718 DoubleCollection
*doubles
= DoubleCollection::FromStr (s
);
3720 *v
= Value::CreateUnrefPtr (new DoubleCollection ());
3725 *v
= Value::CreateUnrefPtr (doubles
);
3729 case Type::POINT_COLLECTION
: {
3730 PointCollection
*points
= PointCollection::FromStr (s
);
3732 *v
= Value::CreateUnrefPtr (new PointCollection ());
3737 *v
= Value::CreateUnrefPtr (points
);
3741 case Type::TRANSFORMGROUP
: {
3742 if (IS_NULL_OR_EMPTY(s
))
3745 Matrix
*mv
= matrix_from_str (s
);
3749 TransformGroup
*tg
= new TransformGroup ();
3750 MatrixTransform
*t
= new MatrixTransform ();
3751 t
->SetValue (MatrixTransform::MatrixProperty
, Value (mv
));
3753 tg
->GetChildren()->Add (t
);
3756 *v
= new Value (tg
);
3762 case Type::TRANSFORM
:
3764 if (!g_ascii_strcasecmp ("Identity", str
)) {
3770 // Intentional fall through, you can create a matrix from a TRANSFORM property, but not using Identity
3771 case Type::MATRIXTRANSFORM
:
3773 if (IS_NULL_OR_EMPTY(s
))
3776 Matrix
*mv
= matrix_from_str (s
);
3780 MatrixTransform
*t
= new MatrixTransform ();
3781 t
->SetValue (MatrixTransform::MatrixProperty
, Value (mv
));
3789 case Type::UNMANAGEDMATRIX
:
3790 case Type::MATRIX
: {
3791 // note: unlike TRANSFORM this creates an empty, identity, matrix for an empty string
3792 Matrix
*matrix
= matrix_from_str (s
);
3796 *v
= new Value (matrix
);
3801 case Type::PROJECTION
:
3803 if (!g_ascii_strcasecmp ("Identity", str
)) {
3809 // Intentional fall through, you can create a matrix from a PROJECTION property, but not using Identity
3810 case Type::MATRIX3DPROJECTION
:
3812 if (IS_NULL_OR_EMPTY(s
))
3815 Matrix3D
*mv
= matrix3d_from_str (s
);
3819 Matrix3DProjection
*p
= new Matrix3DProjection ();
3820 p
->SetValue (Matrix3DProjection::ProjectionMatrixProperty
, Value (mv
));
3828 case Type::UNMANAGEDMATRIX3D
:
3829 case Type::MATRIX3D
: {
3830 Matrix3D
*matrix
= matrix3d_from_str (s
);
3834 *v
= new Value (matrix
);
3839 case Type::PATHGEOMETRY
:
3840 case Type::GEOMETRY
: {
3841 Geometry
*geometry
= geometry_from_str (s
);
3846 *v
= new Value (geometry
);
3851 case Type::THICKNESS
: {
3854 if (!Thickness::FromStr (s
, &t
))
3861 case Type::CORNERRADIUS
: {
3864 if (!CornerRadius::FromStr (s
, &c
))
3871 case Type::GRIDLENGTH
: {
3872 GridLength grid_length
;
3874 if (!grid_length_from_str (s
, &grid_length
))
3877 *v
= new Value (grid_length
);
3881 case Type::IMAGESOURCE
:
3882 case Type::BITMAPIMAGE
: {
3888 BitmapImage
*bi
= new BitmapImage ();
3890 bi
->SetUriSource (&uri
);
3892 *v
= Value::CreateUnrefPtr (bi
);
3897 case Type::MULTISCALETILESOURCE
:
3898 case Type::DEEPZOOMIMAGETILESOURCE
: {
3899 // As far as I know the only thing you can create here is a URI based DeepZoomImageTileSource
3903 *v
= Value::CreateUnrefPtr (new DeepZoomImageTileSource (&uri
));
3908 case Type::FONTFAMILY
: {
3909 *v
= new Value (FontFamily (s
));
3913 case Type::FONTWEIGHT
: {
3914 int fw
= enums_str_to_int ("FontWeight", s
);
3916 *v
= new Value (FontWeight ((FontWeights
)fw
));
3921 case Type::FONTSTYLE
: {
3922 int fs
= enums_str_to_int ("FontStyle", s
);
3924 *v
= new Value (FontStyle ((FontStyles
)fs
));
3929 case Type::FONTSTRETCH
: {
3930 int fs
= enums_str_to_int ("FontStretch", s
);
3932 *v
= new Value (FontStretch ((FontStretches
)fs
));
3937 case Type::PROPERTYPATH
: {
3938 PropertyPath
path (s
);
3939 path
.expanded_path
= expand_property_path (p
, &path
);
3940 *v
= new Value (path
);
3945 // we don't care about NULL or empty values
3946 if (!IS_NULL_OR_EMPTY (s
)) {
3957 XamlElementInstance::TrySetContentProperty (XamlParserInfo
*p
, XamlElementInstance
*value
)
3959 const char* prop_name
= info
->GetContentProperty (p
);
3964 DependencyProperty
*dep
= DependencyProperty::GetDependencyProperty (Type::Find (p
->deployment
, info
->GetKind ()), prop_name
);
3968 bool is_collection
= Type::IsSubclassOf (p
->deployment
, dep
->GetPropertyType(), Type::DEPENDENCY_OBJECT_COLLECTION
);
3970 if (!is_collection
&& Type::IsSubclassOf (p
->deployment
, value
->info
->GetKind (), dep
->GetPropertyType())) {
3972 if (!item
->SetValueWithError (dep
, value
->GetAsValue (), &err
)) {
3973 parser_error (p
, value
->element_name
, NULL
, err
.code
, err
.message
);
3979 // We only want to enter this if statement if we are NOT dealing with the content property element,
3980 // otherwise, attempting to use explicit property setting, would add the content property element
3981 // to the content property element collection
3982 if (is_collection
&& dep
->GetPropertyType() != value
->info
->GetKind ()) {
3983 Value
*col_v
= item
->GetValue (dep
);
3987 col
= collection_new (dep
->GetPropertyType ());
3988 item
->SetValue (dep
, Value (col
));
3991 col
= (Collection
*) col_v
->AsCollection ();
3995 if (-1 == col
->AddWithError (value
->GetAsValue (), &err
)) {
3996 parser_error (p
, value
->element_name
, NULL
, err
.code
, err
.message
);
4007 XamlElementInstance::TrySetContentProperty (XamlParserInfo
*p
, const char *value
)
4009 const char* prop_name
= info
->GetContentProperty (p
);
4012 if (info
->GetKind () == Type::ICON
) {
4013 prop_name
= "Source";
4018 Type::Kind prop_type
= p
->current_element
->info
->GetKind ();
4019 DependencyProperty
*content
= DependencyProperty::GetDependencyProperty (Type::Find (p
->deployment
, prop_type
), prop_name
);
4021 // TODO: There might be other types that can be specified here,
4022 // but string is all i have found so far. If you can specify other
4023 // types, i should pull the property setting out of set_attributes
4024 // and use that code
4026 if (content
&& (content
->GetPropertyType ()) == Type::STRING
&& value
) {
4027 item
->SetValue (content
, Value (g_strstrip (p
->cdata
->str
)));
4029 } else if (content
&& (content
->GetPropertyType ()) == Type::URI
&& value
) {
4032 if (!uri
.Parse (g_strstrip (p
->cdata
->str
)))
4035 item
->SetValue (content
, Value (uri
));
4037 } else if (Type::IsSubclassOf (p
->deployment
, info
->GetKind (), Type::TEXTBLOCK
)) {
4038 TextBlock
*textblock
= (TextBlock
*) item
;
4039 InlineCollection
*inlines
= textblock
->GetInlines ();
4040 Inline
*last
= NULL
;
4042 if (inlines
&& inlines
->GetCount () > 0)
4043 last
= inlines
->GetValueAt (inlines
->GetCount () - 1)->AsInline ();
4045 if (!p
->cdata_content
) {
4046 if (p
->next_element
&& !strcmp (p
->next_element
, "Run") && last
&& last
->GetObjectType () == Type::RUN
&&
4047 !last
->GetAutogenerated ()) {
4048 // LWSP between <Run> elements is to be treated as a single-SPACE <Run> element
4049 // Note: p->cdata is already canonicalized
4051 // This is one of the following cases:
4053 // 1. LWSP before the first <Run> element
4054 // 2. LWSP after the last <Run> element
4055 // 3. LWSP between <Run> and <LineBreak> elements
4059 if (!p
->next_element
|| !strcmp (p
->next_element
, "LineBreak"))
4060 g_strchomp (p
->cdata
->str
);
4062 if (!last
|| last
->GetObjectType () != Type::RUN
|| last
->GetAutogenerated ())
4063 g_strchug (p
->cdata
->str
);
4066 Run
*run
= new Run ();
4067 run
->SetText (p
->cdata
->str
);
4070 inlines
= new InlineCollection ();
4071 textblock
->SetInlines (inlines
);
4084 XamlElementInstance::SetUnknownAttribute (XamlParserInfo
*p
, const char *name
, const char *value
)
4089 Value v
= Value (value
);
4090 if (!p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), info
->xmlns
, GetAsValue (), this, GetParentPointer (), NULL
, name
, &v
, NULL
)) {
4097 XamlElementInstance::SetDelayedProperties (XamlParserInfo
*p
)
4099 GSList
*walk
= delayed_properties
;
4102 DelayedProperty
*prop
= (DelayedProperty
*) walk
->data
;
4104 if (!p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), info
->xmlns
, GetAsValue (), this, GetParentPointer (), prop
->xmlns
, prop
->name
, prop
->value
, NULL
, XamlCallbackData::SETTING_DELAYED_PROPERTY
)) {
4105 parser_error (p
, element_name
, prop
->name
, 2012,
4106 "Unknown property %s on element %s.",
4107 prop
->name
, element_name
);
4117 XamlElementInstance::FindPropertyElement (XamlParserInfo
*p
, const char *el
, const char *dot
)
4119 // We didn't find anything so try looking up in managed
4123 Value
*v
= new Value ();
4124 if (p
->loader
->LookupObject (p
, p
->GetTopElementPtr (), GetAsValue (), p
->current_namespace
->GetUri (), el
, false, true, v
)) {
4125 char *type_name
= g_strndup (el
, dot
- el
);
4127 XamlElementInfoManaged
*res
= new XamlElementInfoManaged (g_strdup (p
->current_namespace
->GetUri ()), el
, info
, v
->GetKind (), v
);
4128 XamlElementInfo
*container
= p
->current_namespace
->FindElement (p
, type_name
, NULL
, false);
4129 info
->SetPropertyOwnerKind (container
->GetKind ());
4138 static XamlElementInfo
*
4139 create_element_info_from_imported_managed_type (XamlParserInfo
*p
, const char *name
, const char **attr
, bool create
)
4144 char* type_name
= NULL
;
4145 char* type_xmlns
= NULL
;
4146 const char* use_xmlns
= NULL
;
4149 // We might have an x:Class attribute specified, so we need to use that for the
4150 // type_name that we pass to LookupObject
4151 if (strcmp ("Application", name
)) {
4152 type_name
= x_namespace
->FindTypeName (attr
, &type_xmlns
);
4155 use_xmlns
= type_xmlns
;
4157 if (!p
->hydrating
) {
4158 parser_error (p
, name
, "x:Class", 4005, "Cannot specify x:Class in xaml files outside of a xap.");
4165 Value
*v
= new Value ();
4166 if (!p
->loader
->LookupObject (p
, use_xmlns
? p
->GetTopElementPtr () : NULL
, NULL
, use_xmlns
, name
, create
, false, v
)) {
4171 g_free (type_xmlns
);
4175 XamlElementInfoImportedManaged
*info
= new XamlElementInfoImportedManaged (g_strdup (name
), NULL
, v
);
4178 if (v
->Is (p
->deployment
, Type::DEPENDENCY_OBJECT
))
4179 p
->AddCreatedElement (v
->AsDependencyObject());
4187 XamlElementInfoNative::GetContentProperty (XamlParserInfo
*p
)
4189 return type
->GetContentPropertyName ();
4192 XamlElementInstance
*
4193 XamlElementInfoNative::CreateElementInstance (XamlParserInfo
*p
)
4195 if (type
->IsValueType ())
4196 return new XamlElementInstanceValueType (this, p
, GetName (), XamlElementInstance::ELEMENT
);
4197 else if (type
->IsSubclassOf (Type::FRAMEWORKTEMPLATE
))
4198 return new XamlElementInstanceTemplate (this, p
, GetName (), XamlElementInstance::ELEMENT
);
4200 return new XamlElementInstanceNative (this, p
, GetName (), XamlElementInstance::ELEMENT
);
4203 XamlElementInstance
*
4204 XamlElementInfoNative::CreateWrappedElementInstance (XamlParserInfo
*p
, Value
*o
)
4206 XamlElementInstance
*res
= new XamlElementInstanceNative (this, p
, GetName (), XamlElementInstance::ELEMENT
, false);
4207 res
->SetDependencyObject (o
->AsDependencyObject ());
4213 XamlElementInstanceNative::FindPropertyElement (XamlParserInfo
*p
, const char *el
, const char *dot
)
4215 if (IsDependencyObject ()) {
4216 const char *prop_name
= dot
+ 1;
4217 DependencyProperty
*prop
= DependencyProperty::GetDependencyProperty (Type::Find (p
->deployment
, info
->GetKind ()), prop_name
);
4219 XamlElementInfoNative
*info
= new XamlElementInfoNative (Type::Find (p
->deployment
, prop
->GetPropertyType ()));
4220 info
->SetPropertyOwnerKind (prop
->GetOwnerType ());
4225 return XamlElementInstance::FindPropertyElement (p
, el
, dot
);
4228 XamlElementInstance
*
4229 XamlElementInfoNative::CreatePropertyElementInstance (XamlParserInfo
*p
, const char *name
)
4231 return new XamlElementInstanceNative (this, p
, name
, XamlElementInstance::PROPERTY
, false);
4234 XamlElementInstanceNative::XamlElementInstanceNative (XamlElementInfoNative
*element_info
, XamlParserInfo
*parser_info
, const char *name
, ElementType type
, bool create_item
) :
4235 XamlElementInstance (element_info
, name
, type
)
4237 this->element_info
= element_info
;
4238 this->parser_info
= parser_info
;
4240 SetDependencyObject (CreateItem ());
4246 XamlElementInstanceNative::CreateItem ()
4248 XamlElementInstance
*walk
= parser_info
->current_element
;
4249 Type
*type
= element_info
->GetType ();
4251 DependencyObject
*item
= NULL
;
4252 DependencyProperty
*dep
= NULL
;
4254 if (type
->IsSubclassOf (Type::COLLECTION
) || type
->IsSubclassOf (Type::RESOURCE_DICTIONARY
)) {
4255 // If we are creating a collection, try walking up the element tree,
4256 // to find the parent that we belong to and using that instance for
4257 // our collection, instead of creating a new one
4259 // We attempt to advance past the property setter, because we might be dealing with a
4262 if (walk
&& walk
->element_type
== XamlElementInstance::PROPERTY
) {
4263 char **prop_name
= g_strsplit (walk
->element_name
, ".", -1);
4265 walk
= walk
->parent
;
4266 dep
= DependencyProperty::GetDependencyProperty (Type::Find (parser_info
->deployment
, walk
->info
->GetKind ()), prop_name
[1]);
4268 g_strfreev (prop_name
);
4269 } else if (walk
&& walk
->info
->GetContentProperty (parser_info
)) {
4270 dep
= DependencyProperty::GetDependencyProperty (Type::Find (parser_info
->deployment
, walk
->info
->GetKind ()),
4271 (char *) walk
->info
->GetContentProperty (parser_info
));
4274 if (dep
&& Type::IsSubclassOf (parser_info
->deployment
, dep
->GetPropertyType(), type
->GetKind ())) {
4275 Value
*v
= ((DependencyObject
* ) walk
->GetAsDependencyObject ())->GetValue (dep
);
4277 item
= v
->AsDependencyObject ();
4280 // note: if !v then the default collection is NULL (e.g. PathFigureCollection)
4285 item
= element_info
->GetType()->IsCtorVisible() ? element_info
->GetType ()->CreateInstance () : NULL
;
4288 parser_info
->AddCreatedElement (item
);
4290 // in case we must store the collection into the parent
4291 if (dep
&& dep
->GetPropertyType() == type
->GetKind ()) {
4293 Value
item_value (item
);
4294 if (!((DependencyObject
* ) walk
->GetAsDependencyObject ())->SetValueWithError (dep
, &item_value
, &err
))
4295 parser_error (parser_info
, element_name
, NULL
, err
.code
, err
.message
);
4298 parser_error (parser_info
, element_name
, NULL
, 2007, "Unknown element: %s.", element_name
);
4306 XamlElementInstanceNative::SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, XamlElementInstance
*value
)
4308 if (property
->info
->RequiresManagedSet () || value
->info
->RequiresManagedSet ())
4309 return p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), NULL
, GetAsValue (), this, GetParentPointer (), property
->info
->xmlns
, property
->element_name
, value
->GetAsValue (), NULL
);
4311 return dependency_object_set_property (p
, this, property
, value
, true);
4315 XamlElementInstanceNative::SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, const char *value
)
4317 char **prop_name
= g_strsplit (property
->element_name
, ".", -1);
4318 Type
*owner
= Type::Find (p
->deployment
, prop_name
[0]);
4319 DependencyProperty
*dep
;
4324 dep
= DependencyProperty::GetDependencyProperty (Type::Find (p
->deployment
, owner
->GetKind ()), prop_name
[1]);
4328 return xaml_set_property_from_str (item
, dep
, value
, NULL
/*XXX*/);
4332 XamlElementInstanceNative::AddChild (XamlParserInfo
*p
, XamlElementInstance
*child
)
4334 dependency_object_add_child (p
, this, child
, true);
4338 XamlElementInstanceNative::SetAttributes (XamlParserInfo
*p
, const char **attr
)
4340 dependency_object_set_attributes (p
, this, attr
);
4344 XamlElementInstanceValueType::XamlElementInstanceValueType (XamlElementInfoNative
*element_info
, XamlParserInfo
*parser_info
, const char *name
, ElementType type
) :
4345 XamlElementInstance (element_info
, name
, type
)
4347 this->element_info
= element_info
;
4348 this->parser_info
= parser_info
;
4352 XamlElementInstanceValueType::CreateValueItemFromString (const char* str
)
4355 bool res
= value_from_str (element_info
->GetType ()->GetKind (), NULL
, str
, &value
);
4360 XamlElementInstanceValueType::SetAttributes (XamlParserInfo
*p
, const char **attr
)
4362 value_type_set_attributes (p
, this, attr
);
4365 XamlElementInstanceEnum::XamlElementInstanceEnum (XamlElementInfoEnum
*element_info
, const char *name
, ElementType type
) :
4366 XamlElementInstance (element_info
, name
, type
)
4371 XamlElementInstanceEnum::CreateEnumFromString (const char* str
)
4373 int i
= enums_str_to_int (element_name
, str
);
4377 value
= new Value (i
);
4382 XamlElementInstanceEnum::SetAttributes (XamlParserInfo
*p
, const char **attr
)
4384 value_type_set_attributes (p
, this, attr
);
4387 XamlElementInstance
*
4388 XamlElementInfoEnum::CreateElementInstance (XamlParserInfo
*p
)
4390 return new XamlElementInstanceEnum (this, name
, XamlElementInstance::ELEMENT
);
4393 XamlElementInstance
*
4394 XamlElementInfoEnum::CreateWrappedElementInstance (XamlParserInfo
*p
, Value
*o
)
4396 XamlElementInstance
*res
= new XamlElementInstanceEnum (this, name
, XamlElementInstance::ELEMENT
);
4401 XamlElementInfoManaged::GetContentProperty (XamlParserInfo
*p
)
4406 // TODO: We could cache this, but for now lets keep things as simple as possible.
4407 const char *res
= p
->loader
->GetContentPropertyName (p
, p
->GetTopElementPtr (), obj
);
4410 return XamlElementInfo::GetContentProperty (p
);
4413 XamlElementInstance
*
4414 XamlElementInfoManaged::CreateElementInstance (XamlParserInfo
*p
)
4416 XamlElementInstanceManaged
*inst
= new XamlElementInstanceManaged (this, GetName (), XamlElementInstance::ELEMENT
, obj
);
4418 if (obj
->Is (p
->deployment
, Type::DEPENDENCY_OBJECT
))
4419 p
->AddCreatedElement (inst
->GetAsDependencyObject ());
4424 XamlElementInstance
*
4425 XamlElementInfoManaged::CreateWrappedElementInstance (XamlParserInfo
*p
, Value
*o
)
4427 XamlElementInstanceManaged
*inst
= new XamlElementInstanceManaged (this, GetName (), XamlElementInstance::ELEMENT
, o
);
4432 XamlElementInstance
*
4433 XamlElementInfoManaged::CreatePropertyElementInstance (XamlParserInfo
*p
, const char *name
)
4435 XamlElementInstanceManaged
*inst
= new XamlElementInstanceManaged (this, name
, XamlElementInstance::PROPERTY
, obj
);
4440 XamlElementInstanceManaged::XamlElementInstanceManaged (XamlElementInfo
*info
, const char *name
, ElementType type
, Value
*obj
) :
4441 XamlElementInstance (info
, name
, type
)
4443 // The managed code owns our Value objects
4444 cleanup_value
= false;
4448 if (obj
->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT
)) {
4449 this->is_dependency_object
= true;
4450 this->SetDependencyObject (obj
->AsDependencyObject ());
4453 this->is_dependency_object
= false;
4457 XamlElementInstanceManaged::GetManagedPointer ()
4459 if (value
->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT
))
4460 return value
->AsDependencyObject ();
4461 return value
->AsManagedObject ();
4465 XamlElementInstanceManaged::GetParentPointer ()
4467 XamlElementInstance
*walk
= parent
;
4468 while (walk
&& walk
->element_type
!= XamlElementInstance::ELEMENT
)
4469 walk
= walk
->parent
;
4475 return walk
->GetAsValue ();
4479 XamlElementInstanceManaged::SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, XamlElementInstance
*value
)
4481 if (GetAsDependencyObject () != NULL
&& dependency_object_set_property (p
, this, property
, value
, false))
4483 return p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), info
->xmlns
, GetAsValue (), this, GetParentPointer (), property
->info
->xmlns
, property
->element_name
, value
->GetAsValue (), value
);
4487 XamlElementInstanceManaged::SetProperty (XamlParserInfo
*p
, XamlElementInstance
*property
, const char *value
)
4489 Value v
= Value (value
);
4490 return p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), info
->xmlns
, GetAsValue (), this, GetParentPointer (), property
->info
->xmlns
, property
->element_name
, &v
, NULL
);
4494 XamlElementInstanceManaged::AddChild (XamlParserInfo
*p
, XamlElementInstance
*child
)
4496 if (element_type
== XamlElementInstance::PROPERTY
) {
4497 Value
*prop
= new Value (element_name
);
4498 p
->loader
->AddChild (p
, p
->GetTopElementPtr (), GetParentPointer (), true, info
->xmlns
, prop
, this, child
->GetAsValue (), child
);
4503 p
->loader
->AddChild (p
, p
->GetTopElementPtr (), GetParentPointer (), false, info
->xmlns
, GetAsValue (), this, child
->GetAsValue (), child
);
4507 XamlElementInstanceManaged::SetAttributes (XamlParserInfo
*p
, const char **attr
)
4509 dependency_object_set_attributes (p
, this, attr
);
4513 XamlElementInstanceManaged::TrySetContentProperty (XamlParserInfo
*p
, XamlElementInstance
*value
)
4515 Value
*v
= value
->GetAsValue ();
4516 const char* prop_name
= info
->GetContentProperty (p
);
4518 return p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), info
->xmlns
, GetAsValue (), this, GetParentPointer (), NULL
, prop_name
, v
, value
);
4522 XamlElementInstanceManaged::TrySetContentProperty (XamlParserInfo
*p
, const char *value
)
4524 if (Type::IsSubclassOf (p
->deployment
, info
->GetKind (), Type::CONTENTCONTROL
)) {
4525 // Content controls are not allowed to have their content set as text, they need to have a child element
4526 // if you want to set the content of a contentcontrol to text you need to use attribute syntax
4530 if (!XamlElementInstance::TrySetContentProperty (p
, value
)) {
4531 const char* prop_name
= info
->GetContentProperty (p
);
4532 if (!p
->cdata_content
)
4534 Value v
= Value (value
);
4535 bool res
= p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), info
->xmlns
, GetAsValue (), this, GetParentPointer (), NULL
, prop_name
, &v
, NULL
);
4542 XamlElementInstance
*
4543 XamlElementInfoImportedManaged::CreateElementInstance (XamlParserInfo
*p
)
4545 XamlElementInstanceManaged
*inst
= new XamlElementInstanceManaged (this, name
, XamlElementInstance::ELEMENT
, obj
);
4551 XamlElementInfoImportedManaged::GetContentProperty (XamlParserInfo
*p
)
4556 // TODO: Test, it's possible that managed objects that aren't DOs are allowed to have content properties.
4557 if (!obj
->Is (p
->deployment
, Type::DEPENDENCY_OBJECT
))
4558 return XamlElementInfo::GetContentProperty (p
);
4561 // TODO: We could cache this, but for now lets keep things as simple as possible.
4562 const char *res
= p
->loader
->GetContentPropertyName (p
, p
->GetTopElementPtr (), obj
);
4566 return XamlElementInfo::GetContentProperty (p
);
4569 XamlElementInstance
*
4570 XamlElementInfoImportedManaged::CreateWrappedElementInstance (XamlParserInfo
*p
, Value
*o
)
4572 XamlElementInstanceManaged
*inst
= new XamlElementInstanceManaged (this, Type::Find (p
->deployment
, o
->GetKind ())->GetName (), XamlElementInstance::ELEMENT
, o
);
4577 XamlElementInstance
*
4578 XamlElementInfoImportedManaged::CreatePropertyElementInstance (XamlParserInfo
*p
, const char *name
)
4580 XamlElementInstanceManaged
*inst
= new XamlElementInstanceManaged (this, name
, XamlElementInstance::PROPERTY
, obj
);
4591 get_key_from_child (XamlElementInstance
*child
)
4593 const char *key
= child
->GetKey ();
4597 key
= child
->GetName ();
4601 if (child
->IsDependencyObject ()) {
4602 DependencyObject
*c
= child
->GetAsDependencyObject();
4604 if (Type::IsSubclassOf (c
->GetDeployment (), Type::STYLE
, child
->info
->GetKind ())) {
4605 Value
*v
= c
->GetValue (Style::TargetTypeProperty
);
4606 if (v
&& v
->GetKind () == Type::MANAGEDTYPEINFO
)
4607 key
= v
->AsManagedTypeInfo ()->full_name
;
4618 dependency_object_add_child (XamlParserInfo
*p
, XamlElementInstance
*parent
, XamlElementInstance
*child
, bool fail_if_no_prop
)
4620 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
4621 if (parent
->element_type
== XamlElementInstance::PROPERTY
) {
4623 if (parent
->info
->RequiresManagedSet ())
4626 char **prop_name
= g_strsplit (parent
->element_name
, ".", -1);
4627 Type
*owner
= types
->Find (prop_name
[0]);
4630 DependencyProperty
*dep
= DependencyProperty::GetDependencyProperty (Type::Find (p
->deployment
, owner
->GetKind ()), prop_name
[1]);
4632 g_strfreev (prop_name
);
4635 g_warning ("Unknown element: %s.", parent
->element_name
);
4636 if (fail_if_no_prop
)
4637 parser_error (p
, parent
->element_name
, NULL
, 2007, "Unknown element: %s.", parent
->element_name
);
4641 // XamlElementInfoEnum has Type::INVALID as
4642 // its kind, which is why that first check is
4644 if (child
->info
->GetKind() != Type::MANAGED
&&
4645 !types
->Find (child
->info
->GetKind())->IsCtorVisible()) {
4646 // we can't instantiate this type
4647 return parser_error (p
, child
->element_name
, NULL
, 2007,
4648 "Unknown element: %s.", child
->element_name
);
4651 // Don't add the child element, if it is the entire collection
4652 if (dep
->GetPropertyType() == child
->info
->GetKind ())
4655 Type::Kind prop_type
= dep
->GetPropertyType ();
4656 if (!types
->IsSubclassOf (prop_type
, Type::DEPENDENCY_OBJECT_COLLECTION
)
4657 && !types
->IsSubclassOf (prop_type
, Type::RESOURCE_DICTIONARY
))
4660 // Most common case, we will have a parent that we can snag the collection from
4661 DependencyObject
*obj
= (DependencyObject
*) parent
->parent
->GetAsDependencyObject ();
4665 Value
*col_v
= obj
->GetValue (dep
);
4667 Type
*col_type
= types
->Find (prop_type
);
4668 DependencyObject
*c_obj
= col_type
->CreateInstance ();
4669 obj
->SetValue (dep
, Value::CreateUnrefPtr (c_obj
));
4670 col_v
= obj
->GetValue (dep
);
4673 Collection
*col
= col_v
->AsCollection ();
4676 if (types
->IsSubclassOf (prop_type
, Type::DEPENDENCY_OBJECT_COLLECTION
)) {
4677 Value
child_val (child
->GetAsDependencyObject ());
4678 if (-1 == col
->AddWithError (&child_val
, &err
))
4679 return parser_error (p
, child
->element_name
, NULL
, err
.code
, err
.message
);
4681 else if (types
->IsSubclassOf (prop_type
, Type::RESOURCE_DICTIONARY
)) {
4682 ResourceDictionary
*dict
= (ResourceDictionary
*)col
;
4684 const char *key
= get_key_from_child (child
);
4687 // XXX don't know the proper values here...
4688 return parser_error (p
, child
->element_name
, NULL
, 2007,
4689 "You must specify an x:Key or x:Name for elements in a ResourceDictionary");
4692 Value
*child_as_value
= child
->GetAsValue ();
4694 if (!child_as_value
) {
4695 // XXX don't know the proper values here...
4696 return parser_error (p
, child
->element_name
, NULL
, 2007,
4697 "Error adding child to ResourceDictionary");
4700 bool added
= dict
->AddWithError (key
, child_as_value
, &err
);
4702 return parser_error (p
, child
->element_name
, NULL
, err
.code
, err
.message
);
4711 if (types
->IsSubclassOf (parent
->info
->GetKind (), Type::DEPENDENCY_OBJECT_COLLECTION
)) {
4712 Collection
*col
= (Collection
*) parent
->GetAsDependencyObject ();
4714 Value
child_val ((DependencyObject
*)child
->GetAsDependencyObject ());
4716 if (-1 == col
->AddWithError (&child_val
, &err
))
4717 return parser_error (p
, child
->element_name
, NULL
, err
.code
, err
.message
);
4720 else if (types
->IsSubclassOf (parent
->info
->GetKind (), Type::RESOURCE_DICTIONARY
)) {
4721 ResourceDictionary
*dict
= (ResourceDictionary
*) parent
->GetAsDependencyObject ();
4724 const char *key
= get_key_from_child (child
);
4727 // XXX don't know the proper values here...
4728 return parser_error (p
, child
->element_name
, NULL
, 2007,
4729 "You must specify an x:Key or x:Name for elements in a ResourceDictionary");
4732 Value
*child_as_value
= child
->GetAsValue ();
4733 bool added
= dict
->AddWithError (key
, child_as_value
, &err
);
4735 return parser_error (p
, child
->element_name
, NULL
, err
.code
, err
.message
);
4739 if (parent
->element_type
!= XamlElementInstance::PROPERTY
) {
4740 parent
->TrySetContentProperty (p
, child
);
4743 // Do nothing if we aren't adding to a collection, or a content property collection
4748 /// set property funcs
4751 // these are just a bunch of special cases
4753 dependency_object_missed_property (XamlElementInstance
*item
, XamlElementInstance
*prop
, XamlElementInstance
*value
, char **prop_name
)
4759 set_managed_attached_property (XamlParserInfo
*p
, XamlElementInstance
*item
, XamlElementInstance
*prop
, XamlElementInstance
*value
)
4764 return p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), item
->info
->xmlns
, item
->GetAsValue (), item
, item
->GetParentPointer (), prop
->info
->xmlns
, prop
->element_name
, value
->GetAsValue (), value
);
4768 dependency_object_set_property (XamlParserInfo
*p
, XamlElementInstance
*item
, XamlElementInstance
*property
, XamlElementInstance
*value
, bool raise_errors
)
4770 char **prop_name
= g_strsplit (property
->element_name
, ".", -1);
4771 DependencyObject
*dep
= item
->GetAsDependencyObject ();
4772 DependencyProperty
*prop
= NULL
;
4774 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
4776 if (types
->Find (item
->info
->GetKind ())->IsValueType ()) {
4777 if (raise_errors
) parser_error (p
, item
->element_name
, NULL
, -1, "Value types (%s) do not have properties.", property
->element_name
);
4778 g_strfreev (prop_name
);
4782 if (types
->Find (property
->info
->GetPropertyOwnerKind ())->IsCustomType ()) {
4783 g_strfreev (prop_name
);
4784 return set_managed_attached_property (p
, item
, property
, value
);
4788 // FIXME is this really where this check should live
4790 parser_error (p
, item
->element_name
, NULL
, 2030,
4791 "Property element %s cannot be used inside another property element.",
4792 property
->element_name
);
4794 g_strfreev (prop_name
);
4798 prop
= DependencyProperty::GetDependencyProperty (Type::Find (p
->deployment
, item
->info
->GetKind ()), prop_name
[1]);
4801 if (prop
->IsReadOnly ()) {
4803 parser_error (p
, item
->element_name
, NULL
, 2014,
4804 "The attribute %s is read only and cannot be set.", prop
->GetName ());
4806 } else if (types
->IsSubclassOf (value
->info
->GetKind (), prop
->GetPropertyType())) {
4807 // an empty collection can be NULL and valid
4808 if (item
->IsPropertySet (prop
->GetName())) {
4810 parser_error (p
, item
->element_name
, NULL
, 2033,
4811 "Cannot specify the value multiple times for property: %s.",
4812 property
->element_name
);
4817 // HACK - since the Setter is added to the collection *before* its properties are set
4818 // we find ourselves with a sealed Setter - which should not be possible at the parse time
4819 SetterBase
*sb
= NULL
;
4820 if (types
->IsSubclassOf (dep
->GetObjectType (), Type::SETTERBASE
)) {
4821 sb
= (SetterBase
*) dep
;
4822 sb
->SetIsSealed (false);
4825 if (!is_managed_kind (value
->info
->GetKind ()) && !value
->info
->RequiresManagedSet()) {
4826 if (!dep
->SetValueWithError (prop
, value
->GetAsValue (), &err
)) {
4828 parser_error (p
, item
->element_name
, NULL
, err
.code
, err
.message
);
4834 if (!p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), NULL
, item
->GetAsValue (), item
, item
->GetParentPointer (), NULL
, prop_name
[1], value
->GetAsValue (), NULL
)) {
4836 parser_error (p
, item
->element_name
, NULL
, err
.code
, err
.message
);
4843 // re-seal the Setter (end-HACK)
4845 sb
->SetIsSealed (true);
4847 item
->MarkPropertyAsSet (prop
->GetName());
4850 } else if (types
->IsSubclassOf (prop
->GetPropertyType (), Type::COLLECTION
) || types
->IsSubclassOf (prop
->GetPropertyType (), Type::RESOURCE_DICTIONARY
)) {
4851 // The items were added in add_child
4855 parser_error (p
, item
->element_name
, NULL
, 2010, "does not support %s as content.", value
->element_name
);
4859 dependency_object_missed_property (item
, property
, value
, prop_name
);
4864 g_strfreev (prop_name
);
4869 xaml_set_property_from_str (DependencyObject
*obj
, DependencyProperty
*prop
, const char *value
, MoonError
*error
)
4874 if (!value_from_str (prop
->GetPropertyType(), prop
->GetName(), value
, &v
))
4877 // it's possible for (a valid) value to be NULL (and we must keep the default value)
4879 rv
= obj
->SetValueWithError (prop
, v
, error
);
4887 xaml_is_valid_event_name (Deployment
*deployment
, Type::Kind kind
, const char *name
, bool allow_desktop_events
)
4889 Type
*type
= Type::Find (deployment
, kind
);
4893 int event_id
= type
->LookupEvent (name
);
4897 if (!allow_desktop_events
|| (moonlight_flags
& RUNTIME_INIT_DESKTOP_EXTENSIONS
) == 0) {
4898 // if we're not allowing desktop-only events, or if the user hasn't allowed them,
4899 // return false if the name corresponds to one of them.
4900 if (!strcmp (name
, "MouseRightButtonDown") ||
4901 !strcmp (name
, "MouseRightButtonUp") ||
4902 !strcmp (name
, "MouseWheel"))
4910 value_type_set_attributes (XamlParserInfo
*p
, XamlElementInstance
*item
, const char **attr
)
4912 // the only attributes value on value types seem to be x:Key
4913 // and x:Name, but reuse the generic namespace attribute stuff
4916 for (int i
= 0; attr
[i
]; i
+= 2) {
4918 if (attr
[i
+ 1] == NULL
|| attr
[i
+ 1][0] == '\0')
4921 char **attr_name
= g_strsplit (attr
[i
], "|", -1);
4923 if (attr_name
[1]) {
4925 XamlNamespace
*ns
= (XamlNamespace
*) g_hash_table_lookup (p
->namespace_map
, attr_name
[0]);
4928 return parser_error (p
, item
->element_name
, attr
[i
], 7055, "undeclared prefix");
4930 ns
->SetAttribute (p
, item
, attr_name
[1], attr
[i
+ 1]);
4932 g_strfreev (attr_name
);
4934 // Setting managed attributes can cause errors galore
4941 g_strfreev (attr_name
);
4946 dependency_object_set_attributes (XamlParserInfo
*p
, XamlElementInstance
*item
, const char **attr
)
4948 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
4949 GList
*delay_att
= NULL
;
4951 for (int i
= 0; attr
[i
]; i
+= 2) {
4956 // Setting attributes like x:Class can change item->item, so we
4957 // need to make sure we have an up to date pointer
4958 DependencyObject
*dep
= item
->GetAsDependencyObject ();
4959 char **attr_name
= g_strsplit (attr
[i
], "|", -1);
4961 if (attr_name
[1]) {
4962 XamlNamespace
*ns
= (XamlNamespace
*) g_hash_table_lookup (p
->namespace_map
, attr_name
[0]);
4964 if (ns
!= x_namespace
) {
4965 delay_att
= g_list_append (delay_att
, GINT_TO_POINTER (i
));
4966 g_strfreev (attr_name
);
4971 g_strfreev (attr_name
);
4972 return parser_error (p
, item
->element_name
, attr
[i
], 5055, "undeclared prefix");
4975 ns
->SetAttribute (p
, item
, attr_name
[1], attr
[i
+ 1]);
4977 g_strfreev (attr_name
);
4979 // Setting managed attributes can cause errors galore
4986 g_strfreev (attr_name
);
4988 const char *pname
= attr
[i
];
4989 char *atchname
= NULL
;
4990 for (int a
= 0; attr
[i
][a
]; a
++) {
4991 if (attr
[i
][a
] != '.')
4993 atchname
= g_strndup (attr
[i
], a
);
4994 pname
= attr
[i
] + a
+ 1;
4998 DependencyProperty
*prop
= NULL
;
5000 Type
*attached_type
= types
->Find (atchname
);
5002 prop
= DependencyProperty::GetDependencyProperty (attached_type
, pname
);
5004 prop
= DependencyProperty::GetDependencyProperty (Type::Find (p
->deployment
, item
->info
->GetKind ()), pname
);
5008 if (prop
->GetId () == DependencyObject::NameProperty
) {
5010 if (item
->GetName ()) {
5011 parser_error (p
, item
->element_name
, NULL
, 2016, "Cannot specify both Name and x:Name attributes.");
5015 // XXX toshok - I don't like doing this here... but it fixes airlines.
5016 item
->SetKey (p
, attr
[i
+1]);
5018 NameScope
*scope
= p
->namescope
;
5019 if (!item
->GetAsDependencyObject ()->SetName (attr
[i
+1], scope
)) {
5020 parser_error (p
, item
->element_name
, NULL
, 2028,
5021 "The name already exists in the tree: %s.", attr
[i
+1]);
5023 g_list_free (delay_att
);
5029 if (prop
->IsReadOnly ()) {
5030 parser_error (p
, item
->element_name
, NULL
, 2014,
5031 "The attribute %s is read only and cannot be set.", prop
->GetName ());
5033 g_list_free (delay_att
);
5037 if (item
->IsPropertySet (prop
->GetName())) {
5038 parser_error (p
, item
->element_name
, attr
[i
], 2033,
5039 "Cannot specify the value multiple times for property: %s.", prop
->GetName ());
5041 g_list_free (delay_att
);
5047 char *attr_value
= g_strdup (attr
[i
+1]);
5049 bool need_managed
= false;
5050 if (attr
[i
+1][0] == '{') {
5051 if (attr
[i
+1][1] == '}') {
5052 // {} is an escape sequence so you can have strings like {StaticResource}
5053 char *nv
= attr_value
;
5054 attr_value
= g_strdup (attr_value
+ 2);
5057 else if (attr
[i
+1][strlen(attr
[i
+1]) - 1] == '}') {
5058 need_managed
= true;
5062 if (!need_managed
) {
5063 if (!value_from_str_with_parser (p
, prop
->GetPropertyType(), prop
->GetName(), attr_value
, &v
, &v_set
)) {
5065 g_free (attr_value
);
5070 Type::Kind propKind
= prop
->GetPropertyType ();
5072 if (need_managed
|| is_managed_kind (propKind
) || types
->Find (prop
->GetOwnerType ())->IsCustomType () || (v
&& is_managed_kind (v
->GetKind ()))) {
5073 bool str_value
= false;
5075 v
= new Value (attr
[i
+ 1]); // Note that we passed the non escaped value, not attr_value
5080 // printf ("setting managed property: %s::%s to %s=%s\n", dep->GetType ()->GetName (), prop->GetName (), attr [i], attr [i + 1]);
5081 if (p
->loader
->SetProperty (p
, p
->GetTopElementPtr (), NULL
, item
->GetAsValue (), item
, item
->GetParentPointer (), NULL
, g_strdup (attr
[i
]), v
, NULL
)) {
5083 g_free (attr_value
);
5090 if (!value_from_str_with_parser (p
, prop
->GetPropertyType(), prop
->GetName(), attr_value
, &v
, &v_set
)) {
5092 g_free (attr_value
);
5099 if (!v_set
&& !value_is_explicit_null (attr
[i
+ 1])) { // Check the non escaped value
5100 parser_error (p
, item
->element_name
, attr
[i
], 2024, "Invalid attribute value %s for property %s.", attr
[i
+1], attr
[i
]);
5102 g_free (attr_value
);
5104 g_list_free (delay_att
);
5109 // 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 ());
5110 if (!dep
->SetValueWithError (prop
, v
, &err
))
5111 parser_error (p
, item
->element_name
, attr
[i
], err
.code
, err
.message
);
5113 item
->MarkPropertyAsSet (prop
->GetName());
5116 g_free (attr_value
);
5118 delay_att
= g_list_append (delay_att
, GINT_TO_POINTER (i
));
5125 GList
*walk
= g_list_first (delay_att
);
5127 int i
= GPOINTER_TO_INT (walk
->data
);
5132 char **attr_name
= g_strsplit (attr
[i
], "|", -1);
5134 if (attr_name
[1]) {
5135 XamlNamespace
*ns
= (XamlNamespace
*) g_hash_table_lookup (p
->namespace_map
, attr_name
[0]);
5137 if (ns
== x_namespace
) {
5138 // Skip these, they are handled earlier
5139 g_strfreev (attr_name
);
5144 g_strfreev (attr_name
);
5145 parser_error (p
, item
->element_name
, attr
[i
], 5055, "undeclared prefix");
5149 ns
->SetAttribute (p
, item
, attr_name
[1], attr
[i
+ 1]);
5151 g_strfreev (attr_name
);
5153 // Setting managed attributes can cause errors galore
5157 if (!item
->SetUnknownAttribute (p
, attr
[i
], attr
[i
+ 1])) {
5158 parser_error (p
, item
->element_name
, attr
[i
], 2012,
5159 "Unknown attribute %s on element %s.",
5160 attr
[i
], item
->element_name
);
5168 g_list_free (delay_att
);
5173 lookup_named_item (XamlElementInstance
*top
, const char *name
)
5175 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
5176 XamlElementInstance
*inst
= top
;
5179 if (inst
->element_type
== XamlElementInstance::ELEMENT
) {
5180 ResourceDictionary
*rd
= NULL
;
5181 Type::Kind kind
= inst
->info
->GetKind ();
5183 if (types
->IsSubclassOf (kind
, Type::FRAMEWORKELEMENT
)) {
5184 rd
= inst
->GetAsDependencyObject ()->GetValue (UIElement::ResourcesProperty
)->AsResourceDictionary ();
5185 } else if (types
->IsSubclassOf (kind
, Type::RESOURCE_DICTIONARY
)) {
5186 rd
= (ResourceDictionary
*) inst
->GetAsDependencyObject ();
5191 Value
*res
= lookup_resource_dictionary (rd
, name
, &exists
);
5197 inst
= inst
->parent
;
5204 lookup_resource_dictionary (ResourceDictionary
*rd
, const char *name
, bool *exists
)
5207 Value
*resource_value
= rd
->Get (name
, exists
);
5208 return *exists
? new Value (*resource_value
) : NULL
;
5212 xaml_lookup_named_item (void *parser
, void *instance
, const char* name
)
5214 XamlParserInfo
*p
= (XamlParserInfo
*) parser
;
5215 XamlElementInstance
*inst
= (XamlElementInstance
*) instance
;
5219 res
= lookup_named_item (inst
, name
);
5221 XamlContext
*context
= p
->loader
->GetContext ();
5222 if (!res
&& context
)
5223 context
->internal
->LookupNamedItem (name
, &res
);
5226 Application
*app
= Application::GetCurrent ();
5228 ResourceDictionary
*rd
= app
->GetResources ();
5230 bool exists
= false;
5231 res
= lookup_resource_dictionary (rd
, name
, &exists
);
5233 if (res
&& Type::IsSubclassOf (p
->deployment
, res
->GetKind (), Type::DEPENDENCY_OBJECT
)) {
5234 DependencyObject
*dob
= res
->AsDependencyObject ();
5235 NameScope::SetNameScope (dob
, dob
->FindNameScope ());
5244 xaml_get_template_parent (void *parser
, void *element_instance
)
5246 XamlParserInfo
*p
= (XamlParserInfo
*) parser
;
5247 XamlElementInstance
*item
= (XamlElementInstance
*) element_instance
;
5249 return p
->GetTemplateParent (item
);
5253 xaml_get_element_key (void *parser
, void *element_instance
)
5255 XamlElementInstance
*item
= (XamlElementInstance
*) element_instance
;
5256 const char *key
= item
->GetKey ();
5258 key
= item
->GetName ();
5259 return g_strdup (key
);
5263 xaml_get_element_name (void *parser
, void *element_instance
)
5265 XamlElementInstance
*item
= (XamlElementInstance
*) element_instance
;
5266 return g_strdup (item
->element_name
);
5270 xaml_is_property_set (void *parser
, void *element_instance
, char *name
)
5272 XamlElementInstance
*item
= (XamlElementInstance
*) element_instance
;
5273 return item
->IsPropertySet (name
);
5277 xaml_mark_property_as_set (void *parser
, void *element_instance
, char *name
)
5279 XamlElementInstance
*item
= (XamlElementInstance
*) element_instance
;
5280 item
->MarkPropertyAsSet (g_strdup (name
));
5284 xaml_delay_set_property (void *parser
, void *element_instance
, const char *xmlns
, const char *name
, const Value
*value
)
5286 XamlElementInstance
*item
= (XamlElementInstance
*) element_instance
;
5287 item
->DelaySetProperty (xmlns
, name
, value
);
5293 default_namespace
= new DefaultNamespace ();
5294 x_namespace
= new XNamespace ();
5295 xml_namespace
= new XmlNamespace ();