diff --git a/extensions/xforms/nsIModelElementPrivate.idl b/extensions/xforms/nsIModelElementPrivate.idl index 82ece7ad5d6..336aab017ed 100644 --- a/extensions/xforms/nsIModelElementPrivate.idl +++ b/extensions/xforms/nsIModelElementPrivate.idl @@ -148,4 +148,14 @@ interface nsIModelElementPrivate : nsIXFormsModelElement * This attribute is set when the model handled xforms-ready event */ readonly attribute boolean isReady; + + /** + * Retrieves the type for an instance data node + * + * @param aInstanceData The instance data node + * @param aType The type of the node + * @param aNSURI The namespace of the type + */ + void GetTypeFromNode(in nsIDOMNode aInstanceData, out AString aType, + out AString aNSUri); }; diff --git a/extensions/xforms/nsXFormsModelElement.cpp b/extensions/xforms/nsXFormsModelElement.cpp index 96705bec2af..f2a640132f2 100644 --- a/extensions/xforms/nsXFormsModelElement.cpp +++ b/extensions/xforms/nsXFormsModelElement.cpp @@ -604,6 +604,10 @@ nsXFormsModelElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper) mInstanceDocuments = new nsXFormsModelInstanceDocuments(); NS_ASSERTION(mInstanceDocuments, "could not create mInstanceDocuments?!"); + // Initialize hash tables + NS_ENSURE_TRUE(mNodeToType.Init(), NS_ERROR_OUT_OF_MEMORY); + NS_ENSURE_TRUE(mNodeToP3PType.Init(), NS_ERROR_OUT_OF_MEMORY); + return NS_OK; } @@ -640,6 +644,12 @@ nsXFormsModelElement::Rebuild() rv = mMDG.Clear(); NS_ENSURE_SUCCESS(rv, rv); + // Clear any type information + NS_ENSURE_TRUE(mNodeToType.IsInitialized() && mNodeToP3PType.IsInitialized(), + NS_ERROR_FAILURE); + mNodeToType.Clear(); + mNodeToP3PType.Clear(); + // 2. Re-attach all elements if (mDocumentLoaded) { // if it's not during initializing phase // Copy the form control list as it stands right now. @@ -1004,9 +1014,9 @@ nsXFormsModelElement::GetTypeForControl(nsIXFormsControl *aControl, nsXFormsModelElement::GetTypeAndNSFromNode(nsIDOMNode *aInstanceData, nsAString &aType, nsAString &aNSUri) { - nsresult rv = nsXFormsUtils::ParseTypeFromNode(aInstanceData, aType, aNSUri); + nsresult rv = GetTypeFromNode(aInstanceData, aType, aNSUri); - if(rv == NS_ERROR_NOT_AVAILABLE) { + if (rv == NS_ERROR_NOT_AVAILABLE) { // if there is no type assigned, then assume that the type is 'string' aNSUri.Assign(NS_LITERAL_STRING(NS_NAMESPACE_XML_SCHEMA)); aType.Assign(NS_LITERAL_STRING("string")); @@ -1185,6 +1195,79 @@ nsXFormsModelElement::GetIsReady(PRBool *aIsReady) return NS_OK; } +NS_IMETHODIMP +nsXFormsModelElement::GetTypeFromNode(nsIDOMNode *aInstanceData, + nsAString &aType, + nsAString &aNSUri) +{ + // aInstanceData could be an instance data node or it could be an attribute + // on an instance data node (basically the node that a control is bound to). + + nsString *typeVal = nsnull; + + // Get type stored directly on instance node + nsAutoString typeAttribute; + nsCOMPtr nodeElem(do_QueryInterface(aInstanceData)); + if (nodeElem) { + nodeElem->GetAttributeNS(NS_LITERAL_STRING(NS_NAMESPACE_XML_SCHEMA_INSTANCE), + NS_LITERAL_STRING("type"), typeAttribute); + if (!typeAttribute.IsEmpty()) { + typeVal = &typeAttribute; + } + } + + // If there was no type information on the node itself, check for a type + // bound to the node via \ + if (!typeVal && !mNodeToType.Get(aInstanceData, &typeVal)) { + // No type information found + return NS_ERROR_NOT_AVAILABLE; + } + + // split type (ns:type) into namespace and type. + nsAutoString prefix; + PRInt32 separator = typeVal->FindChar(':'); + if ((PRUint32) separator == (typeVal->Length() - 1)) { + const PRUnichar *strings[] = { typeVal->get() }; + nsXFormsUtils::ReportError(NS_LITERAL_STRING("missingTypeName"), strings, 1, + mElement, nsnull); + return NS_ERROR_UNEXPECTED; + } + + if (separator == kNotFound) { + // no namespace prefix, which is valid; + prefix = EmptyString(); + aType.Assign(*typeVal); + } else { + prefix.Assign(Substring(*typeVal, 0, separator)); + aType.Assign(Substring(*typeVal, ++separator, typeVal->Length())); + } + + if (prefix.IsEmpty()) { + aNSUri = EmptyString(); + return NS_OK; + } + + // get the namespace url from the prefix using instance data node + nsresult rv; + nsCOMPtr domNode3 = do_QueryInterface(aInstanceData, &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = domNode3->LookupNamespaceURI(prefix, aNSUri); + + if (DOMStringIsNull(aNSUri)) { + // if not found using instance data node, use node + nsCOMPtr instanceNode; + rv = nsXFormsUtils::GetInstanceNodeForData(aInstanceData, + getter_AddRefs(instanceNode)); + NS_ENSURE_SUCCESS(rv, rv); + + domNode3 = do_QueryInterface(instanceNode, &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = domNode3->LookupNamespaceURI(prefix, aNSUri); + } + + return rv; +} + // nsIXFormsContextControl NS_IMETHODIMP @@ -1487,15 +1570,6 @@ nsXFormsModelElement::MaybeNotifyCompletion() } } -static void -DeleteAutoString(void *aObject, - nsIAtom *aPropertyName, - void *aPropertyValue, - void *aData) -{ - delete NS_STATIC_CAST(nsAutoString*, aPropertyValue); -} - nsresult nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, nsIDOMNode *aContextNode, @@ -1582,33 +1656,24 @@ nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, // type and p3ptype are stored as properties on the instance node if (j == eModel_type || j == eModel_p3ptype) { - nsAutoPtr prop (new nsAutoString(propStrings[j])); - nsCOMPtr content = do_QueryInterface(node); - if (content) { - rv = content->SetProperty(sModelPropsList[j], - prop, - DeleteAutoString); - } else { - nsCOMPtr attribute = do_QueryInterface(node); - if (attribute) { - rv = attribute->SetProperty(sModelPropsList[j], - prop, - DeleteAutoString); - } else { - NS_WARNING("node is neither nsIContent or nsIAttribute"); - continue; - } - } - if (NS_SUCCEEDED(rv)) { - prop.forget(); - } else { - return rv; - } - if (rv == NS_PROPTABLE_PROP_OVERWRITTEN) { + nsClassHashtable *table; + table = j == eModel_type ? &mNodeToType : &mNodeToP3PType; + NS_ENSURE_TRUE(table->IsInitialized(), NS_ERROR_FAILURE); + + // Check for existing value + if (table->Get(node, nsnull)) { multiMIP = PR_TRUE; break; } + // Insert value + nsAutoPtr newString(new nsString(propStrings[j])); + NS_ENSURE_TRUE(newString, NS_ERROR_OUT_OF_MEMORY); + NS_ENSURE_TRUE(table->Put(node, newString), NS_ERROR_OUT_OF_MEMORY); + + // string is succesfully stored in the table, we should not dealloc it + newString.forget(); + if (j == eModel_type) { // Inform MDG that it needs to check type. The only arguments // actually used are |eModel_constraint| and |node|. diff --git a/extensions/xforms/nsXFormsModelElement.h b/extensions/xforms/nsXFormsModelElement.h index 97a3129b12f..3c3cbff4256 100644 --- a/extensions/xforms/nsXFormsModelElement.h +++ b/extensions/xforms/nsXFormsModelElement.h @@ -288,6 +288,21 @@ private: // Indicates whether the model's instance was built by lazy authoring PRBool mLazyModel; + + /** + * Type information for nodes, with their type set through \. + * + * @see http://www.w3.org/TR/xforms/slice6.html#model-prop-type + */ + nsClassHashtable mNodeToType; + + /** + * P3P type information for nodes, with their type set through + * \. + + * @see http://www.w3.org/TR/xforms/slice6.html#model-prop-p3ptype + */ + nsClassHashtable mNodeToP3PType; }; /** diff --git a/extensions/xforms/nsXFormsSubmissionElement.cpp b/extensions/xforms/nsXFormsSubmissionElement.cpp index 8ba56052fa2..284c7573146 100644 --- a/extensions/xforms/nsXFormsSubmissionElement.cpp +++ b/extensions/xforms/nsXFormsSubmissionElement.cpp @@ -1279,7 +1279,7 @@ nsXFormsSubmissionElement::CopyChildren(nsIDOMNode *source, nsIDOMNode *dest, PRUint32 encType; if (attachments && - NS_SUCCEEDED(GetElementEncodingType(currentNode, &encType)) && + NS_SUCCEEDED(GetElementEncodingType(currentNode, &encType, model)) && encType == ELEMENT_ENCTYPE_URI) { // ok, looks like we have a local file to upload @@ -1744,7 +1744,9 @@ nsXFormsSubmissionElement::AppendPostDataChunk(nsCString &postDataChunk, } nsresult -nsXFormsSubmissionElement::GetElementEncodingType(nsIDOMNode *node, PRUint32 *encType) +nsXFormsSubmissionElement::GetElementEncodingType(nsIDOMNode *node, + PRUint32 *encType, + nsIModelElementPrivate *aModel) { *encType = ELEMENT_ENCTYPE_STRING; // default @@ -1753,7 +1755,12 @@ nsXFormsSubmissionElement::GetElementEncodingType(nsIDOMNode *node, PRUint32 *en // check for 'xsd:base64Binary', 'xsd:hexBinary', or 'xsd:anyURI' nsAutoString type, nsuri; - nsresult rv = nsXFormsUtils::ParseTypeFromNode(node, type, nsuri); + nsresult rv; + if (aModel) { + rv = aModel->GetTypeFromNode(node, type, nsuri); + } else { + rv = nsXFormsUtils::ParseTypeFromNode(node, type, nsuri); + } if (NS_SUCCEEDED(rv) && nsuri.EqualsLiteral(NS_NAMESPACE_XML_SCHEMA) && !type.IsEmpty()) diff --git a/extensions/xforms/nsXFormsSubmissionElement.h b/extensions/xforms/nsXFormsSubmissionElement.h index 0adae400f4b..142543536bb 100644 --- a/extensions/xforms/nsXFormsSubmissionElement.h +++ b/extensions/xforms/nsXFormsSubmissionElement.h @@ -112,7 +112,7 @@ public: NS_HIDDEN_(nsresult) SerializeDataMultipartFormData(nsIDOMNode *data, nsIInputStream **, nsCString &contentType); NS_HIDDEN_(nsresult) AppendMultipartFormData(nsIDOMNode *data, const nsCString &boundary, nsCString &buf, nsIMultiplexInputStream *); NS_HIDDEN_(nsresult) AppendPostDataChunk(nsCString &postDataChunk, nsIMultiplexInputStream *multiStream); - NS_HIDDEN_(nsresult) GetElementEncodingType(nsIDOMNode *data, PRUint32 *encType); + NS_HIDDEN_(nsresult) GetElementEncodingType(nsIDOMNode *data, PRUint32 *encType, nsIModelElementPrivate* aModel = nsnull); NS_HIDDEN_(nsresult) CreateFileStream(const nsString &absURI, nsIFile **file, nsIInputStream **stream); NS_HIDDEN_(nsresult) SendData(const nsCString &uri, nsIInputStream *stream, const nsCString &contentType); diff --git a/extensions/xforms/nsXFormsUploadElement.cpp b/extensions/xforms/nsXFormsUploadElement.cpp index 09d4c9199bd..81bd480b721 100644 --- a/extensions/xforms/nsXFormsUploadElement.cpp +++ b/extensions/xforms/nsXFormsUploadElement.cpp @@ -146,10 +146,12 @@ nsBoundType nsXFormsUploadElement::GetBoundType() { nsBoundType result = TYPE_DEFAULT; + if (!mModel) + return result; // get type bound to node nsAutoString type, nsuri; - nsresult rv = nsXFormsUtils::ParseTypeFromNode(mBoundNode, type, nsuri); + nsresult rv = mModel->GetTypeFromNode(mBoundNode, type, nsuri); if (NS_SUCCEEDED(rv) && nsuri.EqualsLiteral(NS_NAMESPACE_XML_SCHEMA)) { if (type.EqualsLiteral("anyURI")) { result = TYPE_ANYURI; diff --git a/extensions/xforms/nsXFormsUtils.cpp b/extensions/xforms/nsXFormsUtils.cpp index 7a333db2bab..40aa197d74e 100644 --- a/extensions/xforms/nsXFormsUtils.cpp +++ b/extensions/xforms/nsXFormsUtils.cpp @@ -1260,89 +1260,26 @@ nsXFormsUtils::GetInstanceNodeForData(nsIDOMNode *aInstanceDataNode, } /* static */ nsresult -nsXFormsUtils::ParseTypeFromNode(nsIDOMNode *aInstanceData, - nsAString &aType, nsAString &aNSUri) +nsXFormsUtils::ParseTypeFromNode(nsIDOMNode *aInstanceData, + nsAString &aType, + nsAString &aNSUri) { - nsresult rv = NS_OK; + nsresult rv; - // aInstanceData could be an instance data node or it could be an attribute - // on an instance data node (basically the node that a control is bound to). + // Find the model for the instance data node + nsCOMPtr instanceNode; + rv = nsXFormsUtils::GetInstanceNodeForData(aInstanceData, + getter_AddRefs(instanceNode)); + NS_ENSURE_SUCCESS(rv, rv); - nsAutoString *typeVal = nsnull; + nsCOMPtr modelNode; + rv = instanceNode->GetParentNode(getter_AddRefs(modelNode)); + NS_ENSURE_SUCCESS(rv, rv); - // Get type stored directly on instance node - nsAutoString typeAttribute; - nsCOMPtr nodeElem(do_QueryInterface(aInstanceData)); - if (nodeElem) { - nodeElem->GetAttributeNS(NS_LITERAL_STRING(NS_NAMESPACE_XML_SCHEMA_INSTANCE), - NS_LITERAL_STRING("type"), typeAttribute); - if (!typeAttribute.IsEmpty()) { - typeVal = &typeAttribute; - } - } + nsCOMPtr model(do_QueryInterface(modelNode)); + NS_ENSURE_STATE(model); - if (!typeVal) { - // Get MIP type bound to node - nsCOMPtr nodeContent(do_QueryInterface(aInstanceData)); - if (nodeContent) { - typeVal = - NS_STATIC_CAST(nsAutoString*, - nodeContent->GetProperty(nsXFormsAtoms::type, &rv)); - } else { - nsCOMPtr nodeAttribute(do_QueryInterface(aInstanceData)); - if (!nodeAttribute) - // node is neither content or attribute! - return NS_ERROR_FAILURE; - - typeVal = - NS_STATIC_CAST(nsAutoString*, - nodeAttribute->GetProperty(nsXFormsAtoms::type, &rv)); - } - } - - if (NS_FAILED(rv) || !typeVal) { - return NS_ERROR_NOT_AVAILABLE; - } - - // split type (ns:type) into namespace and type. - nsAutoString prefix; - PRInt32 separator = typeVal->FindChar(':'); - if ((PRUint32) separator == (typeVal->Length() - 1)) { - const PRUnichar *strings[] = { typeVal->get() }; - // XXX: get an element from the document this came from - ReportError(NS_LITERAL_STRING("missingTypeName"), strings, 1, nsnull, nsnull); - return NS_ERROR_UNEXPECTED; - } else if (separator == kNotFound) { - // no namespace prefix, which is valid; - prefix.AssignLiteral(""); - aType.Assign(*typeVal); - } else { - prefix.Assign(Substring(*typeVal, 0, separator)); - aType.Assign(Substring(*typeVal, ++separator, typeVal->Length())); - } - - if (prefix.IsEmpty()) { - aNSUri.AssignLiteral(""); - } else { - // get the namespace url from the prefix using instance data node - nsCOMPtr domNode3 = do_QueryInterface(aInstanceData, &rv); - NS_ENSURE_SUCCESS(rv, rv); - rv = domNode3->LookupNamespaceURI(prefix, aNSUri); - - if (DOMStringIsNull(aNSUri)) { - // if not found using instance data node, use node - nsCOMPtr instanceNode; - rv = nsXFormsUtils::GetInstanceNodeForData(aInstanceData, - getter_AddRefs(instanceNode)); - NS_ENSURE_SUCCESS(rv, rv); - - domNode3 = do_QueryInterface(instanceNode, &rv); - NS_ENSURE_SUCCESS(rv, rv); - rv = domNode3->LookupNamespaceURI(prefix, aNSUri); - } - } - - return rv; + return model->GetTypeFromNode(aInstanceData, aType, aNSUri); } /* static */ void