Back to index

lightning-sunbird  0.9+nobinonly
nsXFormsUtils.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla XForms support.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * IBM Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Brian Ryner <bryner@brianryner.com>
00024  *  Allan Beaufour <abeaufour@novell.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsXFormsUtils.h"
00041 #include "nsString.h"
00042 #include "nsXFormsAtoms.h"
00043 #include "nsIDOMElement.h"
00044 #include "nsIDOMNSHTMLElement.h"
00045 #include "nsIDocument.h"
00046 #include "nsIDOMDocumentXBL.h"
00047 #include "nsINameSpaceManager.h"
00048 #include "nsIDOMNodeList.h"
00049 #include "nsIXFormsXPathEvaluator.h"
00050 #include "nsIDOMXPathResult.h"
00051 #include "nsIDOMXPathNSResolver.h"
00052 #include "nsIDOMDocument.h"
00053 #include "nsIDOMText.h"
00054 #include "nsIModelElementPrivate.h"
00055 #include "nsIXFormsModelElement.h"
00056 #include "nsIXFormsControl.h"
00057 #include "nsIInstanceElementPrivate.h"
00058 #include "nsIDOMNSDocument.h"
00059 #include "nsIDOMLocation.h"
00060 #include "nsIDOMSerializer.h"
00061 #include "nsIContent.h"
00062 #include "nsIAttribute.h"
00063 #include "nsXFormsAtoms.h"
00064 #include "nsIXFormsRepeatElement.h"
00065 #include "nsIContentPolicy.h"
00066 #include "nsContentUtils.h"
00067 #include "nsContentPolicyUtils.h"
00068 #include "nsIXFormsContextControl.h"
00069 #include "nsIDOMDocumentEvent.h"
00070 #include "nsIDOMEvent.h"
00071 #include "nsIDOMEventTarget.h"
00072 #include "nsDataHashtable.h"
00073 
00074 #include "nsAutoPtr.h"
00075 #include "nsXFormsXPathAnalyzer.h"
00076 #include "nsXFormsXPathParser.h"
00077 #include "nsXFormsXPathNode.h"
00078 #include "nsIDOMNSXPathExpression.h"
00079 
00080 #include "nsIScriptSecurityManager.h"
00081 #include "nsIPermissionManager.h"
00082 #include "nsServiceManagerUtils.h"
00083 #include "nsIXFormsUtilityService.h"
00084 #include "nsIDOMAttr.h"
00085 #include "nsIDOM3Node.h"
00086 #include "nsIConsoleService.h"
00087 #include "nsIStringBundle.h"
00088 #include "nsIDOMNSEvent.h"
00089 #include "nsIURI.h"
00090 #include "nsIPrivateDOMEvent.h"
00091 #include "nsIDOMNamedNodeMap.h"
00092 #include "nsIParserService.h"
00093 
00094 #include "nsIPrefBranch.h"
00095 #include "nsIPrefService.h"
00096 #include "nsIDOMDocumentView.h"
00097 #include "nsIDOMAbstractView.h"
00098 #include "nsPIDOMWindow.h"
00099 
00100 #include "nsIDOMDocumentType.h"
00101 #include "nsIDOMEntity.h"
00102 #include "nsIDOMNotation.h"
00103 #include "nsIEventStateManager.h"
00104 #include "nsXFormsModelElement.h"
00105 
00106 #include "prtime.h"
00107 #include "nsIScriptGlobalObject.h"
00108 #include "nsIInterfaceRequestor.h"
00109 #include "nsIInterfaceRequestorUtils.h"
00110 #include "nsIPrompt.h"
00111 
00112 // For locale aware string methods
00113 #include "plstr.h"
00114 
00115 #define CANCELABLE 0x01
00116 #define BUBBLES    0x02
00117 
00118 const EventData sXFormsEventsEntries[43] = {
00119   { "xforms-model-construct",      PR_FALSE, PR_TRUE  },
00120   { "xforms-model-construct-done", PR_FALSE, PR_TRUE  },
00121   { "xforms-ready",                PR_FALSE, PR_TRUE  },
00122   { "xforms-model-destruct",       PR_FALSE, PR_TRUE  },
00123   { "xforms-previous",             PR_TRUE,  PR_FALSE },
00124   { "xforms-next",                 PR_TRUE,  PR_FALSE },
00125   { "xforms-focus",                PR_TRUE,  PR_FALSE },
00126   { "xforms-help",                 PR_TRUE,  PR_TRUE  },
00127   { "xforms-hint",                 PR_TRUE,  PR_TRUE  },
00128   { "xforms-rebuild",              PR_TRUE,  PR_TRUE  },
00129   { "xforms-refresh",              PR_TRUE,  PR_TRUE  },
00130   { "xforms-revalidate",           PR_TRUE,  PR_TRUE  },
00131   { "xforms-recalculate",          PR_TRUE,  PR_TRUE  },
00132   { "xforms-reset",                PR_TRUE,  PR_TRUE  },
00133   { "xforms-submit",               PR_TRUE,  PR_TRUE  },
00134   { "DOMActivate",                 PR_TRUE,  PR_TRUE  },
00135   { "xforms-value-changed",        PR_FALSE, PR_TRUE  },
00136   { "xforms-select",               PR_FALSE, PR_TRUE  },
00137   { "xforms-deselect",             PR_FALSE, PR_TRUE  },
00138   { "xforms-scroll-first",         PR_FALSE, PR_TRUE  },
00139   { "xforms-scroll-last",          PR_FALSE, PR_TRUE  },
00140   { "xforms-insert",               PR_FALSE, PR_TRUE  },
00141   { "xforms-delete",               PR_FALSE, PR_TRUE  },
00142   { "xforms-valid",                PR_FALSE, PR_TRUE  },
00143   { "xforms-invalid",              PR_FALSE, PR_TRUE  },
00144   { "DOMFocusIn",                  PR_FALSE, PR_TRUE  },
00145   { "DOMFocusOut",                 PR_FALSE, PR_TRUE  },
00146   { "xforms-readonly",             PR_FALSE, PR_TRUE  },
00147   { "xforms-readwrite",            PR_FALSE, PR_TRUE  },
00148   { "xforms-required",             PR_FALSE, PR_TRUE  },
00149   { "xforms-optional",             PR_FALSE, PR_TRUE  },
00150   { "xforms-enabled",              PR_FALSE, PR_TRUE  },
00151   { "xforms-disabled",             PR_FALSE, PR_TRUE  },
00152   { "xforms-in-range",             PR_FALSE, PR_TRUE  },
00153   { "xforms-out-of-range",         PR_FALSE, PR_TRUE  },
00154   { "xforms-submit-done",          PR_FALSE, PR_TRUE  },
00155   { "xforms-submit-error",         PR_FALSE, PR_TRUE  },
00156   { "xforms-binding-exception",    PR_FALSE, PR_TRUE  },
00157   { "xforms-link-exception",       PR_FALSE, PR_TRUE  },
00158   { "xforms-link-error",           PR_FALSE, PR_TRUE  },
00159   { "xforms-compute-exception",    PR_FALSE, PR_TRUE  },
00160   { "xforms-moz-hint-off",         PR_FALSE, PR_TRUE  },
00161   { "xforms-submit-serialize",     PR_FALSE, PR_TRUE  }
00162 };
00163 
00164 static const EventData sEventDefaultsEntries[] = {
00165   //UIEvents already in sXFormsEvents
00166   
00167   //MouseEvent
00168   { "click",                       PR_TRUE,  PR_TRUE  },
00169   { "mousedown",                   PR_TRUE,  PR_TRUE  },
00170   { "mouseup",                     PR_TRUE,  PR_TRUE  },
00171   { "mouseover",                   PR_TRUE,  PR_TRUE  },
00172   { "mousemove",                   PR_FALSE, PR_TRUE  },
00173   { "mouseout",                    PR_TRUE,  PR_TRUE  },
00174   //MutationEvent
00175   { "DOMSubtreeModified",          PR_FALSE, PR_TRUE  },
00176   { "DOMNodeInserted",             PR_FALSE, PR_TRUE  },
00177   { "DOMNodeRemoved",              PR_FALSE, PR_TRUE  },
00178   { "DOMNodeRemovedFromDocument",  PR_FALSE, PR_FALSE },
00179   { "DOMNodeInsertedIntoDocument", PR_FALSE, PR_FALSE },
00180   { "DOMAttrModified",             PR_FALSE, PR_TRUE  },
00181   { "DOMCharacterDataModified",    PR_FALSE, PR_TRUE  },
00182   //HTMLEvents
00183   { "load",                        PR_FALSE, PR_FALSE },
00184   { "unload",                      PR_FALSE, PR_FALSE },
00185   { "abort",                       PR_FALSE, PR_TRUE  },
00186   { "error",                       PR_FALSE, PR_TRUE  },
00187   { "select",                      PR_FALSE, PR_TRUE  },
00188   { "change",                      PR_FALSE, PR_TRUE  },
00189   { "submit",                      PR_TRUE,  PR_TRUE  },
00190   { "reset",                       PR_FALSE, PR_TRUE  },
00191   { "focus",                       PR_FALSE, PR_FALSE },
00192   { "blur",                        PR_FALSE, PR_FALSE },
00193   { "resize",                      PR_FALSE, PR_TRUE  },
00194   { "scroll",                      PR_FALSE, PR_TRUE  }
00195 };
00196 
00197 static nsDataHashtable<nsStringHashKey,PRUint32> sXFormsEvents;
00198 static nsDataHashtable<nsStringHashKey,PRUint32> sEventDefaults;
00199 
00200 const PRInt32 kDefaultIntrinsicState =
00201   NS_EVENT_STATE_ENABLED |
00202   NS_EVENT_STATE_VALID |
00203   NS_EVENT_STATE_OPTIONAL |
00204   NS_EVENT_STATE_MOZ_READWRITE;
00205 
00206 const PRInt32 kDisabledIntrinsicState =
00207   NS_EVENT_STATE_DISABLED |
00208   NS_EVENT_STATE_VALID |
00209   NS_EVENT_STATE_OPTIONAL |
00210   NS_EVENT_STATE_MOZ_READWRITE;
00211 
00212 struct EventItem
00213 {
00214   nsXFormsEvent           event;
00215   nsCOMPtr<nsIDOMNode>    eventTarget;
00216   nsCOMPtr<nsIDOMElement> srcElement;
00217   nsCOMArray<nsIXFormsContextInfo> *contextInfo;
00218 };
00219 
00220 PRInt32 nsXFormsUtils::waitLimit = 10;
00221 
00222 PR_STATIC_CALLBACK(int) PrefChangedCallback(const char* aPref, void* aData)
00223 {
00224   nsresult rv;
00225   nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
00226   if (NS_SUCCEEDED(rv) && pref) {
00227 
00228     // if our prefs changed, make sure to update our static variables.
00229     if (strcmp(aPref, PREF_WAIT_LIMIT) == 0) {
00230       PRInt32 val;
00231       if (NS_SUCCEEDED(pref->GetIntPref(PREF_WAIT_LIMIT, &val))) {
00232         nsXFormsUtils::waitLimit = val;
00233       }
00234     }
00235   }
00236 
00237   return 0; // PREF_OK
00238 }
00239 
00240 /* static */ nsresult
00241 nsXFormsUtils::Init()
00242 {
00243   if (!sXFormsEvents.Init())
00244     return NS_ERROR_FAILURE;
00245 
00246   unsigned int i;
00247 
00248   for (i = 0; i < NS_ARRAY_LENGTH(sXFormsEventsEntries); ++i) {
00249     PRUint32 flag = 0;
00250     if (sXFormsEventsEntries[i].canCancel)
00251       flag |= CANCELABLE;
00252     if (sXFormsEventsEntries[i].canBubble)
00253       flag |= BUBBLES;
00254     sXFormsEvents.Put(NS_ConvertUTF8toUTF16(sXFormsEventsEntries[i].name),
00255                                             flag);
00256   }
00257 
00258   if (!sEventDefaults.Init())
00259     return NS_ERROR_FAILURE;
00260   for (i = 0; i < NS_ARRAY_LENGTH(sEventDefaultsEntries); ++i) {
00261     PRUint32 flag = 0;
00262     if (sEventDefaultsEntries[i].canCancel)
00263       flag |= CANCELABLE;
00264     if (sEventDefaultsEntries[i].canBubble)
00265       flag |= BUBBLES;
00266     sEventDefaults.Put(NS_ConvertUTF8toUTF16(sEventDefaultsEntries[i].name),
00267                                              flag);
00268   }
00269 
00270   nsresult rv;
00271   nsCOMPtr<nsIPrefBranch> prefBranch =
00272     do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
00273   if (NS_SUCCEEDED(rv) && prefBranch) {
00274     PRInt32 intval;
00275     rv = prefBranch->GetIntPref(PREF_WAIT_LIMIT, &intval);
00276     if (NS_SUCCEEDED(rv)) {
00277       nsXFormsUtils::waitLimit = intval;
00278     }
00279   }
00280 
00281   nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID, &rv);
00282   NS_ENSURE_STATE(pref);
00283   rv = pref->RegisterCallback(PREF_WAIT_LIMIT,
00284                               PrefChangedCallback, nsnull);
00285   NS_ENSURE_SUCCESS(rv, rv);
00286 
00287   return NS_OK;
00288 }
00289 
00290 /* static */ nsresult
00291 nsXFormsUtils::Shutdown()
00292 {
00293   // unregister our pref listeners
00294 
00295   nsresult rv;
00296   nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID, &rv);
00297   NS_ENSURE_STATE(pref);
00298   rv = pref->UnregisterCallback(PREF_WAIT_LIMIT,
00299                                 PrefChangedCallback, nsnull);
00300   NS_ENSURE_SUCCESS(rv, rv);
00301 
00302   return NS_OK;
00303 }
00304 
00305 /* static */ PRBool
00306 nsXFormsUtils::GetParentModel(nsIDOMElement           *aBindElement,
00307                               nsIModelElementPrivate **aModel)
00308 {
00309   PRBool res = PR_TRUE;
00310   nsCOMPtr<nsIDOMNode> modelWrapper;
00311 
00312   // Walk up the tree looking for the containing model.
00313   aBindElement->GetParentNode(getter_AddRefs(modelWrapper));
00314 
00315   nsAutoString localName, namespaceURI;
00316   nsCOMPtr<nsIDOMNode> temp;
00317 
00318   while (modelWrapper) {
00319     modelWrapper->GetLocalName(localName);
00320     if (localName.EqualsLiteral("model")) {
00321       modelWrapper->GetNamespaceURI(namespaceURI);
00322       if (namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS))
00323         break;
00324     }
00325 
00326     temp.swap(modelWrapper);
00327     temp->GetParentNode(getter_AddRefs(modelWrapper));
00328 
00329     // Model is not the immediate parent, this is a reference to a nested
00330     // (invalid) bind
00331     res = PR_FALSE;
00332   }
00333   *aModel = nsnull;
00334   nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelWrapper);
00335   model.swap(*aModel);
00336 
00337   return res;
00338 }
00339 
00348 /* static */ nsresult
00349 nsXFormsUtils::GetNodeContext(nsIDOMElement           *aElement,
00350                               PRUint32                 aElementFlags,
00351                               nsIModelElementPrivate **aModel,
00352                               nsIDOMElement          **aBindElement,
00353                               PRBool                  *aOuterBind,
00354                               nsIXFormsControl       **aParentControl,
00355                               nsIDOMNode             **aContextNode,
00356                               PRInt32                 *aContextPosition,
00357                               PRInt32                 *aContextSize,
00358                               PRBool                   aUseBindAttr)
00359 {
00360   NS_ENSURE_ARG(aElement);
00361   NS_ENSURE_ARG(aOuterBind);
00362   NS_ENSURE_ARG_POINTER(aContextNode);
00363   NS_ENSURE_ARG_POINTER(aBindElement);
00364   *aBindElement = nsnull;
00365   if (aParentControl)
00366     *aParentControl = nsnull;
00367 
00368   // Set default context size and position
00369   if (aContextSize)
00370     *aContextSize = 1;
00371   if (aContextPosition)
00372     *aContextPosition = 1;
00373 
00374   // Find correct model element
00375   nsAutoString bindId;
00376   NS_NAMED_LITERAL_STRING(bindStr, "bind");
00377   aElement->GetAttribute(bindStr, bindId);
00378   if (!bindId.IsEmpty() && aUseBindAttr) {
00379     // CASE 1: Use @bind
00380     GetElementByContextId(aElement, bindId, aBindElement);
00381 
00382     if (!IsXFormsElement(*aBindElement, bindStr)) {
00383       const PRUnichar *strings[] = { bindId.get(), bindStr.get() };
00384       nsXFormsUtils::ReportError(NS_LITERAL_STRING("idRefError"),
00385                                  strings, 2, aElement, aElement);
00386       DispatchEvent(aElement, eEvent_BindingException);
00387       return NS_ERROR_ABORT;
00388     }
00389 
00390     *aOuterBind = GetParentModel(*aBindElement, aModel);
00391     NS_ENSURE_STATE(*aModel);
00392   } else {
00393     if (aElementFlags & ELEMENT_WITH_MODEL_ATTR) {
00394       // CASE 2: Use @model
00395       // If bind did not set model, and the element has a model attribute we use this
00396       nsAutoString modelId;
00397       NS_NAMED_LITERAL_STRING(modelStr, "model");
00398       aElement->GetAttribute(modelStr, modelId);
00399       
00400       if (!modelId.IsEmpty()) {
00401         nsCOMPtr<nsIDOMElement> modelElement;
00402         GetElementByContextId(aElement, modelId, getter_AddRefs(modelElement));
00403         nsCOMPtr<nsIModelElementPrivate> model = do_QueryInterface(modelElement);
00404 
00405         // No element found, or element not a <model> element
00406         if (!model) {
00407           const PRUnichar *strings[] = { modelId.get(), modelStr.get() };
00408           nsXFormsUtils::ReportError(NS_LITERAL_STRING("idRefError"),
00409                                      strings, 2, aElement, aElement);
00410           nsXFormsUtils::DispatchEvent(aElement, eEvent_BindingException);        
00411           return NS_ERROR_FAILURE;
00412         }
00413         
00414         NS_ADDREF(*aModel = model);
00415       }
00416     }
00417 
00418     // Search for a parent setting context for us
00419     nsresult rv = FindParentContext(aElement,
00420                                     aModel,
00421                                     aParentControl,
00422                                     aContextNode,
00423                                     aContextPosition,
00424                                     aContextSize);
00425     // CASE 3/4: Use parent's model / first model in document.
00426     // If FindParentContext() does not find a parent context but |aModel| is not
00427     // set, it sets the model to the first model in the document.
00428   
00429     NS_ENSURE_SUCCESS(rv, rv);
00430     if (rv == NS_OK_XFORMS_NOTREADY) {
00431       return rv;
00432     }
00433   }
00434 
00435   // if context node is not set, it's the document element of the model's
00436   // default instance
00437   if (!*aContextNode) {
00438     nsCOMPtr<nsIXFormsModelElement> modelInt = do_QueryInterface(*aModel);
00439     NS_ENSURE_STATE(modelInt);
00440 
00441     nsCOMPtr<nsIDOMDocument> instanceDoc;
00442     modelInt->GetInstanceDocument(EmptyString(),
00443                                   getter_AddRefs(instanceDoc));
00444     NS_ENSURE_STATE(instanceDoc);
00445 
00446     nsIDOMElement* docElement;
00447     instanceDoc->GetDocumentElement(&docElement); // addrefs
00448     NS_ENSURE_STATE(docElement);
00449     *aContextNode = docElement; // addref'ed above
00450   }  
00451 
00452   return NS_OK;
00453 }
00454 
00455 /* static */ already_AddRefed<nsIModelElementPrivate>
00456 nsXFormsUtils::GetModel(nsIDOMElement     *aElement,
00457                         nsIXFormsControl **aParentControl,
00458                         PRUint32           aElementFlags,
00459                         nsIDOMNode       **aContextNode)
00460 
00461 {
00462   nsCOMPtr<nsIModelElementPrivate> model;
00463   nsCOMPtr<nsIDOMNode> contextNode;
00464   nsCOMPtr<nsIDOMElement> bind;
00465   PRBool outerbind;
00466 
00467   GetNodeContext(aElement,
00468                  aElementFlags,
00469                  getter_AddRefs(model),
00470                  getter_AddRefs(bind),
00471                  &outerbind,
00472                  aParentControl,
00473                  getter_AddRefs(contextNode));
00474 
00475   NS_ENSURE_TRUE(model, nsnull);
00476 
00477   if (aContextNode) {
00478     NS_IF_ADDREF(*aContextNode = contextNode);
00479   }
00480 
00481   nsIModelElementPrivate *result = nsnull;
00482   if (model)
00483     NS_ADDREF(result = model);
00484   return result;
00485 }
00486 
00487 /* static */ nsresult
00488 nsXFormsUtils::EvaluateXPath(const nsAString        &aExpression,
00489                              nsIDOMNode             *aContextNode,
00490                              nsIDOMNode             *aResolverNode,
00491                              PRUint16                aResultType,
00492                              nsIDOMXPathResult     **aResult,
00493                              PRInt32                 aContextPosition,
00494                              PRInt32                 aContextSize,
00495                              nsCOMArray<nsIDOMNode> *aSet,
00496                              nsStringArray          *aIndexesUsed)
00497 {
00498   NS_ENSURE_ARG_POINTER(aResult);
00499   *aResult = nsnull;
00500 
00501   nsCOMPtr<nsIXFormsXPathEvaluator> eval = 
00502            do_CreateInstance("@mozilla.org/dom/xforms-xpath-evaluator;1");
00503   NS_ENSURE_STATE(eval);
00504 
00505   nsCOMPtr<nsIDOMNSXPathExpression> expression;
00506   nsresult rv = eval->CreateExpression(aExpression, aResolverNode, aContextNode,
00507                          getter_AddRefs(expression));
00508   PRBool throwException = PR_FALSE;
00509   if (!expression) {
00510     const nsPromiseFlatString& flat = PromiseFlatString(aExpression);
00511     const PRUnichar *strings[] = { flat.get() };
00512     nsXFormsUtils::ReportError(NS_LITERAL_STRING("exprParseError"),
00513                                strings, 1, aContextNode, nsnull);
00514     throwException = PR_TRUE;
00515   } else {
00516     nsCOMPtr<nsISupports> supResult;
00517     rv = expression->EvaluateWithContext(aContextNode,
00518                                          aContextPosition,
00519                                          aContextSize,
00520                                          aResultType,
00521                                          nsnull,
00522                                          getter_AddRefs(supResult));
00523 
00524     if (NS_SUCCEEDED(rv) && supResult) {
00528       if (aSet) {
00529         nsXFormsXPathParser parser;
00530         nsXFormsXPathAnalyzer analyzer(eval, aResolverNode, aContextNode);
00531         nsAutoPtr<nsXFormsXPathNode> xNode(parser.Parse(aExpression));
00532         rv = analyzer.Analyze(aContextNode,
00533                               xNode,
00534                               expression,
00535                               &aExpression,
00536                               aSet,
00537                               aContextPosition,
00538                               aContextSize,
00539                               aResultType == nsIDOMXPathResult::STRING_TYPE);
00540         NS_ENSURE_SUCCESS(rv, rv);
00541 
00542         if (aIndexesUsed)
00543           *aIndexesUsed = analyzer.IndexesUsed();
00544       }
00545 
00546       CallQueryInterface(supResult, aResult);  // addrefs
00547       return NS_OK;
00548     }
00549 
00550     if (rv == NS_ERROR_XFORMS_CALCUATION_EXCEPTION) {
00551       const nsPromiseFlatString& flat = PromiseFlatString(aExpression);
00552       const PRUnichar *strings[] = { flat.get() };
00553       nsXFormsUtils::ReportError(NS_LITERAL_STRING("exprEvaluateError"),
00554                                  strings, 1, aContextNode, nsnull);
00555       throwException = PR_TRUE;
00556     }
00557   }
00558 
00559   // Throw xforms-compute-exception
00560   if (throwException) {
00561     nsCOMPtr<nsIDOMElement> resolverElement = do_QueryInterface(aResolverNode);
00562     nsCOMPtr<nsIModelElementPrivate> modelPriv = nsXFormsUtils::GetModel(resolverElement);
00563     nsCOMPtr<nsIDOMNode> model = do_QueryInterface(modelPriv);
00564 
00565     // Context Info: 'error-message'
00566     // Error message containing the expression being processed.
00567     nsAutoString errorMsg;
00568     errorMsg.AssignLiteral("Error evaluating expression: ");
00569     errorMsg.Append(aExpression);
00570 
00571     nsCOMPtr<nsXFormsContextInfo> contextInfo =
00572       new nsXFormsContextInfo(resolverElement);
00573     NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY);
00574     contextInfo->SetStringValue("error-message", errorMsg);
00575     nsCOMArray<nsIXFormsContextInfo> contextInfoArray;
00576     contextInfoArray.AppendObject(contextInfo);
00577     DispatchEvent(model, eEvent_ComputeException, nsnull, resolverElement,
00578                   &contextInfoArray);
00579   }
00580 
00581   return rv;
00582 }
00583 
00584 /* static */ nsresult
00585 nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement           *aElement,
00586                                    PRUint32                 aElementFlags,
00587                                    const nsString          &aBindingAttr,
00588                                    const nsString          &aDefaultRef,
00589                                    PRUint16                 aResultType,
00590                                    nsIModelElementPrivate **aModel,
00591                                    nsIDOMXPathResult      **aResult,
00592                                    PRBool                  *aUsesModelBind,
00593                                    nsIXFormsControl       **aParentControl,
00594                                    nsCOMArray<nsIDOMNode>  *aDeps,
00595                                    nsStringArray           *aIndexesUsed)
00596 {
00597   if (!aElement || !aModel || !aResult || !aUsesModelBind) {
00598     return NS_ERROR_FAILURE;
00599   }
00600 
00601   *aModel = nsnull;
00602   *aResult = nsnull;
00603   *aUsesModelBind = PR_FALSE;
00604 
00605   nsCOMPtr<nsIDOMNode>    contextNode;
00606   nsCOMPtr<nsIDOMElement> bindElement;
00607   PRBool outerBind;
00608   PRInt32 contextPosition;
00609   PRInt32 contextSize;
00610   nsresult rv = GetNodeContext(aElement,
00611                                aElementFlags,
00612                                aModel,
00613                                getter_AddRefs(bindElement),
00614                                &outerBind,
00615                                aParentControl,
00616                                getter_AddRefs(contextNode),
00617                                &contextPosition,
00618                                &contextSize);
00619 
00620   NS_ENSURE_SUCCESS(rv, rv);
00621   if (rv == NS_OK_XFORMS_NOTREADY) {
00622     return rv;
00623   }
00624 
00625   if (!contextNode) {
00626     return NS_OK;   // this will happen if the doc is still loading
00627   }
00628 
00630   // STEP 1: Handle @bind'ings
00631   if (bindElement) {
00632     if (outerBind) {
00633       // If there is an outer bind element, we retrieve its nodeset.
00634       nsCOMPtr<nsIContent> content(do_QueryInterface(bindElement));
00635       NS_ASSERTION(content, "nsIDOMElement not implementing nsIContent?!");
00636 
00637       NS_IF_ADDREF(*aResult =
00638                    NS_STATIC_CAST(nsIDOMXPathResult*,
00639                                   content->GetProperty(nsXFormsAtoms::bind)));
00640       *aUsesModelBind = PR_TRUE;
00641       return NS_OK;
00642     }
00643 
00644     // References to inner binds are not defined.
00645     // "When you refer to @id on a nested bind it returns an emtpy nodeset
00646     // because it has no meaning. The XForms WG will assign meaning in the
00647     // future."
00648     // @see http://www.w3.org/MarkUp/Group/2004/11/f2f/2004Nov11#resolution6
00649     nsXFormsUtils::ReportError(NS_LITERAL_STRING("innerBindRefError"),
00650                                aElement);
00651     return NS_ERROR_FAILURE;
00652   }
00653 
00654 
00656   // STEP 2: No bind attribute
00657   // If there's no bind attribute, we expect there to be a |aBindingAttr|
00658   // attribute.
00659   nsAutoString expr;
00660   aElement->GetAttribute(aBindingAttr, expr);
00661   if (expr.IsEmpty()) {
00662     // if there's no default binding, bail out
00663     if (aDefaultRef.IsEmpty())
00664       return NS_OK;
00665 
00666     expr.Assign(aDefaultRef);
00667   }
00668 
00669   // Evaluate |expr|
00670   nsCOMPtr<nsIDOMXPathResult> res;
00671   rv  = EvaluateXPath(expr, contextNode, aElement, aResultType,
00672                       getter_AddRefs(res), contextPosition, contextSize,
00673                       aDeps, aIndexesUsed);
00674   NS_ENSURE_SUCCESS(rv, rv);
00675 
00677   // STEP 3: Check for lazy binding
00678 
00679   // If the evaluation failed because the node wasn't there and we should be
00680   // lazy authoring, then create it (if the situation qualifies, of course).
00681   // Novell only allows lazy authoring of single bound nodes.
00682   if (aResultType == nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE) {
00683     if (res) {
00684       nsCOMPtr<nsIDOMNode> node;
00685       rv = res->GetSingleNodeValue(getter_AddRefs(node));
00686       if (NS_SUCCEEDED(rv) && !node) {
00687         PRBool lazy = PR_FALSE;
00688         if (*aModel)
00689           (*aModel)->GetLazyAuthored(&lazy);
00690         if (lazy) {
00691           // according to sec 4.2.2 in the spec, "An instance data element node
00692           // will be created using the binding expression from the user
00693           // interface control as the name. If the name is not a valid QName, 
00694           // processing halts with an exception (xforms-binding-exception)"
00695           nsCOMPtr<nsIParserService> parserService =
00696                                     do_GetService(NS_PARSERSERVICE_CONTRACTID);
00697           if (NS_SUCCEEDED(rv) && parserService) {
00698             const PRUnichar* colon;
00699             rv = parserService->CheckQName(expr, PR_TRUE, &colon);
00700             if (NS_SUCCEEDED(rv)) {
00701               nsAutoString namespaceURI(EmptyString());
00702 
00703               // if we detect a namespace, we'll add it to the node, otherwise
00704               // we'll use the empty namespace.  If we should have gotten a
00705               // namespace and didn't, then we might as well give up.
00706               if (colon) {
00707                 nsCOMPtr<nsIDOM3Node> dom3node = do_QueryInterface(aElement);
00708                 rv = dom3node->LookupNamespaceURI(Substring(expr.get(), colon), 
00709                                                   namespaceURI);
00710                 NS_ENSURE_SUCCESS(rv, rv);
00711               }
00712 
00713               if (NS_SUCCEEDED(rv)) {
00714                 nsCOMPtr<nsIInstanceElementPrivate> instance;
00715                 rv = (*aModel)->FindInstanceElement(EmptyString(),
00716                                                     getter_AddRefs(instance));
00717                 NS_ENSURE_SUCCESS(rv, rv);
00718                 nsCOMPtr<nsIDOMDocument> domdoc;
00719                 instance->GetInstanceDocument(getter_AddRefs(domdoc));
00720                 nsCOMPtr<nsIDOMElement> instanceDataEle;
00721                 nsCOMPtr<nsIDOMNode> childReturn;
00722                 rv = domdoc->CreateElementNS(namespaceURI, expr,
00723                                              getter_AddRefs(instanceDataEle));
00724                 NS_ENSURE_SUCCESS(rv, rv);
00725                 nsCOMPtr<nsIDOMElement> instanceRoot;
00726                 rv = domdoc->GetDocumentElement(getter_AddRefs(instanceRoot));
00727                 rv = instanceRoot->AppendChild(instanceDataEle, 
00728                                                getter_AddRefs(childReturn));
00729                 NS_ENSURE_SUCCESS(rv, rv);
00730               }
00731 
00732               // now that we inserted the lazy authored node, try to bind
00733               // again
00734               rv = EvaluateXPath(expr, contextNode, aElement, aResultType,
00735                                  getter_AddRefs(res), contextPosition,
00736                                  contextSize, aDeps, aIndexesUsed);
00737               NS_ENSURE_SUCCESS(rv, rv);
00738             } else {
00739                 const PRUnichar *strings[] = { expr.get() };
00740                 nsXFormsUtils::ReportError(NS_LITERAL_STRING("invalidQName"),
00741                                            strings, 1, aElement, aElement);
00742               nsXFormsUtils::DispatchEvent(aElement, eEvent_BindingException);
00743             }
00744           }
00745         }
00746       }
00747     }
00748   }
00749 
00750   res.swap(*aResult); // exchanges ref
00751 
00752   return NS_OK;
00753 }
00754 
00755 /* static */ void
00756 nsXFormsUtils::GetNodeValue(nsIDOMNode* aDataNode, nsAString& aNodeValue)
00757 {
00758   PRUint16 nodeType;
00759   aDataNode->GetNodeType(&nodeType);
00760   aNodeValue = EmptyString();
00761 
00762   switch(nodeType) {
00763   case nsIDOMNode::ATTRIBUTE_NODE:
00764   case nsIDOMNode::TEXT_NODE:
00765   case nsIDOMNode::CDATA_SECTION_NODE:
00766     // "Returns the string-value of the node."
00767     aDataNode->GetNodeValue(aNodeValue);
00768     break;
00769 
00770   case nsIDOMNode::ELEMENT_NODE:
00771     {
00772       // XForms specs 8.1.1 (http://www.w3.org/TR/xforms/slice8.html#ui-processing)
00773       // says: 'if text child nodes are present, returns the string-value of the
00774       // first text child node. Otherwise, returns "" (the empty string)'.
00775       // The 'text child node' that is mentioned above is from the xforms
00776       // instance document which is, according to spec, is formed by
00777       // 'creating an XPath data model'. So we need to treat 'text node' in
00778       // this case as an XPath text node and not a DOM text node.
00779       // DOM XPath specs (http://www.w3.org/TR/2002/WD-DOM-Level-3-XPath-20020328/xpath.html#TextNodes)
00780       // says:
00781       // 'Applications using XPath in an environment with fragmented text nodes
00782       // must manually gather the text of a single logical text node possibly
00783       // from multiple nodes beginning with the first Text node or CDATASection
00784       // node returned by the implementation'.
00785 
00786       // Therefore we concatenate contiguous CDATA/DOM text nodes and return
00787       // as node value.
00788 
00789       // Find the first child text node.
00790       nsCOMPtr<nsIDOMNodeList> childNodes;
00791       aDataNode->GetChildNodes(getter_AddRefs(childNodes));
00792 
00793       if (childNodes) {
00794         nsCOMPtr<nsIDOMNode> child;
00795         PRUint32 childCount;
00796         childNodes->GetLength(&childCount);
00797 
00798         nsAutoString value;
00799         for (PRUint32 i = 0; i < childCount; ++i) {
00800           childNodes->Item(i, getter_AddRefs(child));
00801           NS_ASSERTION(child, "DOMNodeList length is wrong!");
00802 
00803           child->GetNodeType(&nodeType);
00804           if (nodeType == nsIDOMNode::TEXT_NODE ||
00805               nodeType == nsIDOMNode::CDATA_SECTION_NODE) {
00806             child->GetNodeValue(value);
00807             aNodeValue.Append(value);
00808           } else {
00809             break;
00810           }
00811         }
00812       }
00813 
00814       // No child text nodes.  Return an empty string.
00815     }
00816     break;
00817           
00818   case nsIDOMNode::ENTITY_REFERENCE_NODE:
00819   case nsIDOMNode::ENTITY_NODE:
00820   case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
00821   case nsIDOMNode::COMMENT_NODE:
00822   case nsIDOMNode::DOCUMENT_NODE:
00823   case nsIDOMNode::DOCUMENT_TYPE_NODE:
00824   case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
00825   case nsIDOMNode::NOTATION_NODE:
00826     // String value for these node types is not defined, ie. return the empty
00827     // string.
00828     break;
00829 
00830   default:
00831     NS_ASSERTION(PR_FALSE, "Huh? New node type added to Gecko?!");
00832   }
00833 }
00834 
00835 /* static */ PRBool
00836 nsXFormsUtils::GetSingleNodeBinding(nsIDOMElement* aElement,
00837                                     nsIDOMNode** aNode,
00838                                     nsIModelElementPrivate** aModel)
00839 {
00840   if (!aElement)
00841     return PR_FALSE;
00842   nsCOMPtr<nsIModelElementPrivate> model;
00843   nsCOMPtr<nsIDOMXPathResult> result;
00844   PRBool usesModelBind;
00845   
00846   nsresult rv = EvaluateNodeBinding(aElement,
00847                                     nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR,
00848                                     NS_LITERAL_STRING("ref"),
00849                                     EmptyString(),
00850                                     nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE,
00851                                     getter_AddRefs(model),
00852                                     getter_AddRefs(result),
00853                                     &usesModelBind);
00854 
00855   if (NS_FAILED(rv) || !result)
00856     return PR_FALSE;
00857 
00858   nsCOMPtr<nsIDOMNode> singleNode;
00859   if (usesModelBind) {
00860     result->SnapshotItem(0, getter_AddRefs(singleNode));
00861   } else {
00862     result->GetSingleNodeValue(getter_AddRefs(singleNode));
00863   }
00864   if (!singleNode)
00865     return PR_FALSE;
00866 
00867   singleNode.swap(*aNode);
00868   if (aModel)
00869     model.swap(*aModel);  // transfers ref
00870   return PR_TRUE;
00871 }
00872 
00875 /* static */ PRBool
00876 nsXFormsUtils::GetSingleNodeBindingValue(nsIDOMElement* aElement,
00877                                          nsString& aValue)
00878 {
00879   nsCOMPtr<nsIDOMNode> node;
00880   if (GetSingleNodeBinding(aElement, getter_AddRefs(node), nsnull)) {
00881     nsXFormsUtils::GetNodeValue(node, aValue);
00882     return PR_TRUE;
00883   }
00884   return PR_FALSE;
00885 }
00886 
00887 nsresult
00888 DispatchXFormsEvent(nsIDOMNode* aTarget, nsXFormsEvent aEvent,
00889                     PRBool *aDefaultActionEnabled,
00890                     nsCOMArray<nsIXFormsContextInfo> *aContextInfo)
00891 {
00892   nsCOMPtr<nsIDOMDocument> domDoc;
00893   aTarget->GetOwnerDocument(getter_AddRefs(domDoc));
00894   nsCOMPtr<nsIDOMDocumentEvent> doc = do_QueryInterface(domDoc);
00895   NS_ENSURE_STATE(doc);
00896   
00897   nsCOMPtr<nsIDOMEvent> event;
00898   doc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
00899   NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
00900 
00901   const EventData *data = &sXFormsEventsEntries[aEvent];
00902   event->InitEvent(NS_ConvertUTF8toUTF16(data->name),
00903                    data->canBubble, data->canCancel);
00904 
00905   nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(aTarget);
00906   NS_ENSURE_STATE(target);
00907 
00908   nsXFormsUtils::SetEventTrusted(event, aTarget);
00909 
00910   // Create an nsXFormsDOMEvent with the context info for the event.
00911   nsCOMPtr<nsIXFormsDOMEvent> xfDOMEvent = new nsXFormsDOMEvent(event, aContextInfo);
00912   NS_ENSURE_TRUE(xfDOMEvent, NS_ERROR_OUT_OF_MEMORY);
00913 
00914   PRBool defaultActionEnabled = PR_TRUE;
00915   nsresult rv = target->DispatchEvent(xfDOMEvent, &defaultActionEnabled);
00916 
00917   if (NS_SUCCEEDED(rv) && aDefaultActionEnabled)
00918     *aDefaultActionEnabled = defaultActionEnabled;
00919 
00920   // if this is a fatal error, then display the fatal error dialog if desired
00921   switch (aEvent) {
00922   case eEvent_LinkException:
00923     {
00924       nsCOMPtr<nsIDOMElement> targetEle(do_QueryInterface(aTarget));
00925       nsXFormsUtils::HandleFatalError(targetEle,
00926                                       NS_LITERAL_STRING("XFormsLinkException"));
00927       break;
00928     }
00929   case eEvent_ComputeException:
00930     {
00931       nsCOMPtr<nsIDOMElement> targetEle(do_QueryInterface(aTarget));
00932       nsXFormsUtils::HandleFatalError(targetEle,
00933                                       NS_LITERAL_STRING("XFormsComputeException"));
00934       break;
00935     }
00936   case eEvent_BindingException:
00937     {
00938       nsCOMPtr<nsIDOMElement> targetEle(do_QueryInterface(aTarget));
00939       nsXFormsUtils::HandleFatalError(targetEle,
00940                                       NS_LITERAL_STRING("XFormsBindingException"));
00941       break;
00942     }
00943   default:
00944     break;
00945   }
00946 
00947   // Clear the context info array before the next event.
00948   if (aContextInfo)
00949     aContextInfo->Clear();
00950 
00951   return rv;
00952 }
00953 
00954 static void
00955 DeleteVoidArray(void    *aObject,
00956                 nsIAtom *aPropertyName,
00957                 void    *aPropertyValue,
00958                 void    *aData)
00959 {
00960   nsVoidArray *array = NS_STATIC_CAST(nsVoidArray *, aPropertyValue);
00961   PRInt32 count = array->Count();
00962   for (PRInt32 i = 0; i < count; i++) {
00963     EventItem *item = (EventItem *)array->ElementAt(i);
00964     delete item;
00965   }
00966 
00967   array->Clear();
00968   delete array;
00969 }
00970 
00971 nsresult
00972 DeferDispatchEvent(nsIDOMNode* aTarget, nsXFormsEvent aEvent,
00973                    nsIDOMElement *aSrcElement,
00974                    nsCOMArray<nsIXFormsContextInfo> *aContextInfo)
00975 {
00976   nsCOMPtr<nsIDOMDocument> domDoc;
00977   if (aTarget) {
00978     aTarget->GetOwnerDocument(getter_AddRefs(domDoc));
00979   } else {
00980     if (aSrcElement) {
00981       aSrcElement->GetOwnerDocument(getter_AddRefs(domDoc));
00982     }
00983   }
00984 
00985   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
00986   NS_ENSURE_STATE(doc);
00987 
00988   nsVoidArray *eventList =
00989     NS_STATIC_CAST(nsVoidArray *,
00990                    doc->GetProperty(nsXFormsAtoms::deferredEventListProperty));
00991   if (!eventList) {
00992     eventList = new nsVoidArray(16);
00993     if (!eventList)
00994       return NS_ERROR_OUT_OF_MEMORY;
00995     doc->SetProperty(nsXFormsAtoms::deferredEventListProperty, eventList,
00996                      DeleteVoidArray);
00997   }
00998 
00999   EventItem *deferredEvent = new EventItem;
01000   NS_ENSURE_TRUE(deferredEvent, NS_ERROR_OUT_OF_MEMORY);
01001   deferredEvent->event = aEvent;
01002   deferredEvent->eventTarget = aTarget;
01003   deferredEvent->srcElement = aSrcElement;
01004   deferredEvent->contextInfo = aContextInfo;
01005   eventList->AppendElement(deferredEvent);
01006 
01007   return NS_OK;
01008 }
01009 
01010 /* static */ nsresult
01011 nsXFormsUtils::DispatchEvent(nsIDOMNode* aTarget, nsXFormsEvent aEvent,
01012                              PRBool *aDefaultActionEnabled,
01013                              nsIDOMElement *aSrcElement,
01014                              nsCOMArray<nsIXFormsContextInfo> *aContextInfo)
01015 {
01016   // it is valid to have aTarget be null if this is an event that must be
01017   // targeted at a model per spec and aSrcElement is non-null.  Basically we
01018   // are trying to make sure that we can handle the case where an event needs to
01019   // be sent to the model that doesn't exist, yet (like if the model is
01020   // located at the end of the document and the parser hasn't reached that
01021   // far).  In those cases, we'll defer the event dispatch until the model
01022   // exists.
01023 
01024   switch (aEvent) {
01025     case eEvent_Previous:
01026     case eEvent_Next:
01027     case eEvent_Focus:
01028     case eEvent_Help:
01029     case eEvent_Hint:
01030     case eEvent_DOMActivate:
01031     case eEvent_ValueChanged:
01032     case eEvent_Valid:
01033     case eEvent_Invalid:
01034     case eEvent_DOMFocusIn:
01035     case eEvent_DOMFocusOut:
01036     case eEvent_Readonly:
01037     case eEvent_Readwrite:
01038     case eEvent_Required:
01039     case eEvent_Optional:
01040     case eEvent_Enabled:
01041     case eEvent_Disabled:
01042     case eEvent_InRange:
01043     case eEvent_OutOfRange:
01044       {
01045         if (!aTarget) {
01046           return NS_ERROR_FAILURE;
01047         }
01048 
01049         nsCOMPtr<nsIXFormsControl> control = do_QueryInterface(aTarget);
01050         if (control) {
01051           PRBool acceptableEventTarget = PR_FALSE;
01052           control->IsEventTarget(&acceptableEventTarget);
01053           if (!acceptableEventTarget) {
01054             return NS_OK;
01055           }
01056         }
01057         break;
01058       }
01059     case eEvent_LinkError:
01060     case eEvent_LinkException:
01061     case eEvent_ComputeException:
01062       {
01063         // these events target only models.  Verifying that the target
01064         // exists or at least that we have enough information to find the
01065         // model later when the DOM is finished loading
01066         if (!aTarget) {
01067           if (aSrcElement) {
01068             DeferDispatchEvent(aTarget, aEvent, aSrcElement, aContextInfo);
01069             return NS_OK;
01070           }
01071           return NS_ERROR_FAILURE;
01072         }
01073 
01074         nsCOMPtr<nsIModelElementPrivate> modelPriv(do_QueryInterface(aTarget));
01075         NS_ENSURE_STATE(modelPriv);
01076 
01077         PRBool safeToSendEvent = PR_FALSE;
01078         modelPriv->GetHasDOMContentFired(&safeToSendEvent);
01079         if (!safeToSendEvent) {
01080           DeferDispatchEvent(aTarget, aEvent, nsnull, aContextInfo);
01081           return NS_OK;
01082         }
01083       
01084         break;
01085       }
01086     case eEvent_BindingException:
01087       {
01088         if (!aTarget) {
01089           return NS_ERROR_FAILURE;
01090         }
01091 
01092         // we only need special handling for binding exceptions that are
01093         // targeted at bind elements and even then, only if the containing
01094         // model hasn't gotten a DOMContentLoaded, yet.  If this is the case,
01095         // we'll defer the notification until XMLEvent handlers are attached.
01096         if (!IsXFormsElement(aTarget, NS_LITERAL_STRING("bind"))) {
01097           break;
01098         }
01099 
01100         // look up bind's parent chain looking for the containing model.  If
01101         // not found, that is not goodness.  Not taking the immediate parent
01102         // in case the form uses nested binds (which is ok on some processors
01103         // for XForms 1.0 and should be ok for all processors in XForms 1.1)
01104         nsCOMPtr<nsIDOMNode> parent, temp = aTarget;
01105         nsCOMPtr<nsIModelElementPrivate> modelPriv;
01106         do {
01107           nsresult rv = temp->GetParentNode(getter_AddRefs(parent));
01108           NS_ENSURE_SUCCESS(rv, rv);
01109 
01110           modelPriv = do_QueryInterface(parent);
01111           if (modelPriv) {
01112             break;
01113           }
01114           temp = parent;
01115         } while (temp);
01116 
01117         NS_ENSURE_STATE(modelPriv);
01118 
01119         PRBool safeToSendEvent = PR_FALSE;
01120         modelPriv->GetHasDOMContentFired(&safeToSendEvent);
01121         if (!safeToSendEvent) {
01122           DeferDispatchEvent(aTarget, aEvent, nsnull, aContextInfo);
01123           return NS_OK;
01124         }
01125       
01126         break;
01127       }
01128     default:
01129       break;
01130   }
01131 
01132   return DispatchXFormsEvent(aTarget, aEvent, aDefaultActionEnabled, aContextInfo);
01133 
01134 }
01135 
01136 /* static */ nsresult
01137 nsXFormsUtils::DispatchDeferredEvents(nsIDOMDocument* aDocument)
01138 {
01139   nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDocument));
01140   NS_ENSURE_STATE(doc);
01141 
01142   nsVoidArray *eventList =
01143     NS_STATIC_CAST(nsVoidArray *,
01144                    doc->GetProperty(nsXFormsAtoms::deferredEventListProperty));
01145   if (!eventList) {
01146     return NS_OK;
01147   }
01148 
01149   PRInt32 count = eventList->Count();
01150   for (PRInt32 i = 0; i < count; i++) {
01151     EventItem *item = (EventItem *)eventList->ElementAt(i);
01152 
01153     nsCOMPtr<nsIDOMDocument> objCurrDoc;
01154     if (item->eventTarget) {
01155       item->eventTarget->GetOwnerDocument(getter_AddRefs(objCurrDoc));
01156     } else {
01157       if (item->srcElement) {
01158         item->srcElement->GetOwnerDocument(getter_AddRefs(objCurrDoc));
01159       }
01160     }
01161 
01162     if (!objCurrDoc || (objCurrDoc != aDocument))
01163     {
01164       // well the event target or our way to find the event target aren't in
01165       // the document anymore so we probably shouldn't bother to send out the
01166       // event.  They are probably on a path to destruction.
01167       delete item;
01168 
01169       continue;
01170     }
01171 
01172     if (!item->eventTarget) {
01173       // item doesn't have an event target AND it has a srcElement.  This
01174       // should only happen in the case where we wanted to dispatch an event to
01175       // a model element that hasn't been parsed, yet.  Since
01176       // DispatchDeferredEvents gets called after DOMContentLoaded is
01177       // received by the model, then this should no longer be a problem.
01178       // Go ahead and grab the model from srcElement and make that the
01179       // event target.
01180       if (item->srcElement) {
01181         nsCOMPtr<nsIModelElementPrivate> modelPriv =
01182           nsXFormsUtils::GetModel(item->srcElement);
01183         item->eventTarget = do_QueryInterface(modelPriv);
01184       }
01185       NS_ENSURE_STATE(item->eventTarget);
01186     }
01187 
01188     DispatchXFormsEvent(item->eventTarget, item->event, nsnull, item->contextInfo);
01189   }
01190 
01191   doc->DeleteProperty(nsXFormsAtoms::deferredEventListProperty);
01192   return NS_OK;
01193 }
01194 
01195 /* static */ nsresult
01196 nsXFormsUtils::SetEventTrusted(nsIDOMEvent* aEvent, nsIDOMNode* aRelatedNode)
01197 {
01198   nsCOMPtr<nsIDOMNSEvent> event(do_QueryInterface(aEvent));
01199   if (event) {
01200     PRBool isTrusted = PR_FALSE;
01201     event->GetIsTrusted(&isTrusted);
01202     if (!isTrusted && aRelatedNode) {
01203       nsCOMPtr<nsIDOMDocument> domDoc;
01204       aRelatedNode->GetOwnerDocument(getter_AddRefs(domDoc));
01205       nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
01206       if (doc) {
01207         nsIURI* uri = doc->GetDocumentURI();
01208         if (uri) {
01209           PRBool isChrome = PR_FALSE;
01210           uri->SchemeIs("chrome", &isChrome);
01211           if (isChrome) {
01212             nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aEvent));
01213             NS_ENSURE_STATE(privateEvent);
01214             privateEvent->SetTrusted(PR_TRUE);
01215           }
01216         }
01217       }
01218     }
01219   }
01220   return NS_OK;
01221 }
01222 
01223 /* static */ PRBool
01224 nsXFormsUtils::EventHandlingAllowed(nsIDOMEvent* aEvent, nsIDOMNode* aTarget)
01225 {
01226   PRBool allow = PR_FALSE;
01227   if (aEvent && aTarget) {
01228     nsCOMPtr<nsIDOMNSEvent> related(do_QueryInterface(aEvent));
01229     if (related) {
01230       PRBool isTrusted = PR_FALSE;
01231       if (NS_SUCCEEDED(related->GetIsTrusted(&isTrusted))) {
01232         if (isTrusted) {
01233           allow = PR_TRUE;
01234         } else {
01235           nsCOMPtr<nsIDOMDocument> domDoc;
01236           aTarget->GetOwnerDocument(getter_AddRefs(domDoc));
01237           nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
01238           if (doc) {
01239             nsIURI* uri = doc->GetDocumentURI();
01240             if (uri) {
01241               PRBool isChrome = PR_FALSE;
01242               uri->SchemeIs("chrome", &isChrome);
01243               allow = !isChrome;
01244             }
01245           }
01246         }
01247       }
01248     }
01249   }
01250   NS_ASSERTION(allow, "Event handling not allowed!");
01251   return allow;
01252 }
01253 
01254 /* static */ PRBool
01255 nsXFormsUtils::IsXFormsEvent(const nsAString& aEvent,
01256                              PRBool& aCancelable,
01257                              PRBool& aBubbles)
01258 {
01259   PRUint32 flag = 0;
01260   if (!sXFormsEvents.Get(aEvent, &flag))
01261     return PR_FALSE;
01262   aCancelable = (flag & CANCELABLE) ? PR_TRUE : PR_FALSE;
01263   aBubbles = (flag & BUBBLES) ? PR_TRUE : PR_FALSE;
01264   return PR_TRUE;
01265 }
01266 
01267 /* static */ void
01268 nsXFormsUtils::GetEventDefaults(const nsAString& aEvent,
01269                                 PRBool& aCancelable,
01270                                 PRBool& aBubbles)
01271 {
01272   PRUint32 flag = 0;
01273   if (!sEventDefaults.Get(aEvent, &flag))
01274     return;
01275   aCancelable = (flag & CANCELABLE) ? PR_TRUE : PR_FALSE;
01276   aBubbles = (flag & BUBBLES) ? PR_TRUE : PR_FALSE;
01277 }
01278 
01279 /* static */ nsresult
01280 nsXFormsUtils::CloneScriptingInterfaces(const nsIID *aIIDList,
01281                                         unsigned int aIIDCount,
01282                                         PRUint32 *aOutCount,
01283                                         nsIID ***aOutArray)
01284 {
01285   nsIID **iids = NS_STATIC_CAST(nsIID**,
01286                                 nsMemory::Alloc(aIIDCount * sizeof(nsIID*)));
01287   if (!iids) {
01288     return NS_ERROR_OUT_OF_MEMORY;
01289   }
01290  
01291   for (PRUint32 i = 0; i < aIIDCount; ++i) {
01292     iids[i] = NS_STATIC_CAST(nsIID*,
01293                              nsMemory::Clone(&aIIDList[i], sizeof(nsIID)));
01294  
01295     if (!iids[i]) {
01296       for (PRUint32 j = 0; j < i; ++j)
01297         nsMemory::Free(iids[j]);
01298       nsMemory::Free(iids);
01299       return NS_ERROR_OUT_OF_MEMORY;
01300     }
01301   }
01302  
01303   *aOutArray = iids;
01304   *aOutCount = aIIDCount;
01305   return NS_OK;
01306 }
01307 
01308 /* static */ nsresult
01309 nsXFormsUtils::FindParentContext(nsIDOMElement           *aElement,
01310                                  nsIModelElementPrivate **aModel,
01311                                  nsIXFormsControl       **aParentControl,
01312                                  nsIDOMNode             **aContextNode,
01313                                  PRInt32                 *aContextPosition,
01314                                  PRInt32                 *aContextSize)
01315 {
01316   NS_ENSURE_ARG(aElement);
01317   NS_ENSURE_ARG_POINTER(aModel);
01318   NS_ENSURE_ARG_POINTER(aContextNode);
01319 
01320   nsCOMPtr<nsIDOMNode> curNode;
01321   nsresult rv = aElement->GetParentNode(getter_AddRefs(curNode));
01322   NS_ENSURE_SUCCESS(rv, NS_OK);
01323 
01324   // If a model is set, get its ID
01325   nsAutoString childModelID;
01326   if (*aModel) {
01327     nsCOMPtr<nsIDOMElement> modelElement = do_QueryInterface(*aModel);
01328     NS_ENSURE_TRUE(modelElement, NS_ERROR_FAILURE);
01329     modelElement->GetAttribute(NS_LITERAL_STRING("id"), childModelID);
01330   }
01331 
01332   // Find our context:
01333   // Iterate over all parents and find first one that implements nsIXFormsContextControl,
01334   // and has the same model as us.
01335   nsCOMPtr<nsIDOMNode> temp;  
01336   nsAutoString contextModelID;
01337   while (curNode) {
01338     nsCOMPtr<nsIXFormsContextControl> contextControl = do_QueryInterface(curNode);
01339 
01340     if (contextControl) {
01341       PRInt32 cSize;
01342       PRInt32 cPosition;
01343       nsCOMPtr<nsIDOMNode> tempNode;
01344       rv = contextControl->GetContext(contextModelID,
01345                                       getter_AddRefs(tempNode),
01346                                       &cPosition,
01347                                       &cSize);
01348       NS_ENSURE_SUCCESS(rv, rv);
01349 
01350       // If we were unable to bind due to the context control not being ready,
01351       // then let the context control know that we want to be told when it is
01352       // ready.  But if this bind works and we are still waiting for
01353       // notification, then remove ourselves from the list we think we
01354       // are on.  All of this rigamarole just in case some crazy mutation
01355       // handler is out there stirring the pot.
01356       nsCOMPtr<nsIXFormsControl> control(do_QueryInterface(aElement));
01357       if (control) {
01358         if (rv == NS_OK_XFORMS_NOTREADY) {
01359           contextControl->AddRemoveAbortedControl(control, PR_TRUE);
01360           return rv;
01361         }
01362 
01363         if (rv == NS_OK) {
01364           nsCOMPtr<nsIXFormsContextControl> ctxtControl;
01365 
01366           control->GetAbortedBindListContainer(getter_AddRefs(ctxtControl));
01367           if (ctxtControl) {
01368             ctxtControl->AddRemoveAbortedControl(control, PR_FALSE);
01369           }
01370         }
01371       }
01372 
01373       // If the call failed, it means that we _have_ a parent which sets the
01374       // context but it is invalid, ie. the XPath expression could have
01375       // generated an error.
01376 
01377       if (tempNode && (childModelID.IsEmpty()
01378                        || childModelID.Equals(contextModelID))) {
01379         NS_ADDREF(*aContextNode = tempNode);
01380         if (aContextSize) 
01381           *aContextSize = cSize;
01382         if (aContextPosition)
01383           *aContextPosition = cPosition;
01384         // We QI from nsIXFormsContextControl to nsIXFormsControl here. This
01385         // will always suceed when needed, as the only element not
01386         // implementing both is the model element, and no children of model
01387         // need to register with the model (which is what aParentControl is
01388         // needed for).
01389         if (aParentControl) {
01390           CallQueryInterface(contextControl, aParentControl); // addrefs
01391         }
01392 
01393         break;
01394       }
01395     }
01396     // Next ancestor
01397     temp.swap(curNode);
01398     rv = temp->GetParentNode(getter_AddRefs(curNode));
01399     NS_ENSURE_SUCCESS(rv, NS_OK);
01400   }
01401 
01402   // Child had no model set, set it
01403   if (!*aModel) {
01404     nsCOMPtr<nsIDOMDocument> domDoc;
01405     nsresult rv = aElement->GetOwnerDocument(getter_AddRefs(domDoc));
01406     NS_ENSURE_SUCCESS(rv, rv);
01407     
01408     NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
01409 
01410     nsCOMPtr<nsIModelElementPrivate> model;
01411     if (!*aContextNode || contextModelID.IsEmpty()) {
01412       // We have either not found a context node, or we have found one where
01413       // the model ID is empty. That means we use the first model in document
01414       nsCOMPtr<nsIDOMNodeList> nodes;
01415       domDoc->GetElementsByTagNameNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS),
01416                                      NS_LITERAL_STRING("model"),
01417                                      getter_AddRefs(nodes));
01418       // No model element in document!
01419       NS_ENSURE_STATE(nodes);
01420 
01421       nsCOMPtr<nsIDOMNode> modelNode;
01422       nodes->Item(0, getter_AddRefs(modelNode));
01423       model = do_QueryInterface(modelNode);
01424     } else {
01425       // Get the model with the correct ID
01426       nsCOMPtr<nsIDOMElement> modelElement;
01427       domDoc->GetElementById(contextModelID, getter_AddRefs(modelElement));
01428       model = do_QueryInterface(modelElement);
01429     }    
01430     if (!model) {
01431       nsXFormsUtils::ReportError(NS_LITERAL_STRING("noModelError"), aElement);
01432       DispatchEvent(aElement, eEvent_BindingException);
01433       return NS_ERROR_ABORT;
01434     }
01435     NS_ADDREF(*aModel = model);
01436   }
01437   
01438   return NS_OK;
01439 }
01440 
01441 /* static */ PRBool
01442 nsXFormsUtils::CheckConnectionAllowed(nsIDOMElement *aElement,
01443                                       nsIURI        *aTestURI,
01444                                       ConnectionType aType)
01445 {
01446   if (!aElement || !aTestURI)
01447     return PR_FALSE;
01448 
01449   nsresult rv;
01450 
01451   nsCOMPtr<nsIDOMDocument> domDoc;
01452   aElement->GetOwnerDocument(getter_AddRefs(domDoc));
01453   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
01454   if (!doc)
01455     return PR_FALSE;
01456 
01457   // Start by checking UniversalBrowserRead, which overrides everything.
01458   nsIPrincipal *basePrincipal = doc->GetPrincipal();
01459   PRBool res;
01460   rv = basePrincipal->IsCapabilityEnabled("UniversalBrowserRead", nsnull, &res);
01461   if (NS_SUCCEEDED(rv) && res)
01462     return PR_TRUE;
01463 
01464   // Check same origin
01465   res = CheckSameOrigin(doc, aTestURI, aType);
01466   if (!res || aType == kXFormsActionSend)
01467     return res;
01468 
01469   // Check content policy
01470   return CheckContentPolicy(aElement, doc, aTestURI);
01471 }
01472 
01473 /* static */ PRBool
01474 nsXFormsUtils::CheckSameOrigin(nsIDocument   *aBaseDocument,
01475                                nsIURI        *aTestURI,
01476                                ConnectionType aType)
01477 {
01478   nsresult rv;
01479 
01480   NS_ASSERTION(aBaseDocument && aTestURI, "Got null parameters?!");
01481 
01482   // check the security manager and do a same original check on the principal
01483   nsIPrincipal* basePrincipal = aBaseDocument->GetPrincipal();
01484   nsCOMPtr<nsIScriptSecurityManager> secMan =
01485     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
01486   if (secMan) {
01487     // get a principal for the uri we are testing
01488     nsCOMPtr<nsIPrincipal> testPrincipal;
01489     rv = secMan->GetCodebasePrincipal(aTestURI, getter_AddRefs(testPrincipal));
01490 
01491     if (NS_SUCCEEDED(rv)) {
01492       rv = secMan->CheckSameOriginPrincipal(basePrincipal, testPrincipal);
01493       if (NS_SUCCEEDED(rv))
01494         return PR_TRUE;
01495     }
01496   }
01497 
01498   // else, check with the permission manager to see if this host is
01499   // permitted to access sites from other domains.
01500 
01501   nsCOMPtr<nsIPermissionManager> permMgr =
01502       do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
01503   NS_ENSURE_TRUE(permMgr, PR_FALSE);
01504 
01505   nsCOMPtr<nsIURI> principalURI;
01506   rv = basePrincipal->GetURI(getter_AddRefs(principalURI));
01507 
01508   if (NS_SUCCEEDED(rv)) {
01509     PRUint32 perm;
01510     rv = permMgr->TestPermission(principalURI, "xforms-xd", &perm);
01511 
01512     if (NS_SUCCEEDED(rv) && perm != nsIPermissionManager::UNKNOWN_ACTION) {
01513       // Safe cast, as we only have few ConnectionTypes.
01514       PRInt32 permSigned = perm;
01515       if (permSigned == kXFormsActionLoadSend || permSigned == aType)
01516         return PR_TRUE;
01517     }
01518   }
01519 
01520   return PR_FALSE;
01521 }
01522 
01523 /* static */ PRBool
01524 nsXFormsUtils::CheckContentPolicy(nsIDOMElement *aElement,
01525                                   nsIDocument   *aDoc,
01526                                   nsIURI        *aURI)
01527 {
01528   NS_ASSERTION(aElement && aDoc && aURI, "Got null parameters?!");
01529 
01530   nsIURI *docURI = aDoc->GetDocumentURI();
01531   NS_ENSURE_TRUE(docURI, PR_FALSE);
01532 
01533   PRInt16 decision = nsIContentPolicy::ACCEPT;
01534   nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,
01535                                           aURI,
01536                                           docURI,
01537                                           aElement,        // context
01538                                           EmptyCString(),  // mime guess
01539                                           nsnull,          // extra
01540                                           &decision);
01541   NS_ENSURE_SUCCESS(rv, PR_FALSE);
01542 
01543   return NS_CP_ACCEPTED(decision);
01544 }
01545 
01546 /*static*/ PRBool
01547 nsXFormsUtils::IsXFormsElement(nsIDOMNode* aNode, const nsAString& aName)
01548 {
01549   if (aNode) {
01550     PRUint16 nodeType;
01551     aNode->GetNodeType(&nodeType);
01552     if (nodeType == nsIDOMNode::ELEMENT_NODE) {
01553       nsAutoString name;
01554       aNode->GetLocalName(name);
01555       if (name.Equals(aName)) {
01556         nsAutoString ns;
01557         aNode->GetNamespaceURI(ns);
01558         if (ns.EqualsLiteral(NS_NAMESPACE_XFORMS))
01559           return PR_TRUE;
01560       }
01561     }
01562   }
01563   return PR_FALSE;
01564 }
01565 
01566 /* static */ PRBool
01567 nsXFormsUtils::IsLabelElement(nsIDOMNode *aElement)
01568 {
01569   nsAutoString value;
01570   aElement->GetLocalName(value);
01571   if (value.EqualsLiteral("label")) {
01572     aElement->GetNamespaceURI(value);
01573     return value.EqualsLiteral(NS_NAMESPACE_XFORMS);
01574   }
01575 
01576   return PR_FALSE;
01577 }
01578 
01579 /* static */ PRBool
01580 nsXFormsUtils::FocusControl(nsIDOMElement *aElement)
01581 {
01582   PRBool ret = PR_FALSE;
01583   nsCOMPtr<nsIDOMNSHTMLElement> element(do_QueryInterface(aElement));
01584   if (element && NS_SUCCEEDED(element->Focus()))
01585     ret = PR_TRUE;
01586   return ret;
01587 }
01588 
01589 int
01590 sortFunc(nsIDOMNode *aNode1, nsIDOMNode *aNode2, void *aArg) 
01591 {
01592   return (void*) aNode1 > (void*) aNode2;
01593 }
01594 
01595 /* static */ void
01596 nsXFormsUtils::MakeUniqueAndSort(nsCOMArray<nsIDOMNode> *aArray)
01597 {
01598   if (!aArray)
01599     return;
01600 
01601   aArray->Sort(sortFunc, nsnull);  
01602 
01603   PRInt32 pos = 0;
01604   while (pos + 1 < aArray->Count()) {
01605     if (aArray->ObjectAt(pos) == aArray->ObjectAt(pos + 1)) {
01606       aArray->RemoveObjectAt(pos + 1);
01607     } else {
01608       ++pos;
01609     }
01610   }
01611 }
01612 
01613 /* static */ nsresult
01614 nsXFormsUtils::GetInstanceNodeForData(nsIDOMNode             *aInstanceDataNode,
01615                                       nsIDOMNode             **aInstanceNode)
01616 {
01617   NS_ENSURE_ARG(aInstanceDataNode);
01618   NS_ENSURE_ARG_POINTER(aInstanceNode);
01619   *aInstanceNode = nsnull;
01620 
01621   nsCOMPtr<nsIDOMDocument> instanceDOMDoc;
01622   aInstanceDataNode->GetOwnerDocument(getter_AddRefs(instanceDOMDoc));
01623   // owner doc is null when the data node is the document (e.g., ref="/")
01624   if (!instanceDOMDoc) {
01625     instanceDOMDoc = do_QueryInterface(aInstanceDataNode);
01626   }
01627 
01628   nsCOMPtr<nsIDocument> instanceDoc(do_QueryInterface(instanceDOMDoc));
01629   NS_ENSURE_TRUE(instanceDoc, NS_ERROR_UNEXPECTED);
01630 
01631   nsISupports* owner =
01632     NS_STATIC_CAST(
01633       nsISupports*,
01634       instanceDoc->GetProperty(nsXFormsAtoms::instanceDocumentOwner));
01635 
01636   nsCOMPtr<nsIDOMNode> instanceNode(do_QueryInterface(owner));
01637   if (instanceNode) {
01638     NS_ADDREF(*aInstanceNode = instanceNode);
01639     return NS_OK;
01640   }
01641 
01642   // Two possibilities.  No instance nodes in model (which should never happen)
01643   // or instance node not found.
01644   return NS_ERROR_ABORT;
01645 }
01646 
01647 /* static */ nsresult
01648 nsXFormsUtils::ParseTypeFromNode(nsIDOMNode             *aInstanceData,
01649                                  nsAString              &aType,
01650                                  nsAString              &aNSUri)
01651 {
01652   nsresult rv;
01653 
01654   // Find the model for the instance data node
01655   nsCOMPtr<nsIDOMNode> instanceNode;
01656   rv = nsXFormsUtils::GetInstanceNodeForData(aInstanceData,
01657                                              getter_AddRefs(instanceNode));
01658   NS_ENSURE_SUCCESS(rv, rv);
01659 
01660   nsCOMPtr<nsIDOMNode> modelNode;
01661   rv = instanceNode->GetParentNode(getter_AddRefs(modelNode));
01662   NS_ENSURE_SUCCESS(rv, rv);
01663 
01664   nsCOMPtr<nsIModelElementPrivate> model(do_QueryInterface(modelNode));
01665   NS_ENSURE_STATE(model);
01666 
01667   return model->GetTypeFromNode(aInstanceData, aType, aNSUri);
01668 }
01669 
01670 /* static */ void
01671 nsXFormsUtils::ReportError(const nsAString& aMessage, const PRUnichar **aParams,
01672                            PRUint32 aParamLength, nsIDOMNode *aElement,
01673                            nsIDOMNode *aContext, PRUint32 aErrorFlag,
01674                            PRBool aLiteralMessage)
01675 {
01676 
01677   nsCOMPtr<nsIScriptError> errorObject =
01678     do_CreateInstance("@mozilla.org/scripterror;1");
01679 
01680   nsCOMPtr<nsIConsoleService> consoleService =
01681     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
01682 
01683   if (!(consoleService && errorObject))
01684     return;
01685 
01686   nsAutoString msg;
01687 
01688   if (!aLiteralMessage) {
01689     nsCOMPtr<nsIStringBundleService> bundleService =
01690       do_GetService(NS_STRINGBUNDLE_CONTRACTID);
01691   
01692     if (!bundleService)
01693       return;
01694     
01695     // get the string from the bundle (xforms.properties)
01696     nsCOMPtr<nsIStringBundle> bundle;
01697     bundleService->CreateBundle("chrome://xforms/locale/xforms.properties",
01698                                 getter_AddRefs(bundle));
01699     nsXPIDLString message;
01700     if (aParams) {
01701       bundle->FormatStringFromName(PromiseFlatString(aMessage).get(), aParams,
01702                                    aParamLength, getter_Copies(message));
01703       msg.Append(message);
01704     } else {
01705       bundle->GetStringFromName(PromiseFlatString(aMessage).get(),
01706                                 getter_Copies(message));
01707       msg.Append(message);
01708     }
01709   
01710     if (msg.IsEmpty()) {
01711   #ifdef DEBUG
01712       printf("nsXFormsUtils::ReportError() Failed to get message string for message id '%s'!\n",
01713              NS_ConvertUTF16toUTF8(aMessage).get());
01714   #endif
01715       return;
01716     }
01717   } else {
01718     msg.Append(aMessage);
01719   }
01720 
01721 
01722   nsAutoString srcFile, srcLine;
01723 
01724   // if a context was defined, serialize it and append to the message.
01725   if (aContext) {
01726     nsCOMPtr<nsIDOMElement> element(do_QueryInterface(aContext));
01727     if (element) {
01728       srcLine.AppendLiteral("<");
01729     }
01730 
01731     // For other than element nodes nodeName should be enough.
01732     nsAutoString tmp;
01733     aContext->GetNodeName(tmp);
01734     srcLine.Append(tmp);
01735     
01736     if (element) {
01737       nsCOMPtr<nsIDOMNamedNodeMap> attrs;
01738       element->GetAttributes(getter_AddRefs(attrs));
01739       if (attrs) {
01740         PRUint32 len = 0;
01741         attrs->GetLength(&len);
01742         for (PRUint32 i = 0; i < len; ++i) {
01743           nsCOMPtr<nsIDOMNode> attr;
01744           attrs->Item(i, getter_AddRefs(attr));
01745           if (attr) {
01746             srcLine.AppendLiteral(" ");
01747             attr->GetNodeName(tmp);
01748             srcLine.Append(tmp);
01749             srcLine.AppendLiteral("=\"");
01750             attr->GetNodeValue(tmp);
01751             srcLine.Append(tmp);
01752             srcLine.AppendLiteral("\"");
01753           }
01754         }
01755       }
01756       srcLine.AppendLiteral("/>");
01757     }
01758   }
01759 
01760   // if aElement is defined, we use it to figure out the location of the file
01761   // that caused the error.
01762   if (aElement) {
01763     nsCOMPtr<nsIDOMDocument> domDoc;
01764     aElement->GetOwnerDocument(getter_AddRefs(domDoc));
01765 
01766     if (domDoc) {
01767       nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(domDoc));
01768 
01769       if (nsDoc) {
01770         nsCOMPtr<nsIDOMLocation> domLoc;
01771         nsDoc->GetLocation(getter_AddRefs(domLoc));
01772 
01773         if (domLoc) {
01774           nsAutoString location;
01775           domLoc->GetHref(srcFile);
01776         }
01777       }
01778     }
01779   }
01780 
01781 
01782   // Log the message to Error Console
01783 #ifdef DEBUG
01784   printf("ERR: %s\n", NS_ConvertUTF16toUTF8(msg).get());
01785 #endif
01786   nsresult rv = errorObject->Init(msg.get(), srcFile.get(), srcLine.get(),
01787                                   0, 0, aErrorFlag, "XForms");
01788   if (NS_SUCCEEDED(rv)) {
01789     consoleService->LogMessage(errorObject);
01790   }
01791 }
01792 
01793 /* static */ PRBool
01794 nsXFormsUtils::IsDocumentReadyForBind(nsIDOMElement *aElement)
01795 {
01796   if (!aElement)
01797     return PR_FALSE;
01798 
01799   nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
01800   NS_ASSERTION(content, "mElement not implementing nsIContent?!");
01801 
01802   nsIDocument* doc = content->GetCurrentDoc();
01803   if (!doc)
01804     return PR_FALSE;
01805 
01806   void* test = doc->GetProperty(nsXFormsAtoms::readyForBindProperty);
01807   return test ? PR_TRUE : PR_FALSE;
01808 }
01809 
01818 already_AddRefed<nsIDOMNode>
01819 FindRepeatContext(nsIDOMElement *aElement, PRBool aFindContainer)
01820 {
01821   nsIDOMNode *result = nsnull;
01822   
01823   // XXX Possibly use mRepeatState functionality from nsXFormsDelegateStub to
01824   // save running up the tree?
01825   nsCOMPtr<nsIDOMNode> context, temp;
01826   aElement->GetParentNode(getter_AddRefs(context));
01827   nsresult rv = NS_OK;
01828   while (context) {
01829     if (nsXFormsUtils::IsXFormsElement(context,
01830                                        aFindContainer ?
01831                                          NS_LITERAL_STRING("contextcontainer") :
01832                                          NS_LITERAL_STRING("repeat"))) {
01833       break;
01834     }
01835     temp.swap(context);
01836     rv = temp->GetParentNode(getter_AddRefs(context));
01837   }
01838   if (context && NS_SUCCEEDED(rv)) {
01839       NS_ADDREF(result = context);
01840   }
01841   return result;
01842 }
01843 
01844 /* static */
01845 nsresult
01846 nsXFormsUtils::GetElementById(const nsAString  &aId,
01847                               const PRBool      aOnlyXForms,
01848                               nsIDOMElement    *aCaller,
01849                               nsIDOMElement   **aElement)
01850 {
01851   NS_ENSURE_TRUE(!aId.IsEmpty(), NS_ERROR_INVALID_ARG);
01852   NS_ENSURE_ARG_POINTER(aElement);
01853   *aElement = nsnull;
01854 
01855   nsCOMPtr<nsIDOMElement> element;
01856   GetElementByContextId(aCaller, aId, getter_AddRefs(element));
01857   if (!element)
01858     return NS_OK;
01859 
01860   // Check whether the element is inside a repeat. If it is, find the cloned
01861   // element for the currently selected row.
01862   nsCOMPtr<nsIDOMNode> repeat = FindRepeatContext(element, PR_FALSE);
01863   if (!repeat) {
01864     // Element not inside a repeat, just return the element (eventually
01865     // checking for XForms namespace)
01866     if (aOnlyXForms) {
01867       nsAutoString ns;
01868       element->GetNamespaceURI(ns);
01869       if (!ns.EqualsLiteral(NS_NAMESPACE_XFORMS)) {
01870         return NS_OK;
01871       }
01872     }
01873     NS_ADDREF(*aElement = element);
01874     return NS_OK;
01875   }
01876 
01877   // Check whether the caller is inside a repeat
01878   nsCOMPtr<nsIDOMNode> repeatRow;
01879   if (aCaller) {
01880     repeatRow = FindRepeatContext(aCaller, PR_TRUE);
01881   }
01882 
01883   if (!repeatRow) {
01884     // aCaller was either not set or not inside a repeat, used currently
01885     // focused row of the element's repeat
01886     nsCOMPtr<nsIXFormsRepeatElement> repeatInt(do_QueryInterface(repeat));
01887     NS_ENSURE_STATE(repeatInt);
01888     repeatInt->GetCurrentRepeatRow(getter_AddRefs(repeatRow));
01889     NS_ASSERTION(repeatRow, "huh? No currently selected repeat row?");
01890   }
01891   
01892   nsCOMPtr<nsIDOMElement> rowElement(do_QueryInterface(repeatRow));
01893   NS_ENSURE_STATE(rowElement);
01894 
01895   nsCOMPtr<nsIDOMDocument> repeatDoc;
01896   rowElement->GetOwnerDocument(getter_AddRefs(repeatDoc));
01897     
01898   nsCOMPtr<nsIDOMNodeList> descendants;
01899   nsresult rv;
01900   rv = rowElement->GetElementsByTagNameNS(aOnlyXForms ?
01901                                             NS_LITERAL_STRING(NS_NAMESPACE_XFORMS) :
01902                                             NS_LITERAL_STRING("*"),
01903                                           NS_LITERAL_STRING("*"),
01904                                           getter_AddRefs(descendants));
01905   NS_ENSURE_SUCCESS(rv, rv);
01906   NS_ENSURE_STATE(descendants);
01907   PRUint32 elements;
01908   descendants->GetLength(&elements);
01909   if (!elements) {
01910     return NS_OK;
01911   }
01912 
01913   PRUint32 i;
01914   PRUint16 type;
01915   nsAutoString idVal;
01916   nsCOMPtr<nsIDOMNode> childNode;
01917   for (i = 0; i < elements; ++i) {
01918     descendants->Item(i, getter_AddRefs(childNode));
01919     childNode->GetNodeType(&type);
01920     if (type == nsIDOMNode::ELEMENT_NODE) {
01921       nsCOMPtr<nsIContent> content(do_QueryInterface(childNode));
01922       NS_ASSERTION(content, "An ELEMENT_NODE not implementing nsIContent?!");
01923       rv = content->GetAttr(kNameSpaceID_None, content->GetIDAttributeName(),
01924                             idVal);
01925       if (rv == NS_CONTENT_ATTR_HAS_VALUE && idVal.Equals(aId)) {
01926         element = do_QueryInterface(childNode);
01927         break;
01928       }
01929     }
01930   }
01931 
01932   if (i == elements) {
01933     return NS_OK;
01934   }
01935     
01936   NS_ENSURE_STATE(element);
01937   NS_ADDREF(*aElement = element);
01938 
01939   return NS_OK;
01940 }
01941 
01942 /* static */
01943 nsresult
01944 nsXFormsUtils::GetElementByContextId(nsIDOMElement   *aRefNode,
01945                                      const nsAString &aId,
01946                                      nsIDOMElement   **aElement)
01947 {
01948   NS_ENSURE_ARG(aRefNode);
01949   NS_ENSURE_ARG_POINTER(aElement);
01950 
01951   *aElement = nsnull;
01952 
01953   nsCOMPtr<nsIDOMDocument> document;
01954   aRefNode->GetOwnerDocument(getter_AddRefs(document));
01955   if (!document)
01956     return NS_OK;
01957 
01958   // Even if given element is anonymous node then search element by ID attribute
01959   // of document because anonymous node can inherit attribute from bound node
01960   // that is refID of document.
01961 
01962   nsresult rv = document->GetElementById(aId, aElement);
01963   NS_ENSURE_SUCCESS(rv, rv);
01964 
01965   if (*aElement)
01966     return NS_OK;
01967 
01968   nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(document));
01969   if (!xblDoc)
01970     return NS_OK;
01971 
01972   nsCOMPtr<nsIContent> content(do_QueryInterface(aRefNode));
01973   if (!content)
01974     return NS_OK;
01975 
01976   // Search for the element with the given value in its 'anonid' attribute
01977   // throughout the complete bindings chain. We must ensure that the binding
01978   // parent of currently traversed element is not element itself to avoid an
01979   // infinite loop.
01980   nsIContent *boundContent;
01981   for (boundContent = content->GetBindingParent(); boundContent != nsnull &&
01982          boundContent != boundContent->GetBindingParent() && !*aElement;
01983          boundContent = boundContent->GetBindingParent()) {
01984     nsCOMPtr<nsIDOMElement> boundElm(do_QueryInterface(boundContent));
01985     xblDoc->GetAnonymousElementByAttribute(boundElm, NS_LITERAL_STRING("anonid"),
01986                                            aId, aElement);
01987   }
01988 
01989   return NS_OK;
01990 }
01991 
01992 /* static */
01993 PRBool
01994 nsXFormsUtils::HandleFatalError(nsIDOMElement    *aElement,
01995                                 const nsAString  &aName)
01996 {
01997   if (!aElement) {
01998     return PR_FALSE;
01999   }
02000   nsCOMPtr<nsIDOMDocument> doc;
02001   aElement->GetOwnerDocument(getter_AddRefs(doc));
02002 
02003   nsCOMPtr<nsIDocument> iDoc(do_QueryInterface(doc));
02004   if (!iDoc) {
02005     return PR_FALSE;
02006   }
02007 
02008   // check for fatalError property, enforcing that only one fatal error will
02009   // be shown to the user
02010   if (iDoc->GetProperty(nsXFormsAtoms::fatalError)) {
02011     return PR_FALSE;
02012   }
02013   iDoc->SetProperty(nsXFormsAtoms::fatalError, iDoc);
02014 
02015   // Check for preference, disabling this popup
02016   PRBool disablePopup = PR_FALSE;
02017   nsresult rv;
02018   nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
02019   if (NS_SUCCEEDED(rv) && pref) {
02020     PRBool val;
02021     if (NS_SUCCEEDED(pref->GetBoolPref("xforms.disablePopup", &val)))
02022       disablePopup = val;
02023   }
02024   if (disablePopup)
02025     return PR_FALSE;
02026 
02027   // Get nsIDOMWindowInternal
02028   nsCOMPtr<nsIDOMWindowInternal> internal;
02029   rv = nsXFormsUtils::GetWindowFromDocument(doc, getter_AddRefs(internal));
02030   if (NS_FAILED(rv) || !internal) {
02031     return PR_FALSE;
02032   }
02033 
02034 
02035   // Show popup
02036   nsCOMPtr<nsIDOMWindow> messageWindow;
02037   rv = internal->OpenDialog(NS_LITERAL_STRING("chrome://xforms/content/bindingex.xul"),
02038                             aName,
02039                             NS_LITERAL_STRING("modal,dialog,chrome,dependent"),
02040                             nsnull,
02041                             getter_AddRefs(messageWindow));
02042   return NS_SUCCEEDED(rv);
02043 }
02044 
02045 /* static */
02046 PRBool
02047 nsXFormsUtils::AreEntitiesEqual(nsIDOMNamedNodeMap *aEntities1,
02048                                 nsIDOMNamedNodeMap *aEntities2)
02049 {
02050   if (!aEntities1 && !aEntities2) {
02051     return PR_TRUE;
02052   }
02053 
02054   if (!aEntities1 || !aEntities2) {
02055     return PR_FALSE;
02056   }
02057 
02058   PRUint32 entLength1, entLength2;
02059   nsresult rv1 = aEntities1->GetLength(&entLength1);
02060   nsresult rv2 = aEntities2->GetLength(&entLength2);
02061   if (NS_FAILED(rv1) || NS_FAILED(rv2) || entLength1 != entLength2) {
02062     return PR_FALSE;
02063   }
02064 
02065   nsAutoString buffer1, buffer2;
02066   for (PRUint32 i = 0; i < entLength1; ++i) {
02067     nsCOMPtr<nsIDOMNode> entNode1, entNode2;
02068 
02069     rv1 = aEntities1->Item(i, getter_AddRefs(entNode1));
02070     rv2 = aEntities2->Item(i, getter_AddRefs(entNode2));
02071     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !entNode1 || !entNode2) {
02072       return PR_FALSE;
02073     }
02074 
02075     nsCOMPtr<nsIDOMEntity> ent1, ent2;
02076     ent1 = do_QueryInterface(entNode1);
02077     ent2 = do_QueryInterface(entNode2);
02078     if (!ent1 || !ent2) {
02079       return PR_FALSE;
02080     }
02081 
02082     rv1 = ent1->GetPublicId(buffer1);
02083     rv2 = ent2->GetPublicId(buffer2);
02084     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02085       return PR_FALSE;
02086     }
02087 
02088     rv1 = ent1->GetSystemId(buffer1);
02089     rv2 = ent2->GetSystemId(buffer2);
02090     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02091       return PR_FALSE;
02092     }
02093 
02094     rv1 = ent1->GetNotationName(buffer1);
02095     rv2 = ent2->GetNotationName(buffer2);
02096     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02097       return PR_FALSE;
02098     }
02099 
02100     // XXX: These will need to be uncommented when Mozilla supports these from
02101     // DOM3
02102 #if 0
02103     rv1 = ent1->GetInputEncoding(buffer1);
02104     rv2 = ent2->GetInputEncoding(buffer2);
02105     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02106       return PR_FALSE;
02107     }
02108 
02109     rv1 = ent1->GetXmlEncoding(buffer1);
02110     rv2 = ent2->GetXmlEncoding(buffer2);
02111     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02112       return PR_FALSE;
02113     }
02114     rv1 = ent1->GetXmlVersion(buffer1);
02115     rv2 = ent2->GetXmlVersion(buffer2);
02116     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02117       return PR_FALSE;
02118     }
02119 #endif
02120 
02121   }
02122   return PR_TRUE;
02123 }
02124 
02125 /* static */ PRBool
02126 nsXFormsUtils::AreNotationsEqual(nsIDOMNamedNodeMap *aNotations1,
02127                                  nsIDOMNamedNodeMap *aNotations2)
02128 {
02129   if (!aNotations1 && !aNotations2) {
02130     return PR_TRUE;
02131   }
02132 
02133   if (!aNotations1 || !aNotations2) {
02134     return PR_FALSE;
02135   }
02136 
02137   PRUint32 notLength1, notLength2;
02138   nsresult rv1 = aNotations1->GetLength(&notLength1);
02139   nsresult rv2 = aNotations2->GetLength(&notLength2);
02140   if (NS_FAILED(rv1) || NS_FAILED(rv2) || notLength1 != notLength2) {
02141     return PR_FALSE;
02142   }
02143 
02144   nsAutoString buffer1, buffer2;
02145   for (PRUint32 j = 0; j < notLength1; ++j) {
02146     nsCOMPtr<nsIDOMNode> notNode1, notNode2;
02147 
02148     rv1 = aNotations1->Item(j, getter_AddRefs(notNode1));
02149     rv2 = aNotations2->Item(j, getter_AddRefs(notNode2));
02150     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !notNode1 || !notNode2) {
02151       return PR_FALSE;
02152     }
02153 
02154     nsCOMPtr<nsIDOMNotation> notation1, notation2;
02155     notation1 = do_QueryInterface(notNode1);
02156     notation2 = do_QueryInterface(notNode2);
02157     if (!notation1 || !notation2) {
02158       return PR_FALSE;
02159     }
02160 
02161     rv1 = notation1->GetPublicId(buffer1);
02162     rv2 = notation2->GetPublicId(buffer2);
02163     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02164       return PR_FALSE;
02165     }
02166 
02167     rv1 = notation1->GetSystemId(buffer1);
02168     rv2 = notation2->GetSystemId(buffer2);
02169     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02170       return PR_FALSE;
02171     }
02172   }
02173 
02174   return PR_TRUE;
02175 }
02176 
02177 /* static */ PRBool
02178 nsXFormsUtils::AreNodesEqual(nsIDOMNode *aFirstNode, nsIDOMNode *aSecondNode,
02179                              PRBool aAlreadyNormalized)
02180 {
02181   if (!aFirstNode || !aSecondNode) {
02182     return PR_FALSE;
02183   }
02184 
02185   nsresult rv1, rv2;
02186   PRUint16 firstType, secondType;
02187   rv1 = aFirstNode->GetNodeType(&firstType);
02188   rv2 = aSecondNode->GetNodeType(&secondType);
02189   if (NS_FAILED(rv1) || NS_FAILED(rv2) || firstType != secondType) {
02190     return PR_FALSE;
02191   }
02192 
02193   nsAutoString buffer1, buffer2;
02194   if (firstType == nsIDOMNode::DOCUMENT_TYPE_NODE) {
02195     nsCOMPtr<nsIDOMDocumentType> doc1 = do_QueryInterface(aFirstNode);
02196     nsCOMPtr<nsIDOMDocumentType> doc2 = do_QueryInterface(aSecondNode);
02197     if (!doc1 || !doc2) {
02198       return PR_FALSE;
02199     }
02200 
02201     rv1 = doc1->GetName(buffer1);
02202     rv2 = doc2->GetName(buffer2);
02203     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02204       return PR_FALSE;
02205     }
02206 
02207     rv1 = doc1->GetPublicId(buffer1);
02208     rv2 = doc2->GetPublicId(buffer2);
02209     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02210       return PR_FALSE;
02211     }
02212 
02213     rv1 = doc1->GetSystemId(buffer1);
02214     rv2 = doc2->GetSystemId(buffer2);
02215     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02216       return PR_FALSE;
02217     }
02218 
02219     rv1 = doc1->GetInternalSubset(buffer1);
02220     rv2 = doc2->GetInternalSubset(buffer2);
02221     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02222       return PR_FALSE;
02223     }
02224 
02225     nsCOMPtr<nsIDOMNamedNodeMap> map1, map2;
02226     rv1 = doc1->GetEntities(getter_AddRefs(map1));
02227     rv2 = doc2->GetEntities(getter_AddRefs(map2));
02228 
02229     // XXX need to handle the case where neither has entities?
02230     if (NS_FAILED(rv1) || NS_FAILED(rv2)) {
02231       return PR_FALSE;
02232     }
02233 
02234     PRBool equal = nsXFormsUtils::AreEntitiesEqual(map1, map2);
02235     if (!equal) {
02236       return PR_FALSE;
02237     }
02238 
02239     rv1 = doc1->GetNotations(getter_AddRefs(map1));
02240     rv2 = doc2->GetNotations(getter_AddRefs(map2));
02241     if (NS_FAILED(rv1) || NS_FAILED(rv2)) {
02242       return PR_FALSE;
02243     }
02244 
02245     equal = nsXFormsUtils::AreNotationsEqual(map1, map2);
02246     if (!equal) {
02247       return PR_FALSE;
02248     }
02249 
02250   }
02251 
02252   rv1 = aFirstNode->GetNodeName(buffer1);
02253   rv2 = aSecondNode->GetNodeName(buffer2);
02254   if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02255     return PR_FALSE;
02256   }
02257 
02258   rv1 = aFirstNode->GetLocalName(buffer1);
02259   rv2 = aSecondNode->GetLocalName(buffer2);
02260   if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02261     return PR_FALSE;
02262   }
02263 
02264   rv1 = aFirstNode->GetNamespaceURI(buffer1);
02265   rv2 = aSecondNode->GetNamespaceURI(buffer2);
02266   if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02267     return PR_FALSE;
02268   }
02269 
02270   rv1 = aFirstNode->GetPrefix(buffer1);
02271   rv2 = aSecondNode->GetPrefix(buffer2);
02272   if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02273     return PR_FALSE;
02274   }
02275 
02276   rv1 = aFirstNode->GetNodeValue(buffer1);
02277   rv2 = aSecondNode->GetNodeValue(buffer2);
02278   if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02279     return PR_FALSE;
02280   }
02281 
02282   PRBool hasAttr1, hasAttr2;
02283   rv1 = aFirstNode->HasAttributes(&hasAttr1);
02284   rv2 = aSecondNode->HasAttributes(&hasAttr2);
02285   if (NS_FAILED(rv1) || NS_FAILED(rv2) || hasAttr1 != hasAttr2) {
02286     return PR_FALSE;
02287   }
02288 
02289   if (hasAttr1) {
02290     nsCOMPtr<nsIDOMNamedNodeMap> attrs1, attrs2;
02291     PRUint32 attrLength1, attrLength2;
02292 
02293     rv1 = aFirstNode->GetAttributes(getter_AddRefs(attrs1));
02294     rv2 = aSecondNode->GetAttributes(getter_AddRefs(attrs2));
02295     if (NS_FAILED(rv1) || NS_FAILED(rv2)) {
02296       return PR_FALSE;
02297     }
02298 
02299     rv1 = attrs1->GetLength(&attrLength1);
02300     rv2 = attrs2->GetLength(&attrLength2);
02301     if (NS_FAILED(rv1) || NS_FAILED(rv2) || attrLength1 != attrLength2) {
02302       return PR_FALSE;
02303     }
02304 
02305     // the order of the attributes on the two nodes doesn't matter.  But
02306     // every attribute on node1 must exist on node2 (and no more)
02307     for (PRUint32 i = 0; i < attrLength1; ++i) {
02308       nsCOMPtr<nsIDOMNode> attr1, attr2;
02309       rv1 = attrs1->Item(i, getter_AddRefs(attr1));
02310       if (!attr1) {
02311         return PR_FALSE;
02312       }
02313 
02314       attr1->GetLocalName(buffer1);
02315       attr1->GetNamespaceURI(buffer2);
02316       attrs2->GetNamedItemNS(buffer2, buffer1, getter_AddRefs(attr2));
02317       if (!attr2) {
02318         return PR_FALSE;
02319       }
02320 
02321       rv1 = attr1->GetNodeValue(buffer1);
02322       rv2 = attr2->GetNodeValue(buffer2);
02323       if (NS_FAILED(rv1) || NS_FAILED(rv2) || !buffer1.Equals(buffer2)) {
02324         return PR_FALSE;
02325       }
02326     }
02327   }
02328 
02329   // now looking at the child nodes.  They have to be 'equal' and at the same
02330   // index inside each of the parent nodes.
02331   PRBool hasChildren1, hasChildren2;
02332   rv1 = aFirstNode->HasChildNodes(&hasChildren1);
02333   rv2 = aSecondNode->HasChildNodes(&hasChildren2);
02334   if (NS_FAILED(rv1) || NS_FAILED(rv2) || hasChildren1 != hasChildren2) {
02335     return PR_FALSE;
02336   }
02337 
02338   if (hasChildren1) {
02339     nsCOMPtr<nsIDOMNodeList> children1, children2;
02340     PRUint32 childrenLength1, childrenLength2;
02341 
02342     rv1 = aFirstNode->GetChildNodes(getter_AddRefs(children1));
02343     rv2 = aSecondNode->GetChildNodes(getter_AddRefs(children2));
02344     if (NS_FAILED(rv1) || NS_FAILED(rv2) || !children1 || !children2) {
02345       return PR_FALSE;
02346     }
02347 
02348     rv1 = children1->GetLength(&childrenLength1);
02349     rv2 = children2->GetLength(&childrenLength2);
02350     if (NS_FAILED(rv1) || NS_FAILED(rv2) || childrenLength1 != childrenLength2) {
02351       return PR_FALSE;
02352     }
02353 
02354     nsCOMPtr<nsIDOMNode> clone1, clone2;
02355     if (!aAlreadyNormalized) {
02356       // well we avoided this as long as we can.  If we haven't already
02357       // normalized all children, now is the time to do it.  We'll have to clone
02358       // nodes since the normalization process actually changes the DOM.
02359      
02360       rv1 = aFirstNode->CloneNode(PR_TRUE, getter_AddRefs(clone1));
02361       if (NS_FAILED(rv1) || !clone1) {
02362         return PR_FALSE;
02363       }
02364       rv2 = aSecondNode->CloneNode(PR_TRUE, getter_AddRefs(clone2));
02365       if (NS_FAILED(rv2) || !clone2) {
02366         return PR_FALSE;
02367       }
02368 
02369       rv1 = clone1->Normalize();
02370       rv2 = clone2->Normalize();
02371       if (NS_FAILED(rv1) || NS_FAILED(rv2)) {
02372         return PR_FALSE;
02373       }
02374 
02375       // since this already worked once on the original nodes, won't bother
02376       // checking the results for the clones
02377       clone1->GetChildNodes(getter_AddRefs(children1));
02378       clone2->GetChildNodes(getter_AddRefs(children2));
02379 
02380       // get length again since normalizing may have eliminated some text nodes
02381       rv1 = children1->GetLength(&childrenLength1);
02382       rv2 = children2->GetLength(&childrenLength2);
02383       if (NS_FAILED(rv1) || NS_FAILED(rv2) || childrenLength1 != childrenLength2) {
02384         return PR_FALSE;
02385       }
02386     }
02387 
02388     for (PRUint32 i = 0; i < childrenLength1; ++i) {
02389       nsCOMPtr<nsIDOMNode> child1, child2;
02390 
02391       rv1 = children1->Item(i, getter_AddRefs(child1));
02392       rv2 = children2->Item(i, getter_AddRefs(child2));
02393       if (NS_FAILED(rv1) || NS_FAILED(rv2)) {
02394         return PR_FALSE;
02395       }
02396 
02397       PRBool areEqual = nsXFormsUtils::AreNodesEqual(child1, child2, PR_TRUE);
02398       if (!areEqual) {
02399         return PR_FALSE;
02400       }
02401     }
02402   }
02403 
02404   return PR_TRUE;
02405 
02406 }
02407 
02408 
02409 /* static */
02410 nsresult
02411 nsXFormsUtils::GetWindowFromDocument(nsIDOMDocument         *aDoc,
02412                                      nsIDOMWindowInternal  **aWindow)
02413 {
02414   NS_ENSURE_ARG(aDoc);
02415   NS_ENSURE_ARG_POINTER(aWindow);
02416   *aWindow = nsnull;
02417 
02418   // Get nsIDOMWindowInternal
02419   nsCOMPtr<nsIDOMDocumentView> dview(do_QueryInterface(aDoc));
02420   NS_ENSURE_STATE(dview);
02421 
02422   nsCOMPtr<nsIDOMAbstractView> aview;
02423   dview->GetDefaultView(getter_AddRefs(aview));
02424 
02425   nsCOMPtr<nsIDOMWindowInternal> internal(do_QueryInterface(aview));
02426   NS_ENSURE_STATE(internal);
02427 
02428   NS_ADDREF(*aWindow = internal);
02429   return NS_OK;
02430 }
02431 
02432 /* static */ PRBool
02433 nsXFormsUtils::SetSingleNodeBindingValue(nsIDOMElement *aElement,
02434                                          const nsAString &aValue,
02435                                          PRBool *aChanged)
02436 {
02437   *aChanged = PR_FALSE;
02438   nsCOMPtr<nsIDOMNode> node;
02439   nsCOMPtr<nsIModelElementPrivate> model;
02440   if (GetSingleNodeBinding(aElement, getter_AddRefs(node),
02441                            getter_AddRefs(model)))
02442   {
02443     nsresult rv = model->SetNodeValue(node, aValue, PR_FALSE, aChanged);
02444     if (NS_SUCCEEDED(rv))
02445       return PR_TRUE;
02446   }
02447   return PR_FALSE;
02448 }
02449 
02450 /* static */ PRBool
02451 nsXFormsUtils::NodeHasItemset(nsIDOMNode *aNode)
02452 {
02453   PRBool hasItemset = PR_FALSE;
02454 
02455   nsCOMPtr<nsIDOMNodeList> children;
02456   aNode->GetChildNodes(getter_AddRefs(children));
02457 
02458   PRUint32 childCount = 0;
02459   if (children) {
02460     children->GetLength(&childCount);
02461   }
02462 
02463   for (PRUint32 i = 0; i < childCount; ++i) {
02464     nsCOMPtr<nsIDOMNode> child;
02465     children->Item(i, getter_AddRefs(child));
02466     if (nsXFormsUtils::IsXFormsElement(child, NS_LITERAL_STRING("itemset"))) {
02467       hasItemset = PR_TRUE;
02468       break;
02469     } else if (nsXFormsUtils::IsXFormsElement(child,
02470                                               NS_LITERAL_STRING("choices"))) {
02471       // The choices element may have an itemset.
02472       hasItemset = nsXFormsUtils::NodeHasItemset(child);
02473       if (hasItemset) {
02474         // No need to look at any other children.
02475         break;
02476       }
02477     }
02478   }
02479   return hasItemset;
02480 }
02481 
02482 /* static */ PRBool
02483 nsXFormsUtils::AskStopWaiting(nsIDOMElement *aElement)
02484 {
02485   nsCOMPtr<nsIDOMDocument> domDoc;
02486   aElement->GetOwnerDocument(getter_AddRefs(domDoc));
02487   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
02488   NS_ENSURE_TRUE(doc, PR_TRUE);
02489 
02490   nsCOMPtr<nsPIDOMWindow> win = doc->GetWindow();
02491   NS_ENSURE_TRUE(win, PR_TRUE);
02492 
02493   nsCOMPtr<nsIPrompt> prompt;
02494   win->GetPrompter(getter_AddRefs(prompt));
02495   NS_ENSURE_TRUE(prompt, PR_TRUE);
02496 
02497   // Get localizable strings
02498   nsCOMPtr<nsIStringBundleService>
02499     stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID));
02500   NS_ENSURE_TRUE(stringService, PR_TRUE);
02501 
02502   nsCOMPtr<nsIStringBundle> bundle;
02503   stringService->CreateBundle("chrome://global/locale/dom/dom.properties",
02504                               getter_AddRefs(bundle));
02505   NS_ENSURE_TRUE(bundle, PR_TRUE);
02506   
02507   nsXPIDLString title, msg, stopButton, waitButton;
02508 
02509   nsresult rv;
02510   rv = bundle->GetStringFromName(NS_LITERAL_STRING("KillScriptTitle").get(),
02511                                  getter_Copies(title));
02512   rv |= bundle->GetStringFromName(NS_LITERAL_STRING("StopScriptButton").get(),
02513                                   getter_Copies(stopButton));
02514   rv |= bundle->GetStringFromName(NS_LITERAL_STRING("WaitForScriptButton").get(),
02515                                   getter_Copies(waitButton));
02516   rv |= bundle->GetStringFromName(NS_LITERAL_STRING("KillScriptMessage").get(),
02517                                   getter_Copies(msg));
02518 
02519 
02520   // GetStringFromName can return NS_OK and still give NULL string
02521   if (NS_FAILED(rv) || !title || !msg || !stopButton || !waitButton) {
02522     NS_ERROR("Failed to get localized strings.");
02523     return PR_TRUE;
02524   }
02525 
02526   PRInt32 buttonPressed = 1; // In case user exits dialog by clicking X
02527   PRUint32 buttonFlags = (nsIPrompt::BUTTON_TITLE_IS_STRING *
02528                           (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
02529 
02530   // Open the dialog.
02531   rv = prompt->ConfirmEx(title, msg, buttonFlags, stopButton, waitButton,
02532                          nsnull, nsnull, nsnull, &buttonPressed);
02533 
02534   if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) {
02535     // Request stopping the unresponsive code
02536     return PR_TRUE;
02537   } else {
02538     return PR_FALSE;
02539   }
02540 }
02541 
02542 static inline PRUnichar
02543 ToHexChar(PRInt16 aValue)
02544 {
02545   if (aValue < 10)
02546     return (PRUnichar) aValue + '0';
02547   else
02548     return (PRUnichar) aValue - 10 + 'A';
02549 }
02550 
02551 void
02552 nsXFormsUtils::BinaryToHex(const char *aBuffer, PRUint32 aCount,
02553                            PRUnichar **aHexString)
02554 {
02555   for (PRUint32 index = 0; index < aCount; index++) {
02556     (*aHexString)[index * 2] = ToHexChar((aBuffer[index] >> 4) & 0xf);
02557     (*aHexString)[index * 2 + 1] = ToHexChar(aBuffer[index] & 0xf);
02558   }
02559 }
02560 
02561 /* static */ nsresult
02562 nsXFormsUtils::GetTimeZone(const nsAString &aTime,
02563                            nsAString &aResult)
02564 {
02565   aResult.Truncate();
02566 
02567   if (!aTime.IsEmpty()) {
02568     PRInt32 timeZoneSeparator = aTime.FindChar(PRUnichar('-'));
02569     if (timeZoneSeparator == kNotFound) {
02570       timeZoneSeparator = aTime.FindChar(PRUnichar('+'));
02571       if (timeZoneSeparator == kNotFound) {
02572         // no time zone information available
02573         return NS_OK;
02574       }
02575     }
02576     aResult.Append(Substring(aTime, timeZoneSeparator,
02577                              aTime.Length() - timeZoneSeparator));
02578   }
02579 
02580   return NS_OK;
02581 }