From e0eda4916c7ae3ce083f06430446c15510685220 Mon Sep 17 00:00:00 2001 From: "peterv%propagandism.org" Date: Thu, 13 Jul 2006 14:21:53 +0000 Subject: [PATCH] Fix for bug 278981 (Extension mechanism for XPath extension functions). r=sicking, sr=jst. git-svn-id: svn://10.0.0.236/trunk@202020 18797224-902f-48f8-a5cc-f745e15eee43 --- .../base/public/nsIXFormsUtilityService.h | 90 +-- .../base/public/nsIXPathEvaluatorInternal.h | 11 +- mozilla/content/xslt/public/Makefile.in | 3 + mozilla/content/xslt/public/txDouble.h | 128 ++++ .../public/txIFunctionEvaluationContext.idl | 51 ++ mozilla/content/xslt/public/txINodeSet.idl | 57 ++ mozilla/content/xslt/src/base/txCore.h | 1 + mozilla/content/xslt/src/base/txDouble.cpp | 74 +- mozilla/content/xslt/src/xpath/Makefile.in | 13 +- .../xslt/src/xpath/nsIXFormsXPathEvaluator.h | 102 --- .../xslt/src/xpath/nsXFormsXPathEvaluator.cpp | 272 -------- .../xslt/src/xpath/nsXPathEvaluator.cpp | 158 +++-- .../content/xslt/src/xpath/nsXPathEvaluator.h | 15 + .../xslt/src/xpath/txNodeSetAdaptor.cpp | 129 ++++ ...rmsXPathEvaluator.h => txNodeSetAdaptor.h} | 75 +- .../xslt/src/xpath/txRelationalExpr.cpp | 23 +- .../xslt/src/xpath/txXFormsFunctionCall.cpp | 647 ------------------ .../src/xpath/txXPCOMExtensionFunction.cpp | 587 ++++++++++++++++ mozilla/extensions/xforms/Makefile.in | 2 + .../xforms/nsIXFormsXPathFunctions.idl | 60 ++ .../extensions/xforms/nsXFormsMDGEngine.cpp | 10 +- .../xforms/nsXFormsModelElement.cpp | 68 +- .../extensions/xforms/nsXFormsModelElement.h | 14 +- mozilla/extensions/xforms/nsXFormsModule.cpp | 19 +- .../xforms/nsXFormsUtilityService.cpp | 383 ----------- .../xforms/nsXFormsUtilityService.h | 20 - mozilla/extensions/xforms/nsXFormsUtils.cpp | 428 +++++++++++- mozilla/extensions/xforms/nsXFormsUtils.h | 89 ++- .../xforms/nsXFormsXPathAnalyzer.cpp | 25 +- .../extensions/xforms/nsXFormsXPathAnalyzer.h | 12 +- .../xforms/nsXFormsXPathFunctions.cpp | 426 ++++++++++++ .../xforms/nsXFormsXPathFunctions.h} | 48 +- mozilla/layout/build/nsLayoutModule.cpp | 22 +- 33 files changed, 2229 insertions(+), 1833 deletions(-) create mode 100644 mozilla/content/xslt/public/txDouble.h create mode 100644 mozilla/content/xslt/public/txIFunctionEvaluationContext.idl create mode 100644 mozilla/content/xslt/public/txINodeSet.idl delete mode 100644 mozilla/content/xslt/src/xpath/nsIXFormsXPathEvaluator.h delete mode 100644 mozilla/content/xslt/src/xpath/nsXFormsXPathEvaluator.cpp create mode 100644 mozilla/content/xslt/src/xpath/txNodeSetAdaptor.cpp rename mozilla/content/xslt/src/xpath/{nsXFormsXPathEvaluator.h => txNodeSetAdaptor.h} (53%) delete mode 100644 mozilla/content/xslt/src/xpath/txXFormsFunctionCall.cpp create mode 100644 mozilla/content/xslt/src/xpath/txXPCOMExtensionFunction.cpp create mode 100644 mozilla/extensions/xforms/nsIXFormsXPathFunctions.idl create mode 100644 mozilla/extensions/xforms/nsXFormsXPathFunctions.cpp rename mozilla/{content/xslt/src/xpath/txXFormsFunctions.h => extensions/xforms/nsXFormsXPathFunctions.h} (58%) diff --git a/mozilla/content/base/public/nsIXFormsUtilityService.h b/mozilla/content/base/public/nsIXFormsUtilityService.h index 2bf5b07fd01..47e4a4d2b53 100755 --- a/mozilla/content/base/public/nsIXFormsUtilityService.h +++ b/mozilla/content/base/public/nsIXFormsUtilityService.h @@ -47,14 +47,11 @@ #define NS_NO_VTABLE #endif -class nsIDOMNode; /* forward declaration */ - /* nsIXFormsUtilityService */ -#define NS_IXFORMSUTILITYSERVICE_IID_STR "4a744a59-8771-4065-959d-b8de3dad81da" - +#define NS_IXFORMSUTILITYSERVICE_IID_STR "f7276415-bb3e-4170-b746-aa57f68d7006" #define NS_IXFORMSUTILITYSERVICE_IID \ - {0x4a744a59, 0x8771, 0x4065, \ - { 0x95, 0x9d, 0xb8, 0xde, 0x3d, 0xad, 0x81, 0xda }} +{ 0xf7276415, 0xbb3e, 0x4170, \ + { 0xb7, 0x46, 0xaa, 0x57, 0xf6, 0x8d, 0x70, 0x06 } } /** * Private interface implemented by the nsXFormsUtilityService in XForms @@ -64,87 +61,6 @@ class NS_NO_VTABLE nsIXFormsUtilityService : public nsISupports { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXFORMSUTILITYSERVICE_IID) - - /** - * Function to get the corresponding model element from a xforms node or - * a xforms instance data node. - */ - /* nsIDOMNode getModelFromNode (in nsIDOMNode node); */ - NS_IMETHOD GetModelFromNode(nsIDOMNode *node, nsIDOMNode **aModel) = 0; - - /** - * Function to see if the given node is associated with the given model. - * Right now this function is only called by XPath in the case of the - * instance() function. - * The provided node can be an instance node from an instance - * document and thus be associated to the model in that way (model elements - * contain instance elements). Otherwise the node will be an XForms element - * that was used as the context node of the XPath expression (i.e the - * XForms control has an attribute that contains an XPath expression). - * Form controls are associated with model elements either explicitly through - * single-node binding or implicitly (if model cannot by calculated, it - * will use the first model element encountered in the document). The model - * can also be inherited from a containing element like xforms:group or - * xforms:repeat. - */ - /* PRBool isNodeAssocWithModel (in nsIDOMNode aNode, in nsIDOMNode aModel); */ - NS_IMETHOD IsNodeAssocWithModel(nsIDOMNode *aNode, nsIDOMNode *aModel, - PRBool *aModelAssocWithNode) = 0; - - /** - * Function to get the instance document root for the instance element with - * the given id. The instance element must be associated with the given - * model. - */ - /* nsIDOMNode getInstanceDocumentRoot(in DOMString aID, - in nsIDOMNode aModelNode); */ - NS_IMETHOD GetInstanceDocumentRoot(const nsAString& aID, - nsIDOMNode *aModelNode, - nsIDOMNode **aInstanceRoot) = 0; - - /** - * Function to ensure that aValue is of the schema type aType. Will basically - * be a forwarder to the nsISchemaValidator function of the same name. - */ - /* boolean validateString (in AString aValue, in AString aType, - in AString aNamespace); */ - NS_IMETHOD ValidateString(const nsAString& aValue, const nsAString& aType, - const nsAString & aNamespace, PRBool *aResult) = 0; - - /** - * Function to retrieve the index from the given repeat element. - */ - /* long getRepeatIndex (in nsIDOMNode aRepeat); */ - NS_IMETHOD GetRepeatIndex(nsIDOMNode *aRepeat, PRInt32 *aIndex) = 0; - - /** - * Function to retrieve the number of months represented by the - * xsd:duration provided in aValue - */ - /* long getMonths (in DOMString aValue); */ - NS_IMETHOD GetMonths(const nsAString& aValue, PRInt32 *aMonths) = 0; - - /** - * Function to retrieve the number of seconds represented by the - * xsd:duration provided in aValue - */ - /* double getSeconds (in DOMString aValue); */ - NS_IMETHOD GetSeconds(const nsAString& aValue, double *aSeconds) = 0; - - /** - * Function to retrieve the number of seconds represented by the - * xsd:dateTime provided in aValue - */ - /* double getSecondsFromDateTime (in DOMString aValue); */ - NS_IMETHOD GetSecondsFromDateTime(const nsAString& aValue, - double *aSeconds) = 0; - - /** - * Function to retrieve the number of days represented by the - * xsd:dateTime provided in aValue - */ - /* long getDaysFromDateTime (in DOMString aValue); */ - NS_IMETHOD GetDaysFromDateTime(const nsAString& aValue, PRInt32 *aDays) = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIXFormsUtilityService, diff --git a/mozilla/content/base/public/nsIXPathEvaluatorInternal.h b/mozilla/content/base/public/nsIXPathEvaluatorInternal.h index b4e5e88af1a..42f8d7d1948 100644 --- a/mozilla/content/base/public/nsIXPathEvaluatorInternal.h +++ b/mozilla/content/base/public/nsIXPathEvaluatorInternal.h @@ -39,9 +39,11 @@ #ifndef nsIXPathEvaluatorInternal_h__ #define nsIXPathEvaluatorInternal_h__ -#include "nsISupports.h" +#include "nsCOMArray.h" class nsIDOMDocument; +class nsIDOMXPathExpression; +class nsIDOMXPathNSResolver; #define NS_IXPATHEVALUATORINTERNAL_IID \ {0xb4b72daa, 0x65d6, 0x440f, \ @@ -57,6 +59,13 @@ public: * Sets the document this evaluator corresponds to */ NS_IMETHOD SetDocument(nsIDOMDocument* aDocument) = 0; + + NS_IMETHOD CreateExpression(const nsAString &aExpression, + nsIDOMXPathNSResolver *aResolver, + nsStringArray *aNamespaceURIs, + nsCStringArray *aContractIDs, + nsCOMArray *aState, + nsIDOMXPathExpression **aResult) = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIXPathEvaluatorInternal, diff --git a/mozilla/content/xslt/public/Makefile.in b/mozilla/content/xslt/public/Makefile.in index c69a2c0a6d2..99a2a701f76 100644 --- a/mozilla/content/xslt/public/Makefile.in +++ b/mozilla/content/xslt/public/Makefile.in @@ -47,6 +47,7 @@ XPIDL_MODULE = content_xslt EXPORTS = \ nsIDocumentTransformer.h \ + txDouble.h \ $(NULL) XPIDLSRCS = \ @@ -54,6 +55,8 @@ XPIDLSRCS = \ nsIXSLTProcessor.idl \ nsIXSLTProcessorObsolete.idl \ nsIXSLTProcessorPrivate.idl \ + txIFunctionEvaluationContext.idl \ + txINodeSet.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/mozilla/content/xslt/public/txDouble.h b/mozilla/content/xslt/public/txDouble.h new file mode 100644 index 00000000000..14770ac0e13 --- /dev/null +++ b/mozilla/content/xslt/public/txDouble.h @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Peter Van der Beken. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __txdouble_h__ +#define __txdouble_h__ + +//A trick to handle IEEE floating point exceptions on FreeBSD - E.D. +#ifdef __FreeBSD__ +#include +#ifdef __alpha__ +fp_except_t allmask = FP_X_INV|FP_X_OFL|FP_X_UFL|FP_X_DZ|FP_X_IMP; +#else +fp_except_t allmask = FP_X_INV|FP_X_OFL|FP_X_UFL|FP_X_DZ|FP_X_IMP|FP_X_DNML; +#endif +fp_except_t oldmask = fpsetmask(~allmask); +#endif + +/** + * Macros to workaround math-bugs bugs in various platforms + */ + +/** + * Stefan Hanske reports: + * ARM is a little endian architecture but 64 bit double words are stored + * differently: the 32 bit words are in little endian byte order, the two words + * are stored in big endian`s way. + */ + +#if defined(__arm) || defined(__arm32__) || defined(__arm26__) || defined(__arm__) +#define CPU_IS_ARM +#endif + +#if (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || __GNUC__ > 2 +/** + * This version of the macros is safe for the alias optimizations + * that gcc does, but uses gcc-specific extensions. + */ + +typedef union txdpun { + PRFloat64 d; + struct { +#if defined(IS_LITTLE_ENDIAN) && !defined(CPU_IS_ARM) + PRUint32 lo, hi; +#else + PRUint32 hi, lo; +#endif + } s; +} txdpun; + +#define TX_DOUBLE_HI32(x) (__extension__ ({ txdpun u; u.d = (x); u.s.hi; })) +#define TX_DOUBLE_LO32(x) (__extension__ ({ txdpun u; u.d = (x); u.s.lo; })) + +#else // __GNUC__ + +/* We don't know of any non-gcc compilers that perform alias optimization, + * so this code should work. + */ + +#if defined(IS_LITTLE_ENDIAN) && !defined(CPU_IS_ARM) +#define TX_DOUBLE_HI32(x) (((PRUint32 *)&(x))[1]) +#define TX_DOUBLE_LO32(x) (((PRUint32 *)&(x))[0]) +#else +#define TX_DOUBLE_HI32(x) (((PRUint32 *)&(x))[0]) +#define TX_DOUBLE_LO32(x) (((PRUint32 *)&(x))[1]) +#endif + +#endif // __GNUC__ + +#define TX_DOUBLE_HI32_SIGNBIT 0x80000000 +#define TX_DOUBLE_HI32_EXPMASK 0x7ff00000 +#define TX_DOUBLE_HI32_MANTMASK 0x000fffff + +#define TX_DOUBLE_IS_NaN(x) \ +((TX_DOUBLE_HI32(x) & TX_DOUBLE_HI32_EXPMASK) == TX_DOUBLE_HI32_EXPMASK && \ + (TX_DOUBLE_LO32(x) || (TX_DOUBLE_HI32(x) & TX_DOUBLE_HI32_MANTMASK))) + +#ifdef IS_BIG_ENDIAN +#define TX_DOUBLE_NaN {TX_DOUBLE_HI32_EXPMASK | TX_DOUBLE_HI32_MANTMASK, \ + 0xffffffff} +#else +#define TX_DOUBLE_NaN {0xffffffff, \ + TX_DOUBLE_HI32_EXPMASK | TX_DOUBLE_HI32_MANTMASK} +#endif + +#if defined(XP_WIN) +#define TX_DOUBLE_COMPARE(LVAL, OP, RVAL) \ + (!TX_DOUBLE_IS_NaN(LVAL) && !TX_DOUBLE_IS_NaN(RVAL) && (LVAL) OP (RVAL)) +#else +#define TX_DOUBLE_COMPARE(LVAL, OP, RVAL) ((LVAL) OP (RVAL)) +#endif + +#endif /* __txdouble_h__ */ diff --git a/mozilla/content/xslt/public/txIFunctionEvaluationContext.idl b/mozilla/content/xslt/public/txIFunctionEvaluationContext.idl new file mode 100644 index 00000000000..2cbbca84e02 --- /dev/null +++ b/mozilla/content/xslt/public/txIFunctionEvaluationContext.idl @@ -0,0 +1,51 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Peter Van der Beken. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "domstubs.idl" + +interface txINodeSet; + +[scriptable, uuid(0ecbb00c-6a78-11d9-9791-000a95dc234c)] +interface txIFunctionEvaluationContext : nsISupports +{ + readonly attribute PRUint32 position; + readonly attribute PRUint32 size; + readonly attribute nsIDOMNode contextNode; + readonly attribute nsISupports state; +}; diff --git a/mozilla/content/xslt/public/txINodeSet.idl b/mozilla/content/xslt/public/txINodeSet.idl new file mode 100644 index 00000000000..a17d843a27f --- /dev/null +++ b/mozilla/content/xslt/public/txINodeSet.idl @@ -0,0 +1,57 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Peter Van der Beken. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "domstubs.idl" + +%{ C++ +class txAExprResult; +%} + +[ptr] native txAExprResultPtr(txAExprResult); + +[scriptable, uuid(15d424c0-6b47-11d9-9791-000a95dc234c)] +interface txINodeSet : nsISupports +{ + nsIDOMNode item(in unsigned long index); + double itemAsNumber(in unsigned long index); + DOMString itemAsString(in unsigned long index); + readonly attribute unsigned long length; + void add(in nsIDOMNode node); + [noscript, notxpcom] txAExprResultPtr getTxNodeSet(); +}; diff --git a/mozilla/content/xslt/src/base/txCore.h b/mozilla/content/xslt/src/base/txCore.h index c6e76e2c562..763ff97545b 100644 --- a/mozilla/content/xslt/src/base/txCore.h +++ b/mozilla/content/xslt/src/base/txCore.h @@ -42,6 +42,7 @@ #include "nscore.h" #include "nsDebug.h" #include "prtypes.h" +#include "txDouble.h" class nsAString; diff --git a/mozilla/content/xslt/src/base/txDouble.cpp b/mozilla/content/xslt/src/base/txDouble.cpp index d709e9a38d3..c7532d499d4 100644 --- a/mozilla/content/xslt/src/base/txDouble.cpp +++ b/mozilla/content/xslt/src/base/txDouble.cpp @@ -49,81 +49,12 @@ * Utility class for doubles */ -//A trick to handle IEEE floating point exceptions on FreeBSD - E.D. -#ifdef __FreeBSD__ -#include -#ifdef __alpha__ -fp_except_t allmask = FP_X_INV|FP_X_OFL|FP_X_UFL|FP_X_DZ|FP_X_IMP; -#else -fp_except_t allmask = FP_X_INV|FP_X_OFL|FP_X_UFL|FP_X_DZ|FP_X_IMP|FP_X_DNML; -#endif -fp_except_t oldmask = fpsetmask(~allmask); -#endif - -/** - * Macros to workaround math-bugs bugs in various platforms - */ - -/** - * Stefan Hanske reports: - * ARM is a little endian architecture but 64 bit double words are stored - * differently: the 32 bit words are in little endian byte order, the two words - * are stored in big endian`s way. - */ - -#if defined(__arm) || defined(__arm32__) || defined(_arm26__) || defined(__arm__) -#define CPU_IS_ARM -#endif - -#if (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || __GNUC__ > 2 -/** - * This version of the macros is safe for the alias optimizations - * that gcc does, but uses gcc-specific extensions. - */ - -typedef union txdpun { - PRFloat64 d; - struct { -#if defined(IS_LITTLE_ENDIAN) && !defined(CPU_IS_ARM) - PRUint32 lo, hi; -#else - PRUint32 hi, lo; -#endif - } s; -} txdpun; - -#define TX_DOUBLE_HI32(x) (__extension__ ({ txdpun u; u.d = (x); u.s.hi; })) -#define TX_DOUBLE_LO32(x) (__extension__ ({ txdpun u; u.d = (x); u.s.lo; })) - -#else // __GNUC__ - -/* We don't know of any non-gcc compilers that perform alias optimization, - * so this code should work. - */ - -#if defined(IS_LITTLE_ENDIAN) && !defined(CPU_IS_ARM) -#define TX_DOUBLE_HI32(x) (((PRUint32 *)&(x))[1]) -#define TX_DOUBLE_LO32(x) (((PRUint32 *)&(x))[0]) -#else -#define TX_DOUBLE_HI32(x) (((PRUint32 *)&(x))[0]) -#define TX_DOUBLE_LO32(x) (((PRUint32 *)&(x))[1]) -#endif - -#endif // __GNUC__ - -#define TX_DOUBLE_HI32_SIGNBIT 0x80000000 -#define TX_DOUBLE_HI32_EXPMASK 0x7ff00000 -#define TX_DOUBLE_HI32_MANTMASK 0x000fffff - //-- Initialize Double related constants +const PRUint32 nanMask[2] = TX_DOUBLE_NaN; #ifdef IS_BIG_ENDIAN -const PRUint32 nanMask[2] = {TX_DOUBLE_HI32_EXPMASK | TX_DOUBLE_HI32_MANTMASK, - 0xffffffff}; const PRUint32 infMask[2] = {TX_DOUBLE_HI32_EXPMASK, 0}; const PRUint32 negInfMask[2] = {TX_DOUBLE_HI32_EXPMASK | TX_DOUBLE_HI32_SIGNBIT, 0}; #else -const PRUint32 nanMask[2] = {0xffffffff, - TX_DOUBLE_HI32_EXPMASK | TX_DOUBLE_HI32_MANTMASK}; const PRUint32 infMask[2] = {0, TX_DOUBLE_HI32_EXPMASK}; const PRUint32 negInfMask[2] = {0, TX_DOUBLE_HI32_EXPMASK | TX_DOUBLE_HI32_SIGNBIT}; #endif @@ -147,8 +78,7 @@ MBool Double::isInfinite(double aDbl) */ MBool Double::isNaN(double aDbl) { - return ((TX_DOUBLE_HI32(aDbl) & TX_DOUBLE_HI32_EXPMASK) == TX_DOUBLE_HI32_EXPMASK && - (TX_DOUBLE_LO32(aDbl) || (TX_DOUBLE_HI32(aDbl) & TX_DOUBLE_HI32_MANTMASK))); + return TX_DOUBLE_IS_NaN(aDbl); } /* diff --git a/mozilla/content/xslt/src/xpath/Makefile.in b/mozilla/content/xslt/src/xpath/Makefile.in index 4de1cb3c7ac..f2d533df6e0 100644 --- a/mozilla/content/xslt/src/xpath/Makefile.in +++ b/mozilla/content/xslt/src/xpath/Makefile.in @@ -101,20 +101,13 @@ CPPSRCS += nsXPathEvaluator.cpp \ nsXPathNSResolver.cpp \ nsXPathResult.cpp \ nsXPath1Scheme.cpp \ - txMozillaXPathTreeWalker.cpp + txMozillaXPathTreeWalker.cpp \ + txNodeSetAdaptor.cpp \ + txXPCOMExtensionFunction.cpp else CPPSRCS += txStandaloneXPathTreeWalker.cpp endif -ifndef DISABLE_XFORMS_HOOKS # Dummy var, nobody sets it! -ifndef MOZ_XSLT_STANDALONE -EXPORTS = nsIXFormsXPathEvaluator.h - -CPPSRCS += nsXFormsXPathEvaluator.cpp \ - txXFormsFunctionCall.cpp -endif -endif - # we don't want the shared lib, but we want to force the creation of a # static lib. FORCE_STATIC_LIB = 1 diff --git a/mozilla/content/xslt/src/xpath/nsIXFormsXPathEvaluator.h b/mozilla/content/xslt/src/xpath/nsIXFormsXPathEvaluator.h deleted file mode 100644 index f641a596d32..00000000000 --- a/mozilla/content/xslt/src/xpath/nsIXFormsXPathEvaluator.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla XForms support. - * - * The Initial Developer of the Original Code is - * IBM Corporation. - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Aaron Reed - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef nsIXFormsXPathEvaluator_h -#define nsIXFormsXPathEvaluator_h - - -#include "nsISupports.h" - -/* For IDL files that don't want to include root IDL files. */ -#ifndef NS_NO_VTABLE -#define NS_NO_VTABLE -#endif -class nsIDOMNode; /* forward declaration */ -class nsIDOMNSXPathExpression; /* forward declaration */ - -/* starting interface: nsIXFormsXPathEvaluator */ -#define NS_XFORMS_XPATH_EVALUATOR_CONTRACTID "@mozilla.org/dom/xforms-xpath-evaluator;1" -/* 4cdd884f-f949-4d82-bb78-b8edd9f1420c */ -#define TRANSFORMIIX_XFORMS_XPATH_EVALUATOR_CID \ -{ 0x4cdd884f, 0xf949, 0x4d82, \ - {0xbb, 0x78, 0xb8, 0xed, 0xd9, 0xf1, 0x42, 0x0c} } - -/* 61e5a446-73f7-432e-a2d6-d94d4a51aed8 */ -#define TRANSFORMIIX_XFORMS_XPATH_EVALUATOR_IID \ -{ 0x61e5a446, 0x73f7, 0x432e, \ - {0xa2, 0xd6, 0xd9, 0x4d, 0x4a, 0x51, 0xae, 0xd8} } - -/* Use this macro when declaring classes that implement this interface. */ -#define NS_DECL_NSIXFORMXPATHEVALUATOR \ - NS_IMETHOD CreateExpression(const nsAString & aExpression, nsIDOMNode *aResolverNode, nsIDOMNSXPathExpression **aResult); \ - NS_IMETHOD Evaluate(const nsAString & aExpression, nsIDOMNode *aContextNode, PRUint32 aContextPosition, PRUint32 aContextSize, nsIDOMNode *aResolverNode, PRUint16 aType, nsISupports *aInResult, nsISupports **aResult); - -/** - * Private interface implemented by the nsXFormsXPathEvaluator in Transformiix - * and will move to the XForms extension when XPath is made extensible. We - * are using this interface instead of nsIDOMXPathEvaluator since we can - * don't really need all of that overhead. For example, this interface uses - * a resolver node from the xforms document rather than forcing XForms to - * create a namespace resolver node prior to creating the expression or - * running an evaluation. - */ -class NS_NO_VTABLE nsIXFormsXPathEvaluator : public nsISupports { - public: - - NS_DECLARE_STATIC_IID_ACCESSOR(TRANSFORMIIX_XFORMS_XPATH_EVALUATOR_IID) - - /** - * Function to create a nsIDOMNSXPathExpression from the provided expression - * string. aResolverNode is the xforms node that the expression is - * associated with. - */ - NS_IMETHOD CreateExpression(const nsAString & aExpression, nsIDOMNode *aResolverNode, nsIDOMNSXPathExpression **aResult) = 0; - - /** - * Function to evaluate the given expression. aResolverNode is the xforms - * node that the expression is associated with. The other parameters are as - * required by DOM's XPathEvaluator. - */ - NS_IMETHOD Evaluate(const nsAString & aExpression, nsIDOMNode *aContextNode, PRUint32 aContextPosition, PRUint32 aContextSize, nsIDOMNode *aResolverNode, PRUint16 aType, nsISupports *aInResult, nsISupports **aResult) = 0; - -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsIXFormsXPathEvaluator, - TRANSFORMIIX_XFORMS_XPATH_EVALUATOR_IID) - -#endif /* nsIXFormsXPathEvaluator_h */ diff --git a/mozilla/content/xslt/src/xpath/nsXFormsXPathEvaluator.cpp b/mozilla/content/xslt/src/xpath/nsXFormsXPathEvaluator.cpp deleted file mode 100644 index f6396bfd6d3..00000000000 --- a/mozilla/content/xslt/src/xpath/nsXFormsXPathEvaluator.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla XForms support. - * - * The Initial Developer of the Original Code is - * IBM Corporation. - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Aaron Reed - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "nsXFormsXPathEvaluator.h" -#include "nsCOMPtr.h" -#include "nsIAtom.h" -#include "nsIDOMClassInfo.h" -#include "nsXPathExpression.h" -#include "nsXPathNSResolver.h" -#include "nsXPathResult.h" -#include "nsContentCID.h" -#include "txExpr.h" -#include "txExprParser.h" -#include "nsDOMError.h" -#include "txURIUtils.h" -#include "nsIDocument.h" -#include "nsIDOMDocument.h" -#include "nsDOMString.h" -#include "nsINameSpaceManager.h" -#include "txError.h" -#include "txAtoms.h" -#include "txXFormsFunctions.h" -#include "nsIDOM3Node.h" -#include "nsContentUtils.h" - -NS_IMPL_ADDREF(nsXFormsXPathEvaluator) -NS_IMPL_RELEASE(nsXFormsXPathEvaluator) -NS_INTERFACE_MAP_BEGIN(nsXFormsXPathEvaluator) - NS_INTERFACE_MAP_ENTRY(nsIXFormsXPathEvaluator) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXFormsXPathEvaluator) -NS_INTERFACE_MAP_END - -nsXFormsXPathEvaluator::nsXFormsXPathEvaluator() -{ -} - -nsXFormsXPathEvaluator::~nsXFormsXPathEvaluator() -{ -} - -NS_IMETHODIMP -nsXFormsXPathEvaluator::CreateExpression(const nsAString & aExpression, - nsIDOMNode *aResolverNode, - nsIDOMNSXPathExpression **aResult) -{ - nsresult rv = NS_OK; - if (!mRecycler) { - nsRefPtr recycler = new txResultRecycler; - NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY); - - rv = recycler->init(); - NS_ENSURE_SUCCESS(rv, rv); - - mRecycler = recycler; - } - - XFormsParseContextImpl pContext(aResolverNode); - - nsAutoPtr expression; - rv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext, - getter_Transfers(expression)); - if (NS_FAILED(rv)) { - if (rv == NS_ERROR_DOM_NAMESPACE_ERR) { - return NS_ERROR_DOM_NAMESPACE_ERR; - } - - return NS_ERROR_DOM_INVALID_EXPRESSION_ERR; - } - - *aResult = new nsXPathExpression(expression, mRecycler); - if (!*aResult) { - return NS_ERROR_OUT_OF_MEMORY; - } - - NS_ADDREF(*aResult); - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsXPathEvaluator::Evaluate(const nsAString & aExpression, - nsIDOMNode *aContextNode, - PRUint32 aPosition, - PRUint32 aSize, - nsIDOMNode *aResolverNode, - PRUint16 aType, - nsISupports *aInResult, - nsISupports **aResult) -{ - // XXX Need to check document of aContextNode if created by - // QI'ing a document. - - nsCOMPtr expression; - nsresult rv = CreateExpression(aExpression, aResolverNode, - getter_AddRefs(expression)); - NS_ENSURE_SUCCESS(rv, rv); - - return expression->EvaluateWithContext(aContextNode, aPosition, aSize, - aType, aInResult, aResult); -} - - -/* - * Implementation of txIParseContext private to nsXFormsXPathEvaluator - * XFormsParseContextImpl bases on a nsIDOMXPathNSResolver - */ - -nsresult nsXFormsXPathEvaluator::XFormsParseContextImpl::resolveNamespacePrefix - (nsIAtom* aPrefix, PRInt32& aID) -{ - aID = kNameSpaceID_Unknown; - - if (!mResolverNode) { - return NS_ERROR_DOM_NAMESPACE_ERR; - } - - nsAutoString prefix; - if (aPrefix) { - aPrefix->ToString(prefix); - } - - nsVoidableString ns; - nsresult rv; - // begin - taken directly from nsXPathNSResolver::LookupNamespaceURI - if (prefix.EqualsLiteral("xml")) { - ns.AssignLiteral("http://www.w3.org/XML/1998/namespace"); - rv = NS_OK; - } - else { - nsCOMPtr dom3Node = do_QueryInterface(mResolverNode); - NS_ASSERTION(dom3Node, "Need a node to resolve namespaces."); - if( dom3Node ) { - rv = dom3Node->LookupNamespaceURI(prefix, ns); - } - else { - SetDOMStringToNull(ns); - rv = NS_OK; - } - } - // end - taken directly from nsXPathNSResolver::LookupNamespaceURI - NS_ENSURE_SUCCESS(rv, rv); - - if (DOMStringIsNull(ns)) { - return NS_ERROR_DOM_NAMESPACE_ERR; - } - - if (ns.IsEmpty()) { - aID = kNameSpaceID_None; - return NS_OK; - } - - // get the namespaceID for the URI - return nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns, aID); -} - -nsresult -nsXFormsXPathEvaluator::XFormsParseContextImpl::resolveFunctionCall( - nsIAtom* aName, - PRInt32 aNamespaceID, - FunctionCall*& aFnCall) -{ - if (aNamespaceID == kNameSpaceID_None) { - PRBool isOutOfMem = PR_TRUE; - - if (aName == txXPathAtoms::avg) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::AVG); - } - else if (aName == txXPathAtoms::booleanFromString) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::BOOLEANFROMSTRING); - } - else if (aName == txXPathAtoms::countNonEmpty) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::COUNTNONEMPTY); - } - else if (aName == txXPathAtoms::daysFromDate) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::DAYSFROMDATE); - } - else if (aName == txXPathAtoms::_if) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::IF); - } - else if (aName == txXPathAtoms::index) { - NS_ENSURE_TRUE(mResolverNode, NS_ERROR_FAILURE); - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::INDEX, - mResolverNode); - } - else if (aName == txXPathAtoms::instance) { - NS_ENSURE_TRUE(mResolverNode, NS_ERROR_FAILURE); - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::INSTANCE, - mResolverNode); - } - else if (aName == txXPathAtoms::max) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::MAX); - } - else if (aName == txXPathAtoms::min) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::MIN); - } - else if (aName == txXPathAtoms::months) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::MONTHS); - } - else if (aName == txXPathAtoms::now) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::NOW); - } - else if (aName == txXPathAtoms::property) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::PROPERTY); - } - else if (aName == txXPathAtoms::seconds) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::SECONDS); - } - else if (aName == txXPathAtoms::secondsFromDateTime) { - aFnCall = new XFormsFunctionCall(XFormsFunctionCall::SECONDSFROMDATETIME); - } - else { - // didn't find functioncall here, aFnCall should be null - isOutOfMem = PR_FALSE; - } - - if (aFnCall) - { - return NS_OK; - } - else if (isOutOfMem) { - NS_ERROR("XPath FunctionLib failed on out-of-memory"); - return NS_ERROR_OUT_OF_MEMORY; - } - } - return NS_ERROR_XPATH_UNKNOWN_FUNCTION; -} - -PRBool nsXFormsXPathEvaluator::XFormsParseContextImpl::caseInsensitiveNameTests() -{ - // This will always be false since this handles XForms, which is XML-based, - // so case sensitive. - return PR_FALSE; -} - -void -nsXFormsXPathEvaluator::XFormsParseContextImpl::SetErrorOffset(PRUint32 aOffset) -{ -} diff --git a/mozilla/content/xslt/src/xpath/nsXPathEvaluator.cpp b/mozilla/content/xslt/src/xpath/nsXPathEvaluator.cpp index 24bb67087d1..7c0eebdd5f3 100644 --- a/mozilla/content/xslt/src/xpath/nsXPathEvaluator.cpp +++ b/mozilla/content/xslt/src/xpath/nsXPathEvaluator.cpp @@ -59,16 +59,23 @@ class nsXPathEvaluatorParseContext : public txIParseContext { public: - nsXPathEvaluatorParseContext(nsIDOMXPathNSResolver *aResolver, + nsXPathEvaluatorParseContext(nsXPathEvaluator &aEvaluator, + nsIDOMXPathNSResolver* aResolver, + nsTArray *aNamespaceIDs, + nsCStringArray *aContractIDs, + nsCOMArray *aState, PRBool aIsCaseSensitive) - : mResolver(aResolver), + : mEvaluator(aEvaluator), + mResolver(aResolver), + mNamespaceIDs(aNamespaceIDs), + mContractIDs(aContractIDs), + mState(aState), mLastError(NS_OK), mIsCaseSensitive(aIsCaseSensitive) { - } - - ~nsXPathEvaluatorParseContext() - { + NS_ASSERTION(mContractIDs || + (!mNamespaceIDs || mNamespaceIDs->Length() == 0), + "Need contract IDs if there are namespaces."); } nsresult getError() @@ -83,7 +90,11 @@ public: void SetErrorOffset(PRUint32 aOffset); private: + nsXPathEvaluator &mEvaluator; nsIDOMXPathNSResolver* mResolver; + nsTArray *mNamespaceIDs; + nsCStringArray *mContractIDs; + nsCOMArray *mState; nsresult mLastError; PRBool mIsCaseSensitive; }; @@ -113,38 +124,8 @@ nsXPathEvaluator::CreateExpression(const nsAString & aExpression, nsIDOMXPathNSResolver *aResolver, nsIDOMXPathExpression **aResult) { - nsresult rv = NS_OK; - if (!mRecycler) { - nsRefPtr recycler = new txResultRecycler; - NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY); - - rv = recycler->init(); - NS_ENSURE_SUCCESS(rv, rv); - - mRecycler = recycler; - } - - nsCOMPtr doc = do_QueryReferent(mDocument); - nsXPathEvaluatorParseContext pContext(aResolver, - !doc || doc->IsCaseSensitive()); - nsAutoPtr expression; - rv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext, - getter_Transfers(expression)); - if (NS_FAILED(rv)) { - if (rv == NS_ERROR_DOM_NAMESPACE_ERR) { - return NS_ERROR_DOM_NAMESPACE_ERR; - } - - return NS_ERROR_DOM_INVALID_EXPRESSION_ERR; - } - - *aResult = new nsXPathExpression(expression, mRecycler); - if (!*aResult) { - return NS_ERROR_OUT_OF_MEMORY; - } - - NS_ADDREF(*aResult); - return NS_OK; + return CreateExpression(aExpression, aResolver, (nsTArray*)nsnull, + nsnull, nsnull, aResult); } NS_IMETHODIMP @@ -172,7 +153,6 @@ nsXPathEvaluator::Evaluate(const nsAString & aExpression, { // XXX Need to check document of aContextNode if created by // QI'ing a document. - nsCOMPtr expression; nsresult rv = CreateExpression(aExpression, aResolver, getter_AddRefs(expression)); @@ -189,6 +169,85 @@ nsXPathEvaluator::SetDocument(nsIDOMDocument* aDocument) return NS_OK; } +NS_IMETHODIMP +nsXPathEvaluator::CreateExpression(const nsAString & aExpression, + nsIDOMXPathNSResolver *aResolver, + nsStringArray *aNamespaceURIs, + nsCStringArray *aContractIDs, + nsCOMArray *aState, + nsIDOMXPathExpression **aResult) +{ + nsTArray namespaceIDs; + if (aNamespaceURIs) { + PRInt32 count = aNamespaceURIs->Count(); + + if (!aContractIDs || aContractIDs->Count() != count) { + return NS_ERROR_FAILURE; + } + + if (!namespaceIDs.SetLength(count)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + PRInt32 i; + for (i = 0; i < count; ++i) { + if (aContractIDs->CStringAt(i)->IsEmpty()) { + return NS_ERROR_FAILURE; + } + + nsContentUtils::NameSpaceManager()->RegisterNameSpace(*aNamespaceURIs->StringAt(i), namespaceIDs[i]); + } + } + + + return CreateExpression(aExpression, aResolver, &namespaceIDs, aContractIDs, + aState, aResult); +} + +nsresult +nsXPathEvaluator::CreateExpression(const nsAString & aExpression, + nsIDOMXPathNSResolver *aResolver, + nsTArray *aNamespaceIDs, + nsCStringArray *aContractIDs, + nsCOMArray *aState, + nsIDOMXPathExpression **aResult) +{ + nsresult rv; + if (!mRecycler) { + nsRefPtr recycler = new txResultRecycler; + NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY); + + rv = recycler->init(); + NS_ENSURE_SUCCESS(rv, rv); + + mRecycler = recycler; + } + + nsCOMPtr doc = do_QueryReferent(mDocument); + nsXPathEvaluatorParseContext pContext(*this, aResolver, aNamespaceIDs, + aContractIDs, aState, + !doc || doc->IsCaseSensitive()); + + nsAutoPtr expression; + rv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext, + getter_Transfers(expression)); + if (NS_FAILED(rv)) { + if (rv == NS_ERROR_DOM_NAMESPACE_ERR) { + return NS_ERROR_DOM_NAMESPACE_ERR; + } + + return NS_ERROR_DOM_INVALID_EXPRESSION_ERR; + } + + *aResult = new nsXPathExpression(expression, mRecycler); + if (!*aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(*aResult); + return NS_OK; +} + /* * Implementation of txIParseContext private to nsXPathEvaluator, based on a * nsIDOMXPathNSResolver @@ -226,12 +285,31 @@ nsresult nsXPathEvaluatorParseContext::resolveNamespacePrefix return nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns, aID); } +extern nsresult +TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, PRInt32 aNamespaceID, + nsIAtom *aName, nsISupports *aState, + FunctionCall *&aFunction); + nsresult nsXPathEvaluatorParseContext::resolveFunctionCall(nsIAtom* aName, PRInt32 aID, FunctionCall*& aFn) { - return NS_ERROR_XPATH_UNKNOWN_FUNCTION; + nsresult rv = NS_ERROR_XPATH_UNKNOWN_FUNCTION; + + PRUint32 i, count = mNamespaceIDs ? mNamespaceIDs->Length() : 0; + for (i = 0; i < count; ++i) { + if (mNamespaceIDs->ElementAt(i) == aID) { + nsISupports *state = mState ? mState->SafeObjectAt(i) : nsnull; + rv = TX_ResolveFunctionCallXPCOM(*mContractIDs->CStringAt(i), aID, + aName, state, aFn); + if (NS_SUCCEEDED(rv)) { + break; + } + } + } + + return rv; } PRBool nsXPathEvaluatorParseContext::caseInsensitiveNameTests() diff --git a/mozilla/content/xslt/src/xpath/nsXPathEvaluator.h b/mozilla/content/xslt/src/xpath/nsXPathEvaluator.h index c53812ca0ac..a6ce05d55d1 100644 --- a/mozilla/content/xslt/src/xpath/nsXPathEvaluator.h +++ b/mozilla/content/xslt/src/xpath/nsXPathEvaluator.h @@ -43,8 +43,10 @@ #include "nsIXPathEvaluatorInternal.h" #include "nsIWeakReference.h" #include "nsAutoPtr.h" +#include "nsString.h" #include "txResultRecycler.h" #include "nsAgg.h" +#include "nsTArray.h" /** * A class for evaluating an XPath expression string @@ -68,8 +70,21 @@ public: // nsIXPathEvaluatorInternal interface NS_IMETHOD SetDocument(nsIDOMDocument* aDocument); + NS_IMETHOD CreateExpression(const nsAString &aExpression, + nsIDOMXPathNSResolver *aResolver, + nsStringArray *aNamespaceURIs, + nsCStringArray *aContractIDs, + nsCOMArray *aState, + nsIDOMXPathExpression **aResult); private: + nsresult CreateExpression(const nsAString & aExpression, + nsIDOMXPathNSResolver *aResolver, + nsTArray *aNamespaceIDs, + nsCStringArray *aContractIDs, + nsCOMArray *aState, + nsIDOMXPathExpression **aResult); + nsWeakPtr mDocument; nsRefPtr mRecycler; }; diff --git a/mozilla/content/xslt/src/xpath/txNodeSetAdaptor.cpp b/mozilla/content/xslt/src/xpath/txNodeSetAdaptor.cpp new file mode 100644 index 00000000000..b4e1d20b9a8 --- /dev/null +++ b/mozilla/content/xslt/src/xpath/txNodeSetAdaptor.cpp @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Peter Van der Beken. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "txNodeSetAdaptor.h" +#include "txXPathTreeWalker.h" + +txNodeSetAdaptor::txNodeSetAdaptor() + : mWritable(PR_TRUE) +{ +} + +txNodeSetAdaptor::txNodeSetAdaptor(txNodeSet *aNodeSet) + : mNodeSet(aNodeSet), + mWritable(PR_FALSE) +{ + NS_ASSERTION(aNodeSet, + "Don't create an adaptor if you don't have a txNodeSet"); +} + +NS_IMPL_ISUPPORTS1(txNodeSetAdaptor, txINodeSet) + +nsresult +txNodeSetAdaptor::Init() +{ + if (!mNodeSet) { + mNodeSet = new txNodeSet(nsnull); + } + + return mNodeSet ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +txNodeSetAdaptor::Item(PRUint32 aIndex, nsIDOMNode **aResult) +{ + *aResult = nsnull; + + if (aIndex > (PRUint32)mNodeSet->size()) { + return NS_ERROR_ILLEGAL_VALUE; + } + + return txXPathNativeNode::getNode(mNodeSet->get(aIndex), aResult); +} + +NS_IMETHODIMP +txNodeSetAdaptor::ItemAsNumber(PRUint32 aIndex, double *aResult) +{ + if (aIndex > (PRUint32)mNodeSet->size()) { + return NS_ERROR_ILLEGAL_VALUE; + } + + nsAutoString result; + txXPathNodeUtils::appendNodeValue(mNodeSet->get(aIndex), result); + + *aResult = Double::toDouble(result); + + return NS_OK; +} + +NS_IMETHODIMP +txNodeSetAdaptor::ItemAsString(PRUint32 aIndex, nsAString &aResult) +{ + if (aIndex > (PRUint32)mNodeSet->size()) { + return NS_ERROR_ILLEGAL_VALUE; + } + + txXPathNodeUtils::appendNodeValue(mNodeSet->get(aIndex), aResult); + + return NS_OK; +} + +NS_IMETHODIMP +txNodeSetAdaptor::GetLength(PRUint32 *aLength) +{ + *aLength = (PRUint32)mNodeSet->size(); + + return NS_OK; +} + +NS_IMETHODIMP +txNodeSetAdaptor::Add(nsIDOMNode *aNode) +{ + NS_ENSURE_TRUE(mWritable, NS_ERROR_FAILURE); + + nsAutoPtr node(txXPathNativeNode::createXPathNode(aNode)); + + return node ? mNodeSet->add(*node) : NS_ERROR_OUT_OF_MEMORY; +} + +txAExprResult* +txNodeSetAdaptor::GetTxNodeSet() +{ + return mNodeSet; +} diff --git a/mozilla/content/xslt/src/xpath/nsXFormsXPathEvaluator.h b/mozilla/content/xslt/src/xpath/txNodeSetAdaptor.h similarity index 53% rename from mozilla/content/xslt/src/xpath/nsXFormsXPathEvaluator.h rename to mozilla/content/xslt/src/xpath/txNodeSetAdaptor.h index 04375ef822a..6d88e9e778a 100644 --- a/mozilla/content/xslt/src/xpath/nsXFormsXPathEvaluator.h +++ b/mozilla/content/xslt/src/xpath/txNodeSetAdaptor.h @@ -12,15 +12,16 @@ * for the specific language governing rights and limitations under the * License. * - * The Original Code is Mozilla XForms support. + * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is - * IBM Corporation. - * Portions created by the Initial Developer are Copyright (C) 2004 + * Peter Van der Beken. + * Portions created by the Initial Developer are Copyright (C) 2005 * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Aaron Reed + * Peter Van der Beken + * * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -36,66 +37,30 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsXFormsXPathEvaluator_h__ -#define nsXFormsXPathEvaluator_h__ +#ifndef txNodeSetAdaptor_h__ +#define txNodeSetAdaptor_h__ -#include "nsIXFormsXPathEvaluator.h" -#include "txIXPathContext.h" -#include "nsIXPathEvaluatorInternal.h" -#include "nsIWeakReference.h" -#include "nsAutoPtr.h" -#include "txResultRecycler.h" - - -class nsIDOMDocument; -class nsIDOMXPathExpression; +#include "txINodeSet.h" +#include "txNodeSet.h" /** - * A class for evaluating an XPath expression string + * Implements an XPCOM wrapper around an XPath NodeSet. */ -class nsXFormsXPathEvaluator : public nsIXFormsXPathEvaluator + +class txNodeSetAdaptor : public txINodeSet { public: - nsXFormsXPathEvaluator(); - virtual ~nsXFormsXPathEvaluator(); + txNodeSetAdaptor(); + txNodeSetAdaptor(txNodeSet *aNodeSet); + + nsresult Init(); - // nsISupports interface NS_DECL_ISUPPORTS - - // nsIXFormsXPathEvaluator interface - NS_DECL_NSIXFORMXPATHEVALUATOR + NS_DECL_TXINODESET private: - // txIParseContext implementation - class XFormsParseContextImpl : public txIParseContext - { - public: - XFormsParseContextImpl(nsIDOMNode* aResolverNode) - : mResolverNode(aResolverNode), mLastError(NS_OK) - { - } - - ~XFormsParseContextImpl() - { - } - - nsresult getError() - { - return mLastError; - } - - nsresult resolveNamespacePrefix(nsIAtom* aPrefix, PRInt32& aID); - nsresult resolveFunctionCall(nsIAtom* aName, PRInt32 aID, - FunctionCall*& aFunction); - PRBool caseInsensitiveNameTests(); - void SetErrorOffset(PRUint32 aOffset); - - private: - nsIDOMNode* mResolverNode; - nsresult mLastError; - }; - - nsRefPtr mRecycler; + nsRefPtr mNodeSet; + PRBool mWritable; }; -#endif +#endif // txNodeSetAdaptor_h__ diff --git a/mozilla/content/xslt/src/xpath/txRelationalExpr.cpp b/mozilla/content/xslt/src/xpath/txRelationalExpr.cpp index a144687938b..a2a26dbcc26 100644 --- a/mozilla/content/xslt/src/xpath/txRelationalExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txRelationalExpr.cpp @@ -37,6 +37,7 @@ * ***** END LICENSE BLOCK ***** */ #include "txExpr.h" +#include "txDouble.h" #include "txNodeSet.h" #include "txIXPathContext.h" #include "txXPathTreeWalker.h" @@ -118,14 +119,7 @@ RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft, rtype == txAExprResult::NUMBER) { double lval = aLeft->numberValue(); double rval = aRight->numberValue(); -#if defined(XP_WIN) - if (Double::isNaN(lval) || Double::isNaN(rval)) - result = PR_FALSE; - else - result = lval == rval; -#else - result = lval == rval; -#endif + result = TX_DOUBLE_COMPARE(lval, ==, rval); } // Otherwise compare as strings. Try to use the stringobject in @@ -157,27 +151,22 @@ RelationalExpr::compareResults(txIEvalContext* aContext, txAExprResult* aLeft, double leftDbl = aLeft->numberValue(); double rightDbl = aRight->numberValue(); -#if defined(XP_WIN) - if (Double::isNaN(leftDbl) || Double::isNaN(rightDbl)) - return PR_FALSE; -#endif - switch (mOp) { case LESS_THAN: { - return leftDbl < rightDbl; + return TX_DOUBLE_COMPARE(leftDbl, <, rightDbl); } case LESS_OR_EQUAL: { - return leftDbl <= rightDbl; + return TX_DOUBLE_COMPARE(leftDbl, <=, rightDbl); } case GREATER_THAN: { - return leftDbl > rightDbl; + return TX_DOUBLE_COMPARE(leftDbl, >, rightDbl); } case GREATER_OR_EQUAL: { - return leftDbl >= rightDbl; + return TX_DOUBLE_COMPARE(leftDbl, >=, rightDbl); } default: { diff --git a/mozilla/content/xslt/src/xpath/txXFormsFunctionCall.cpp b/mozilla/content/xslt/src/xpath/txXFormsFunctionCall.cpp deleted file mode 100644 index 259d28ebe3e..00000000000 --- a/mozilla/content/xslt/src/xpath/txXFormsFunctionCall.cpp +++ /dev/null @@ -1,647 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla XForms support. - * - * The Initial Developer of the Original Code is - * IBM Corporation. - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Aaron Reed - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * XFormsFunctionCall - * A representation of the XPath NodeSet funtions - */ - -#include "txExpr.h" -#include "nsAutoPtr.h" -#include "txNodeSet.h" -#include "txAtoms.h" -#include "txIXPathContext.h" -#include "txTokenizer.h" -#include "txXFormsFunctions.h" -#include -#include "nsIDOMDocument.h" -#include "nsIDOMDocumentEvent.h" -#include "nsIDOMEvent.h" -#include "nsIDOMEventTarget.h" -#include "nsIDOMElement.h" -#include "nsIXFormsUtilityService.h" -#include "nsServiceManagerUtils.h" // needed for do_GetService? -#include "prprf.h" -#include "txXPathTreeWalker.h" - -/* - * Creates a XFormsFunctionCall of the given type - */ -XFormsFunctionCall::XFormsFunctionCall(XFormsFunctions aType, nsIDOMNode *aResolverNode) - : mType(aType) - , mResolverNode(aResolverNode) -{ -} - -/* - * Evaluates this Expr based on the given context node and processor state - * @param context the context node for evaluation of this Expr - * @param ps the ContextState containing the stack information needed - * for evaluation - * @return the result of the evaluation - */ -nsresult -XFormsFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) -{ - *aResult = nsnull; - nsresult rv = NS_OK; - txListIterator iter(¶ms); - - switch (mType) { - case AVG: - { - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - nsRefPtr nodes; - nsresult rv = evaluateToNodeSet((Expr*)iter.next(), aContext, - getter_AddRefs(nodes)); - NS_ENSURE_SUCCESS(rv, rv); - - double res = 0; - PRInt32 i; - for (i = 0; i < nodes->size(); ++i) { - nsAutoString resultStr; - txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr); - res += Double::toDouble(resultStr); - } - - if (i > 0) { - res = (res/i); - } - else { - res = Double::NaN; - } - return aContext->recycler()->getNumberResult(res, aResult); - } - case BOOLEANFROMSTRING: - { - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - Expr *expr1 = NS_STATIC_CAST(Expr*, iter.next()); - - nsAutoString booleanValue; - expr1->evaluateToString(aContext, booleanValue); - - aContext->recycler()->getBoolResult( - booleanValue.EqualsLiteral("1") || - booleanValue.LowerCaseEqualsLiteral("true"), - aResult); - - return NS_OK; - } - case COUNTNONEMPTY: - { - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - nsRefPtr nodes; - nsresult rv = evaluateToNodeSet((Expr*)iter.next(), aContext, - getter_AddRefs(nodes)); - NS_ENSURE_SUCCESS(rv, rv); - - PRInt32 i, count=0; - for (i = 0; i < nodes->size(); ++i) { - nsAutoString resultStr; - txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr); - if (!resultStr.IsEmpty()) { - count++; - } - } - - return aContext->recycler()->getNumberResult(count, aResult); - } - case DAYSFROMDATE: - { - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - Expr *expr1 = NS_STATIC_CAST(Expr*, iter.next()); - - nsAutoString date; - expr1->evaluateToString(aContext, date); - - nsCOMPtrxformsService = - do_GetService("@mozilla.org/xforms-utility-service;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - PRInt32 result = 0; - double res = Double::NaN; - nsresult rv = xformsService->GetDaysFromDateTime(date, &result); - if (NS_SUCCEEDED(rv)) { - res = result; - } - else if (rv != NS_ERROR_ILLEGAL_VALUE) { - // if we failed for a reason other than the parameter value, pass that - // up the chain - return rv; - } - - return aContext->recycler()->getNumberResult(res, aResult); - } - case IF: - { - if (!requireParams(3, 3, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - Expr *expr1 = NS_STATIC_CAST(Expr*, iter.next()); - - PRBool test; - nsAutoString valueToReturn; - expr1->evaluateToBool(aContext, test); - - // grab 'true' value to return - Expr *getvalue = NS_STATIC_CAST(Expr*, iter.next()); - - if (!test) { - // grab 'false' value to return - getvalue = NS_STATIC_CAST(Expr*, iter.next()); - } - getvalue->evaluateToString(aContext, valueToReturn); - - return aContext->recycler()->getStringResult(valueToReturn, aResult); - } - case INDEX: - { - // Given an element's id as the parameter, need to query the element and - // make sure that it is a xforms:repeat node. Given that, must query - // its index. - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - Expr *expr1 = NS_STATIC_CAST(Expr*, iter.next()); - - nsAutoString indexId; - expr1->evaluateToString(aContext, indexId); - - // here document is the XForms document - nsCOMPtr document; - rv = mResolverNode->GetOwnerDocument(getter_AddRefs(document)); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(document, NS_ERROR_NULL_POINTER); - - // indexId should be the id of a nsIXFormsRepeatElement - nsCOMPtr repeatEle; - rv = document->GetElementById(indexId, getter_AddRefs(repeatEle)); - NS_ENSURE_SUCCESS(rv, rv); - - // now get the index value from the xforms:repeat. Need to use the - // service to do this work so that we don't have dependencies in - // transformiix on XForms. - nsCOMPtrxformsService = - do_GetService("@mozilla.org/xforms-utility-service;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - PRInt32 index = 0; - double res = Double::NaN; - rv = xformsService->GetRepeatIndex(repeatEle, &index); - NS_ENSURE_SUCCESS(rv, rv); - - if (index >= 0) { - // repeat's index is 1-based. If it is 0, then that is still ok since - // repeat's index can be 0 if uninitialized or if the nodeset that it - // is bound to is empty (either initially or due to delete remove all - // of the instance nodes). If index == -1, then repeatEle isn't an - // XForms repeat element, so we need to return NaN per spec. - res = index; - } - - return aContext->recycler()->getNumberResult(res, aResult); - - } - case INSTANCE: - { - nsresult rv; - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - nsRefPtr resultSet; - rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet)); - NS_ENSURE_SUCCESS(rv, rv); - - Expr *expr1 = NS_STATIC_CAST(Expr*, iter.next()); - - nsAutoString instanceId; - expr1->evaluateToString(aContext, instanceId); - - // here document is the XForms document - nsCOMPtr document; - rv = mResolverNode->GetOwnerDocument(getter_AddRefs(document)); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(document, NS_ERROR_NULL_POINTER); - - nsCOMPtr instEle; - rv = document->GetElementById(instanceId, getter_AddRefs(instEle)); - - PRBool foundInstance = PR_FALSE; - nsAutoString localname, namespaceURI; - if (instEle) { - instEle->GetLocalName(localname); - instEle->GetNamespaceURI(namespaceURI); - if (localname.EqualsLiteral("instance") && - namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) { - foundInstance = PR_TRUE; - } - } - - if (!foundInstance) { - // We didn't find an instance element with the given id. Return the - // empty result set. - *aResult = resultSet; - NS_ADDREF(*aResult); - - return NS_OK; - } - - // Make sure that this element is contained in the same - // model as the context node of the expression as per - // the XForms 1.0 spec. - - // first step is to get the contextNode passed in to - // the evaluation - - nsCOMPtr xfContextNode; - rv = txXPathNativeNode::getNode(aContext->getContextNode(), - getter_AddRefs(xfContextNode)); - NS_ENSURE_SUCCESS(rv, rv); - - // now see if the node we found (instEle) and the - // context node for the evaluation (xfContextNode) link - // back to the same model. - nsCOMPtrxformsService = - do_GetService("@mozilla.org/xforms-utility-service;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr instNode, modelInstance; - instNode = do_QueryInterface(instEle); - rv = xformsService->GetModelFromNode(instNode, - getter_AddRefs(modelInstance)); - - NS_ENSURE_SUCCESS(rv, rv); - - PRBool modelContainsNode = PR_FALSE; - rv = xformsService->IsNodeAssocWithModel(xfContextNode, - modelInstance, - &modelContainsNode); - NS_ENSURE_SUCCESS(rv, rv); - - if (modelContainsNode) { - // ok, we've found an instance node with the proper id - // that fulfills the requirement of being from the - // same model as the context node. Now we need to - // return a 'node-set containing just the root - // element node of the referenced instance data'. - // Wonderful. - - nsCOMPtr instanceRoot; - rv = xformsService->GetInstanceDocumentRoot( - instanceId, - modelInstance, - getter_AddRefs(instanceRoot)); - NS_ENSURE_SUCCESS(rv, rv); - if (instanceRoot) { - nsAutoPtr txNode(txXPathNativeNode::createXPathNode(instanceRoot)); - if (txNode) { - resultSet->add(*txNode); - } - } - } - - - // XXX where we need to do the work - // if (walker.moveToElementById(instanceId)) { - // resultSet->add(walker.getCurrentPosition()); - // } - - *aResult = resultSet; - NS_ADDREF(*aResult); - - return NS_OK; - } - case MAX: - { - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - nsRefPtr nodes; - nsresult rv = evaluateToNodeSet((Expr*)iter.next(), aContext, - getter_AddRefs(nodes)); - NS_ENSURE_SUCCESS(rv, rv); - - double res = Double::NaN; - PRInt32 i; - for (i = 0; i < nodes->size(); ++i) { - double test; - nsAutoString resultStr; - txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr); - test = Double::toDouble(resultStr); - if (Double::isNaN(test)) { - res = Double::NaN; - break; - } - if (test > res || i == 0) { - res = test; - } - } - - return aContext->recycler()->getNumberResult(res, aResult); - } - case MIN: - { - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - nsRefPtr nodes; - nsresult rv = evaluateToNodeSet((Expr*)iter.next(), aContext, - getter_AddRefs(nodes)); - NS_ENSURE_SUCCESS(rv, rv); - - double res = Double::NaN; - PRInt32 i; - for (i = 0; i < nodes->size(); ++i) { - double test; - nsAutoString resultStr; - txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr); - test = Double::toDouble(resultStr); - if (Double::isNaN(test)) { - res = Double::NaN; - break; - } - if ((test < res) || (i==0)) { - res = test; - } - } - - return aContext->recycler()->getNumberResult(res, aResult); - } - case MONTHS: - { - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - Expr *expr1 = NS_STATIC_CAST(Expr*, iter.next()); - - nsAutoString duration; - expr1->evaluateToString(aContext, duration); - - nsCOMPtrxformsService = - do_GetService("@mozilla.org/xforms-utility-service;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - PRInt32 result = 0; - double res = Double::NaN; - nsresult rv = xformsService->GetMonths(duration, &result); - if (NS_SUCCEEDED(rv)) { - res = result; - } - else if (rv != NS_ERROR_ILLEGAL_VALUE) { - // if we failed for a reason other than the parameter value, pass that - // up the chain - return rv; - } - - return aContext->recycler()->getNumberResult(res, aResult); - } - case NOW: - { - if (!requireParams(0, 0, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - PRExplodedTime time; - char ctime[60]; - - PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &time); - int gmtoffsethour = time.tm_params.tp_gmt_offset < 0 ? - -1*time.tm_params.tp_gmt_offset / 3600 : - time.tm_params.tp_gmt_offset / 3600; - int remainder = time.tm_params.tp_gmt_offset%3600; - int gmtoffsetminute = remainder ? remainder/60 : 00; - - char zone_location[40]; - const int zoneBufSize = sizeof(zone_location); - PR_snprintf(zone_location, zoneBufSize, "%c%02d:%02d\0", - time.tm_params.tp_gmt_offset < 0 ? '-' : '+', - gmtoffsethour, gmtoffsetminute); - - PR_FormatTime(ctime, sizeof(ctime), "%Y-%m-%dT%H:%M:%S\0", &time); - nsString sTime = NS_ConvertASCIItoUTF16(ctime) + NS_ConvertASCIItoUTF16(zone_location); - - return aContext->recycler()->getStringResult(sTime, aResult); - } - case PROPERTY: - { - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - Expr *expr1 = NS_STATIC_CAST(Expr*, iter.next()); - - nsAutoString property; - expr1->evaluateToString(aContext, property); - - // This function can handle "version" and "conformance-level" - // which is all that the XForms 1.0 spec is worried about - if (property.Equals(NS_LITERAL_STRING("version"))) - property.Assign(NS_LITERAL_STRING("1.0")); - else if (property.Equals(NS_LITERAL_STRING("conformance-level"))) - property.Assign(NS_LITERAL_STRING("basic")); - - return aContext->recycler()->getStringResult(property, aResult); - } - case SECONDS: - { - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - Expr *expr1 = NS_STATIC_CAST(Expr*, iter.next()); - - nsAutoString duration; - expr1->evaluateToString(aContext, duration); - - nsCOMPtrxformsService = - do_GetService("@mozilla.org/xforms-utility-service;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - double res; - nsresult rv = xformsService->GetSeconds(duration, &res); - if (NS_FAILED(rv)) { - if (rv != NS_ERROR_ILLEGAL_VALUE) { - // if we failed for a reason other than the parameter value, pass that - // up the chain - return rv; - } - res = Double::NaN; - } - - return aContext->recycler()->getNumberResult(res, aResult); - } - case SECONDSFROMDATETIME: - { - if (!requireParams(1, 1, aContext)) - return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; - - Expr *expr1 = NS_STATIC_CAST(Expr*, iter.next()); - - nsAutoString dateTime; - expr1->evaluateToString(aContext, dateTime); - - nsCOMPtrxformsService = - do_GetService("@mozilla.org/xforms-utility-service;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - double res; - nsresult rv = xformsService->GetSecondsFromDateTime(dateTime, &res); - if (NS_FAILED(rv)) { - if (rv != NS_ERROR_ILLEGAL_VALUE) { - // if we failed for a reason other than the parameter value, pass that - // up the chain - return rv; - } - res = Double::NaN; - } - - return aContext->recycler()->getNumberResult(res, aResult); - } - } /* switch() */ - - aContext->receiveError(NS_LITERAL_STRING("Internal error"), - NS_ERROR_UNEXPECTED); - return NS_ERROR_UNEXPECTED; -} - -Expr::ResultType -XFormsFunctionCall::getReturnType() -{ - // It doesn't really matter what we return here, but it might - // be a good idea to try to keep this as unoptimizable as possible - return ANY_RESULT; -} - -PRBool -XFormsFunctionCall::isSensitiveTo(ContextSensitivity aContext) -{ - // It doesn't really matter what we return here, but it might - // be a good idea to try to keep this as unoptimizable as possible - return PR_TRUE; -} - -#ifdef TX_TO_STRING -nsresult -XFormsFunctionCall::getNameAtom(nsIAtom** aAtom) -{ - switch (mType) { - case AVG: - { - *aAtom = txXPathAtoms::avg; - break; - } - case BOOLEANFROMSTRING: - { - *aAtom = txXPathAtoms::booleanFromString; - break; - } - case COUNTNONEMPTY: - { - *aAtom = txXPathAtoms::countNonEmpty; - break; - } - case DAYSFROMDATE: - { - *aAtom = txXPathAtoms::daysFromDate; - break; - } - case IF: - { - *aAtom = txXPathAtoms::_if; - break; - } - case INDEX: - { - *aAtom = txXPathAtoms::index; - break; - } - case INSTANCE: - { - *aAtom = txXPathAtoms::instance; - break; - } - case MAX: - { - *aAtom = txXPathAtoms::max; - break; - } - case MIN: - { - *aAtom = txXPathAtoms::min; - break; - } - case MONTHS: - { - *aAtom = txXPathAtoms::months; - break; - } - case NOW: - { - *aAtom = txXPathAtoms::now; - break; - } - case PROPERTY: - { - *aAtom = txXPathAtoms::property; - break; - } - case SECONDS: - { - *aAtom = txXPathAtoms::seconds; - break; - } - case SECONDSFROMDATETIME: - { - *aAtom = txXPathAtoms::secondsFromDateTime; - break; - } - default: - { - *aAtom = 0; - return NS_ERROR_FAILURE; - } - } - NS_ADDREF(*aAtom); - return NS_OK; -} -#endif diff --git a/mozilla/content/xslt/src/xpath/txXPCOMExtensionFunction.cpp b/mozilla/content/xslt/src/xpath/txXPCOMExtensionFunction.cpp new file mode 100644 index 00000000000..60822c2e8f8 --- /dev/null +++ b/mozilla/content/xslt/src/xpath/txXPCOMExtensionFunction.cpp @@ -0,0 +1,587 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Peter Van der Beken. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsAutoPtr.h" +#include "nsComponentManagerUtils.h" +#include "nsDependentString.h" +#include "nsIAtom.h" +#include "nsIInterfaceInfoManager.h" +#include "nsServiceManagerUtils.h" +#include "txExpr.h" +#include "txIFunctionEvaluationContext.h" +#include "txIXPathContext.h" +#include "txNodeSetAdaptor.h" +#include "txXPathTreeWalker.h" +#include "xptcall.h" + +class txFunctionEvaluationContext : public txIFunctionEvaluationContext +{ +public: + txFunctionEvaluationContext(txIEvalContext *aContext, nsISupports *aState); + + NS_DECL_ISUPPORTS + NS_DECL_TXIFUNCTIONEVALUATIONCONTEXT + + void ClearContext() + { + mContext = nsnull; + } + +private: + txIEvalContext *mContext; + nsCOMPtr mState; +}; + +txFunctionEvaluationContext::txFunctionEvaluationContext(txIEvalContext *aContext, + nsISupports *aState) + : mContext(aContext), + mState(aState) +{ +} + +NS_IMPL_ISUPPORTS1(txFunctionEvaluationContext, txIFunctionEvaluationContext) + +NS_IMETHODIMP +txFunctionEvaluationContext::GetPosition(PRUint32 *aPosition) +{ + NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE); + + *aPosition = mContext->position(); + + return NS_OK; +} + +NS_IMETHODIMP +txFunctionEvaluationContext::GetSize(PRUint32 *aSize) +{ + NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE); + + *aSize = mContext->size(); + + return NS_OK; +} + +NS_IMETHODIMP +txFunctionEvaluationContext::GetContextNode(nsIDOMNode **aNode) +{ + NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE); + + return txXPathNativeNode::getNode(mContext->getContextNode(), aNode); +} + +NS_IMETHODIMP +txFunctionEvaluationContext::GetState(nsISupports **aState) +{ + NS_IF_ADDREF(*aState = mState); + + return NS_OK; +} + +enum txArgumentType { + BOOLEAN = nsXPTType::T_BOOL, + NUMBER = nsXPTType::T_DOUBLE, + STRING = nsXPTType::T_DOMSTRING, + NODESET, + CONTEXT, + UNKNOWN +}; + +class txXPCOMExtensionFunctionCall : public FunctionCall +{ +public: + txXPCOMExtensionFunctionCall(nsISupports *aHelper, const nsIID &aIID, + PRUint16 aMethodIndex, +#ifdef TX_TO_STRING + PRInt32 aNamespaceID, nsIAtom *aName, +#endif + nsISupports *aState); + + TX_DECL_FUNCTION; + +private: + txArgumentType GetParamType(const nsXPTParamInfo &aParam, + nsIInterfaceInfo *aInfo); + + nsCOMPtr mHelper; + nsIID mIID; + PRUint16 mMethodIndex; +#ifdef TX_TO_STRING + PRInt32 mNamespaceID; + nsCOMPtr mName; +#endif + nsCOMPtr mState; +}; + +txXPCOMExtensionFunctionCall::txXPCOMExtensionFunctionCall(nsISupports *aHelper, + const nsIID &aIID, + PRUint16 aMethodIndex, +#ifdef TX_TO_STRING + PRInt32 aNamespaceID, + nsIAtom *aName, +#endif + nsISupports *aState) + : mHelper(aHelper), + mIID(aIID), + mMethodIndex(aMethodIndex), +#ifdef TX_TO_STRING + mNamespaceID(aNamespaceID), + mName(aName), +#endif + mState(aState) +{ +} + +class txInterfacesArrayHolder +{ +public: + txInterfacesArrayHolder(nsIID **aArray, PRUint32 aCount) : mArray(aArray), + mCount(aCount) + { + } + ~txInterfacesArrayHolder() + { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCount, mArray); + } + +private: + nsIID **mArray; + PRUint32 mCount; +}; + +static nsresult +LookupFunction(const char *aContractID, nsIAtom* aName, nsIID &aIID, + PRUint16 &aMethodIndex) +{ + nsresult rv; + nsCOMPtr classInfo = do_GetClassObject(aContractID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr iim = + do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(iim, NS_ERROR_FAILURE); + + nsIID** iidArray = nsnull; + PRUint32 iidCount = 0; + rv = classInfo->GetInterfaces(&iidCount, &iidArray); + NS_ENSURE_SUCCESS(rv, rv); + + txInterfacesArrayHolder holder(iidArray, iidCount); + + // Remove any minus signs and uppercase the following letter (so + // foo-bar becomes fooBar). Note that if there are any names that already + // have uppercase letters they might cause false matches (both fooBar and + // foo-bar matching fooBar). + const char *name; + aName->GetUTF8String(&name); + nsCAutoString methodName; + char letter; + PRBool upperNext = PR_FALSE; + while ((letter = *name)) { + if (letter == '-') { + upperNext = PR_TRUE; + } + else { + methodName.Append(upperNext ? nsCRT::ToUpper(letter) : letter); + upperNext = PR_FALSE; + } + ++name; + } + + PRUint32 i; + for (i = 0; i < iidCount; ++i) { + nsIID *iid = iidArray[i]; + + nsCOMPtr info; + rv = iim->GetInfoForIID(iid, getter_AddRefs(info)); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint16 methodIndex; + const nsXPTMethodInfo *methodInfo; + rv = info->GetMethodInfoForName(methodName.get(), &methodIndex, + &methodInfo); + if (NS_SUCCEEDED(rv)) { + // Exclude notxpcom and hidden. Also check that we have at least a + // return value (the xpidl compiler ensures that that return value + // is the last argument). + PRUint8 paramCount = methodInfo->GetParamCount(); + if (methodInfo->IsNotXPCOM() || methodInfo->IsHidden() || + paramCount == 0 || + !methodInfo->GetParam(paramCount - 1).IsRetval()) { + return NS_ERROR_FAILURE; + } + + aIID = *iid; + aMethodIndex = methodIndex; + + return NS_OK; + } + } + + return NS_ERROR_XPATH_UNKNOWN_FUNCTION; +} + +/* static */ +nsresult +TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, PRInt32 aNamespaceID, + nsIAtom* aName, nsISupports *aState, + FunctionCall *&aFunction) +{ + nsIID iid; + PRUint16 methodIndex; + nsresult rv = LookupFunction(aContractID.get(), aName, iid, methodIndex); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr helper; + rv = CallGetService(aContractID.get(), iid, getter_AddRefs(helper)); + NS_ENSURE_SUCCESS(rv, rv); + + aFunction = new txXPCOMExtensionFunctionCall(helper, iid, methodIndex, +#ifdef TX_TO_STRING + aNamespaceID, aName, +#endif + aState); + + return aFunction ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +txArgumentType +txXPCOMExtensionFunctionCall::GetParamType(const nsXPTParamInfo &aParam, + nsIInterfaceInfo *aInfo) +{ + PRUint8 tag = aParam.GetType().TagPart(); + switch (tag) { + case nsXPTType::T_BOOL: + case nsXPTType::T_DOUBLE: + case nsXPTType::T_DOMSTRING: + { + return txArgumentType(tag); + } + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + nsIID iid; + aInfo->GetIIDForParamNoAlloc(mMethodIndex, &aParam, &iid); + if (iid.Equals(NS_GET_IID(txINodeSet))) { + return NODESET; + } + if (iid.Equals(NS_GET_IID(txIFunctionEvaluationContext))) { + return CONTEXT; + } + } + default: + { + // XXX Error! + return UNKNOWN; + } + } +} + +class txParamArrayHolder +{ +public: + txParamArrayHolder() + : mCount(0) + { + } + ~txParamArrayHolder(); + + PRBool Init(PRUint8 aCount); + operator nsXPTCVariant*() const + { + return mArray; + } + +private: + nsAutoArrayPtr mArray; + PRUint8 mCount; +}; + +txParamArrayHolder::~txParamArrayHolder() +{ + PRUint8 i; + for (i = 0; i < mCount; ++i) { + nsXPTCVariant &variant = mArray[i]; + if (variant.IsValInterface()) { + NS_STATIC_CAST(nsISupports*, variant.val.p)->Release(); + } + else if (variant.IsValDOMString()) { + delete (nsAString*)variant.val.p; + } + } +} + +PRBool +txParamArrayHolder::Init(PRUint8 aCount) +{ + mCount = aCount; + mArray = new nsXPTCVariant[mCount]; + if (!mArray) { + return PR_FALSE; + } + + memset(mArray, 0, mCount * sizeof(nsXPTCVariant)); + + return PR_TRUE; +} + +nsresult +txXPCOMExtensionFunctionCall::evaluate(txIEvalContext* aContext, + txAExprResult** aResult) +{ + nsCOMPtr iim = + do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(iim, NS_ERROR_FAILURE); + + nsCOMPtr info; + nsresult rv = iim->GetInfoForIID(&mIID, getter_AddRefs(info)); + NS_ENSURE_SUCCESS(rv, rv); + + const nsXPTMethodInfo *methodInfo; + rv = info->GetMethodInfo(mMethodIndex, &methodInfo); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint8 paramCount = methodInfo->GetParamCount(); + PRUint8 inArgs = paramCount - 1; + + txParamArrayHolder invokeParams; + if (!invokeParams.Init(paramCount)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(0); + txArgumentType type = GetParamType(paramInfo, info); + if (type == UNKNOWN) { + return NS_ERROR_FAILURE; + } + + txFunctionEvaluationContext *context; + PRUint8 i = 0; + if (type == CONTEXT) { + if (paramInfo.IsOut()) { + // We don't support out values. + return NS_ERROR_FAILURE; + } + + // Create context wrapper. + context = new txFunctionEvaluationContext(aContext, mState); + if (!context) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsXPTCVariant &invokeParam = invokeParams[0]; + invokeParam.type = paramInfo.GetType(); + invokeParam.SetValIsInterface(); + NS_ADDREF((txIFunctionEvaluationContext*&)invokeParam.val.p = context); + + // Skip first argument, since it's the context. + ++i; + } + else { + context = nsnull; + } + + // XXX varargs + if (!requireParams(inArgs - i, inArgs - i, aContext)) { + return NS_ERROR_FAILURE; + } + + txListIterator iter(¶ms); + for (; i < inArgs; ++i) { + Expr* expr = NS_STATIC_CAST(Expr*, iter.next()); + + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(i); + txArgumentType type = GetParamType(paramInfo, info); + if (type == UNKNOWN) { + return NS_ERROR_FAILURE; + } + + nsXPTCVariant &invokeParam = invokeParams[i]; + if (paramInfo.IsOut()) { + // We don't support out values. + return NS_ERROR_FAILURE; + } + + invokeParam.type = paramInfo.GetType(); + switch (type) { + case NODESET: + { + nsRefPtr nodes; + rv = evaluateToNodeSet(expr, aContext, getter_AddRefs(nodes)); + NS_ENSURE_SUCCESS(rv, rv); + + txNodeSetAdaptor *adaptor = new txNodeSetAdaptor(nodes); + if (!adaptor) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsCOMPtr nodeSet = adaptor; + rv = adaptor->Init(); + NS_ENSURE_SUCCESS(rv, rv); + + invokeParam.SetValIsInterface(); + nodeSet.swap((txINodeSet*&)invokeParam.val.p); + break; + } + case BOOLEAN: + { + rv = expr->evaluateToBool(aContext, invokeParam.val.b); + NS_ENSURE_SUCCESS(rv, rv); + + break; + } + case NUMBER: + { + invokeParam.val.d = evaluateToNumber(expr, aContext); + break; + } + case STRING: + { + nsString *value = new nsString(); + if (!value) { + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = expr->evaluateToString(aContext, *value); + NS_ENSURE_SUCCESS(rv, rv); + + invokeParam.SetValIsDOMString(); + invokeParam.val.p = value; + break; + } + case CONTEXT: + case UNKNOWN: + { + // We only support passing the context as the *first* argument. + return NS_ERROR_FAILURE; + } + } + } + + const nsXPTParamInfo &returnInfo = methodInfo->GetParam(inArgs); + txArgumentType returnType = GetParamType(returnInfo, info); + if (returnType == UNKNOWN) { + return NS_ERROR_FAILURE; + } + + nsXPTCVariant &returnParam = invokeParams[inArgs]; + returnParam.type = returnInfo.GetType(); + if (returnType == STRING) { + nsString *value = new nsString(); + if (!value) { + return NS_ERROR_FAILURE; + } + + returnParam.SetValIsDOMString(); + returnParam.val.p = value; + } + else { + returnParam.SetPtrIsData(); + returnParam.ptr = &returnParam.val; + } + + rv = XPTC_InvokeByIndex(mHelper, mMethodIndex, paramCount, invokeParams); + + // In case someone is holding on to the txFunctionEvaluationContext which + // could thus stay alive longer than this function. + if (context) { + context->ClearContext(); + } + + NS_ENSURE_SUCCESS(rv, rv); + + switch (returnType) { + case NODESET: + { + txINodeSet *nodeSet = NS_STATIC_CAST(txINodeSet*, + returnParam.val.p); + + NS_ADDREF(*aResult = nodeSet->GetTxNodeSet()); + + return NS_OK; + } + case BOOLEAN: + { + aContext->recycler()->getBoolResult(returnParam.val.b, aResult); + + return NS_OK; + } + case NUMBER: + { + return aContext->recycler()->getNumberResult(returnParam.val.d, + aResult); + } + case STRING: + { + nsString *returned = NS_STATIC_CAST(nsString*, + returnParam.val.p); + return aContext->recycler()->getStringResult(*returned, aResult); + } + default: + { + // Huh? + return NS_ERROR_FAILURE; + } + } +} + +Expr::ResultType +txXPCOMExtensionFunctionCall::getReturnType() +{ + // It doesn't really matter what we return here, but it might + // be a good idea to try to keep this as unoptimizable as possible + return ANY_RESULT; +} + +PRBool +txXPCOMExtensionFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + // It doesn't really matter what we return here, but it might + // be a good idea to try to keep this as unoptimizable as possible + return PR_TRUE; +} + +#ifdef TX_TO_STRING +nsresult +txXPCOMExtensionFunctionCall::getNameAtom(nsIAtom** aAtom) +{ + NS_ADDREF(*aAtom = mName); + + return NS_OK; +} +#endif diff --git a/mozilla/extensions/xforms/Makefile.in b/mozilla/extensions/xforms/Makefile.in index 20c62c70873..dcbc6500f29 100644 --- a/mozilla/extensions/xforms/Makefile.in +++ b/mozilla/extensions/xforms/Makefile.in @@ -148,6 +148,7 @@ XPIDLSRCS = \ nsIXFormsCopyElement.idl \ nsIXFormsEphemeralMessageUI.idl \ nsIXFormsRangeConditionAccessors.idl \ + nsIXFormsXPathFunctions.idl \ $(NULL) # XForms source files @@ -208,6 +209,7 @@ CPPSRCS = \ nsXFormsRangeAccessors.cpp \ nsXFormsCopyElement.cpp \ nsXFormsRangeConditionAccessors.cpp \ + nsXFormsXPathFunctions.cpp \ $(NULL) # Standard Mozilla make rules diff --git a/mozilla/extensions/xforms/nsIXFormsXPathFunctions.idl b/mozilla/extensions/xforms/nsIXFormsXPathFunctions.idl new file mode 100644 index 00000000000..50643091815 --- /dev/null +++ b/mozilla/extensions/xforms/nsIXFormsXPathFunctions.idl @@ -0,0 +1,60 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Peter Van der Beken. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" +#include "txIFunctionEvaluationContext.idl" + +[scriptable, uuid(cc846954-69a0-11d9-9791-000a95dc234c)] +interface nsIXFormsXPathFunctions : nsISupports +{ + double avg(in txINodeSet aNodeSet); + boolean booleanFromString(in DOMString aString); + double countNonEmpty(in txINodeSet aNodeSet); + double daysFromDate(in DOMString aDateTime); + DOMString if(in boolean aValue, in DOMString aIfString, in DOMString aElseString); + double index(in txIFunctionEvaluationContext aContext, in DOMString aId); + txINodeSet instance(in txIFunctionEvaluationContext aContext, in DOMString aString); + double max(in txINodeSet aNodeSet); + double min(in txINodeSet aNodeSet); + double months(in DOMString aDuration); + DOMString now(); + DOMString property(in DOMString aProperty); + double seconds(in DOMString aDuration); + double secondsFromDateTime(in DOMString aDateTime); +}; diff --git a/mozilla/extensions/xforms/nsXFormsMDGEngine.cpp b/mozilla/extensions/xforms/nsXFormsMDGEngine.cpp index 36131a7249b..6b00b87f4f1 100644 --- a/mozilla/extensions/xforms/nsXFormsMDGEngine.cpp +++ b/mozilla/extensions/xforms/nsXFormsMDGEngine.cpp @@ -380,14 +380,16 @@ nsXFormsMDGEngine::Recalculate(nsCOMArray *aChangedNodes) switch (g->mType) { case eModel_calculate: if (g->HasExpr()) { - nsCOMPtr xpath_res; + nsCOMPtr result; rv = g->mExpression->EvaluateWithContext(g->mContextNode, g->mContextPosition, g->mContextSize, nsIDOMXPathResult::STRING_TYPE, nsnull, - getter_AddRefs(xpath_res)); + getter_AddRefs(result)); NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr xpath_res = do_QueryInterface(result); NS_ENSURE_STATE(xpath_res); nsAutoString nodeval; @@ -1039,7 +1041,7 @@ nsXFormsMDGEngine::BooleanExpression(nsXFormsMDGNode* aNode, PRBool& state) NS_ENSURE_ARG_POINTER(aNode); NS_ENSURE_TRUE(aNode->mExpression, NS_ERROR_FAILURE); - nsISupports* retval; + nsCOMPtr retval; nsresult rv; rv = aNode->mExpression->EvaluateWithContext(aNode->mContextNode, @@ -1047,7 +1049,7 @@ nsXFormsMDGEngine::BooleanExpression(nsXFormsMDGNode* aNode, PRBool& state) aNode->mContextSize, nsIDOMXPathResult::BOOLEAN_TYPE, nsnull, - &retval); + getter_AddRefs(retval)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr xpath_res = do_QueryInterface(retval); diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.cpp b/mozilla/extensions/xforms/nsXFormsModelElement.cpp index 7b46efcb426..e8584961296 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsModelElement.cpp @@ -55,7 +55,9 @@ #include "nsIDOMXMLDocument.h" #include "nsIDOMEventReceiver.h" #include "nsIDOMXPathResult.h" -#include "nsIXFormsXPathEvaluator.h" +#include "nsIDOMXPathEvaluator.h" +#include "nsIXPathEvaluatorInternal.h" +#include "nsIDOMXPathExpression.h" #include "nsIDOMXPathNSResolver.h" #include "nsIDOMNSXPathExpression.h" #include "nsIContent.h" @@ -1983,10 +1985,10 @@ nsXFormsModelElement::ProcessBindElements() firstInstanceDoc->GetDocumentElement(getter_AddRefs(firstInstanceRoot)); nsresult rv; - nsCOMPtr xpath = - do_CreateInstance("@mozilla.org/dom/xforms-xpath-evaluator;1", &rv); - NS_ENSURE_TRUE(xpath, rv); - + nsCOMPtr xpath = do_QueryInterface(firstInstanceDoc, + &rv); + NS_ENSURE_TRUE(rv, rv); + nsCOMPtr children; mElement->GetChildNodes(getter_AddRefs(children)); @@ -2266,19 +2268,26 @@ nsXFormsModelElement::MaybeNotifyCompletion() } nsresult -nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, - nsIDOMNode *aContextNode, - PRInt32 aContextPosition, - PRInt32 aContextSize, - nsIDOMElement *aBindElement, - PRBool aIsOuter) +nsXFormsModelElement::ProcessBind(nsIDOMXPathEvaluator *aEvaluator, + nsIDOMNode *aContextNode, + PRInt32 aContextPosition, + PRInt32 aContextSize, + nsIDOMElement *aBindElement, + PRBool aIsOuter) { // Get the model item properties specified by this \. - nsCOMPtr props[eModel__count]; + nsCOMPtr props[eModel__count]; nsAutoString propStrings[eModel__count]; - nsresult rv; nsAutoString attrStr; + nsCOMPtr resolver; + nsresult rv = aEvaluator->CreateNSResolver(aBindElement, + getter_AddRefs(resolver)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr eval = do_QueryInterface(aEvaluator, &rv); + NS_ENSURE_SUCCESS(rv, rv); + for (PRUint32 i = 0; i < eModel__count; ++i) { sModelPropsList[i]->ToString(attrStr); @@ -2286,8 +2295,9 @@ nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, if (!propStrings[i].IsEmpty() && i != eModel_type && i != eModel_p3ptype) { - rv = aEvaluator->CreateExpression(propStrings[i], aBindElement, - getter_AddRefs(props[i])); + rv = nsXFormsUtils::CreateExpression(eval, propStrings[i], resolver, + aBindElement, + getter_AddRefs(props[i])); if (NS_FAILED(rv)) { const PRUnichar *strings[] = { propStrings[i].get() }; nsXFormsUtils::ReportError(NS_LITERAL_STRING("mipParseError"), @@ -2301,21 +2311,21 @@ nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, // Find the nodeset that this bind applies to. nsCOMPtr result; - nsAutoString expr; - aBindElement->GetAttribute(NS_LITERAL_STRING("nodeset"), expr); - if (expr.IsEmpty()) { - expr = NS_LITERAL_STRING("."); + nsAutoString exprString; + aBindElement->GetAttribute(NS_LITERAL_STRING("nodeset"), exprString); + if (exprString.IsEmpty()) { + exprString = NS_LITERAL_STRING("."); } - rv = aEvaluator->Evaluate(expr, aContextNode, aContextPosition, aContextSize, - aBindElement, - nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, - nsnull, getter_AddRefs(result)); + + rv = nsXFormsUtils::EvaluateXPath(eval, exprString, aContextNode, resolver, + aBindElement, + nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, + aContextPosition, aContextSize, + nsnull, getter_AddRefs(result)); if (NS_FAILED(rv)) { if (rv == NS_ERROR_DOM_INVALID_EXPRESSION_ERR) { // the xpath expression isn't valid xpath - - const nsPromiseFlatString& flat = PromiseFlatString(expr); - const PRUnichar *strings[] = { flat.get() }; + const PRUnichar *strings[] = { exprString.get() }; nsXFormsUtils::ReportError(NS_LITERAL_STRING("exprParseError"), strings, 1, aBindElement, nsnull); nsXFormsUtils::DispatchEvent(mElement, eEvent_ComputeException); @@ -2323,7 +2333,7 @@ nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, #ifdef DEBUG printf("xforms-binding-exception: XPath Evaluation failed\n"); #endif - const PRUnichar *strings[] = { expr.get() }; + const PRUnichar *strings[] = { exprString.get() }; nsXFormsUtils::ReportError(NS_LITERAL_STRING("nodesetEvaluateError"), strings, 1, aBindElement, aBindElement); nsXFormsUtils::DispatchEvent(mElement, eEvent_BindingException); @@ -2367,7 +2377,7 @@ nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, // Apply MIPs nsXFormsXPathParser parser; - nsXFormsXPathAnalyzer analyzer(aEvaluator, aBindElement); + nsXFormsXPathAnalyzer analyzer(eval, resolver, aBindElement); PRBool multiMIP = PR_FALSE; for (PRUint32 j = 0; j < eModel__count; ++j) { if (propStrings[j].IsEmpty()) @@ -2402,7 +2412,7 @@ nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, } } else { // the rest of the MIPs are given to the MDG - nsCOMPtr expr = props[j]; + nsCOMPtr expr = do_QueryInterface(props[j]); // Get node dependencies nsAutoPtr xNode(parser.Parse(propStrings[j])); diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.h b/mozilla/extensions/xforms/nsXFormsModelElement.h index ccd14cb4e51..5ffd2002821 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.h +++ b/mozilla/extensions/xforms/nsXFormsModelElement.h @@ -60,7 +60,7 @@ class nsIDOMElement; class nsIDOMNode; -class nsIXFormsXPathEvaluator; +class nsIDOMXPathEvaluator; class nsIDOMXPathResult; class nsXFormsControl; class nsXFormsModelInstanceDocuments; @@ -310,12 +310,12 @@ private: NS_HIDDEN_(nsresult) ConstructDone(); NS_HIDDEN_(void) MaybeNotifyCompletion(); - NS_HIDDEN_(nsresult) ProcessBind(nsIXFormsXPathEvaluator *aEvaluator, - nsIDOMNode *aContextNode, - PRInt32 aContextPosition, - PRInt32 aContextSize, - nsIDOMElement *aBindElement, - PRBool aIsOuter = PR_FALSE); + NS_HIDDEN_(nsresult) ProcessBind(nsIDOMXPathEvaluator *aEvaluator, + nsIDOMNode *aContextNode, + PRInt32 aContextPosition, + PRInt32 aContextSize, + nsIDOMElement *aBindElement, + PRBool aIsOuter = PR_FALSE); NS_HIDDEN_(void) RemoveModelFromDocument(); diff --git a/mozilla/extensions/xforms/nsXFormsModule.cpp b/mozilla/extensions/xforms/nsXFormsModule.cpp index ec1e556cc9f..4d6806635fc 100644 --- a/mozilla/extensions/xforms/nsXFormsModule.cpp +++ b/mozilla/extensions/xforms/nsXFormsModule.cpp @@ -44,6 +44,8 @@ #include "nsXFormsUtils.h" #include "nsICategoryManager.h" #include "nsIServiceManager.h" +#include "nsIClassInfoImpl.h" +#include "nsXFormsXPathFunctions.h" // bb0d9c8b-3096-4b66-92a0-6c1ddf80e65f #define NS_XFORMSUTILITYSERVICE_CID \ @@ -52,9 +54,15 @@ #define NS_XFORMSUTILITYSERVICE_CONTRACTID \ "@mozilla.org/xforms-utility-service;1" +#define XFORMSXPATHFUNCTIONS_CID \ +{ 0x8edc8cf1, 0x69a3, 0x11d9, { 0x97, 0x91, 0x00, 0x0a, 0x95, 0xdc, 0x23, 0x4c } } +#define XFORMSXPATHFUNCTIONS_CONTRACTID \ +"@mozilla.org/xforms-xpath-functions;1" + NS_GENERIC_FACTORY_CONSTRUCTOR(nsXFormsElementFactory) NS_GENERIC_FACTORY_CONSTRUCTOR(nsXFormsUtilityService) - +NS_GENERIC_FACTORY_CONSTRUCTOR(nsXFormsXPathFunctions) +NS_DECL_CLASSINFO(nsXFormsXPathFunctions) static NS_IMETHODIMP RegisterXFormsModule(nsIComponentManager *aCompMgr, @@ -132,6 +140,15 @@ static const nsModuleComponentInfo components[] = { NS_XFORMSUTILITYSERVICE_CID, NS_XFORMSUTILITYSERVICE_CONTRACTID, nsXFormsUtilityServiceConstructor + }, + { "XForms XPath extension functions", + XFORMSXPATHFUNCTIONS_CID, + XFORMSXPATHFUNCTIONS_CONTRACTID, + nsXFormsXPathFunctionsConstructor, + nsnull, nsnull, nsnull, + NS_CI_INTERFACE_GETTER_NAME(nsXFormsXPathFunctions), + nsnull, + &NS_CLASSINFO_NAME(nsXFormsXPathFunctions) } }; diff --git a/mozilla/extensions/xforms/nsXFormsUtilityService.cpp b/mozilla/extensions/xforms/nsXFormsUtilityService.cpp index 03528e15ba0..515a1bff51d 100644 --- a/mozilla/extensions/xforms/nsXFormsUtilityService.cpp +++ b/mozilla/extensions/xforms/nsXFormsUtilityService.cpp @@ -36,389 +36,6 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsIServiceManager.h" #include "nsXFormsUtilityService.h" -#include "nsXFormsUtils.h" -#include "nsIXTFElement.h" -#include "nsIDOMNode.h" -#include "nsIDOMElement.h" -#include "nsString.h" -#include "nsIDOMDocument.h" -#include "nsIXFormsModelElement.h" -#include "nsIDOMNodeList.h" -#include "nsIInstanceElementPrivate.h" -#include "nsIXFormsRepeatElement.h" -#include "nsISchemaValidator.h" -#include "nsISchemaDuration.h" -#include "nsXFormsSchemaValidator.h" -#include "prdtoa.h" NS_IMPL_ISUPPORTS1(nsXFormsUtilityService, nsIXFormsUtilityService) - -/* I don't know why Doron didn't put this in the .idl so that it could be added - * to the generated .h file. Put it here for now - */ -#define NS_SCHEMAVALIDATOR_CONTRACTID "@mozilla.org/schemavalidator;1" - - -NS_IMETHODIMP -nsXFormsUtilityService::GetModelFromNode(nsIDOMNode *aNode, - nsIDOMNode **aModel) -{ - nsCOMPtr element = do_QueryInterface(aNode); - NS_ASSERTION(aModel, "no return buffer, we'll crash soon"); - *aModel = nsnull; - - nsAutoString namespaceURI; - aNode->GetNamespaceURI(namespaceURI); - - // If the node is in the XForms namespace and XTF based, then it should - // be able to be handled by GetModel. Otherwise it is probably an instance - // node in a instance document. - if (!namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) { - return NS_ERROR_FAILURE; - } - - nsCOMPtr modelPriv = nsXFormsUtils::GetModel(element); - nsCOMPtr modelElement = do_QueryInterface(modelPriv); - if( modelElement ) { - NS_IF_ADDREF(*aModel = modelElement); - } - - // No model found - NS_ENSURE_TRUE(*aModel, NS_ERROR_FAILURE); - - return NS_OK; -} - - -/** - * Function to see if the given node is associated with the given model. - * Right now this function is only called by XPath in the case of the - * instance() function. - * The provided node can be an instance node from an instance - * document and thus be associated to the model in that way (model elements - * contain instance elements). Otherwise the node will be an XForms element - * that was used as the context node of the XPath expression (i.e the - * XForms control has an attribute that contains an XPath expression). - * Form controls are associated with model elements either explicitly through - * single-node binding or implicitly (if model cannot by calculated, it - * will use the first model element encountered in the document). The model - * can also be inherited from a containing element like xforms:group or - * xforms:repeat. - */ -NS_IMETHODIMP -nsXFormsUtilityService::IsNodeAssocWithModel( nsIDOMNode *aNode, - nsIDOMNode *aModel, - PRBool *aModelAssocWithNode) -{ - - nsCOMPtr modelNode; - - nsAutoString namespaceURI; - aNode->GetNamespaceURI(namespaceURI); - // If the node is in the XForms namespace and XTF based, then it should - // be able to be handled by GetModel. Otherwise it is probably an instance - // node in a instance document. - if (namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) { - nsCOMPtr element = do_QueryInterface(aNode); - nsCOMPtr modelPriv = nsXFormsUtils::GetModel(element); - modelNode = do_QueryInterface(modelPriv); - } else { - // We are assuming that if the node coming in isn't a proper XForms element, - // then it is an instance element in an instance doc. Now we just have - // to determine if the given model contains this instance document. - nsCOMPtr instNode; - nsresult rv = - nsXFormsUtils::GetInstanceNodeForData(aNode, getter_AddRefs(instNode)); - if (NS_SUCCEEDED(rv) && instNode) { - instNode->GetParentNode(getter_AddRefs(modelNode)); - } - } - - if (modelNode && (modelNode == aModel)) { - *aModelAssocWithNode = PR_TRUE; - } else { - *aModelAssocWithNode = PR_FALSE; - } - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsUtilityService::GetInstanceDocumentRoot(const nsAString& aID, - nsIDOMNode *aModelNode, - nsIDOMNode **aInstanceRoot) -{ - nsresult rv = NS_ERROR_FAILURE; - NS_ASSERTION(aInstanceRoot, "no return buffer, we'll crash soon"); - *aInstanceRoot = nsnull; - - if (aID.IsEmpty()) { - return rv; - } - - nsCOMPtr modelElement = do_QueryInterface(aModelNode); - nsCOMPtr doc; - rv = modelElement->GetInstanceDocument(aID, getter_AddRefs(doc)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr element; - rv = doc->GetDocumentElement(getter_AddRefs(element)); - NS_ENSURE_SUCCESS(rv, rv); - - if (element) { - NS_IF_ADDREF(*aInstanceRoot = element); - } - - return rv; -} - -/* Gotta do this via the service since we don't want transformiix to require - * any of the new extensions, like schema-validation - */ -NS_IMETHODIMP -nsXFormsUtilityService::ValidateString(const nsAString & aValue, - const nsAString & aType, - const nsAString & aNamespace, - PRBool *aResult) -{ - - NS_ASSERTION(aResult, "no return buffer for result so we'll crash soon"); - *aResult = PR_FALSE; - - nsXFormsSchemaValidator *validator = new nsXFormsSchemaValidator(); - if (validator) { - *aResult = validator->ValidateString(aValue, aType, aNamespace); - delete validator; - } - return *aResult ? NS_OK : NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsXFormsUtilityService::GetRepeatIndex(nsIDOMNode *aRepeat, PRInt32 *aIndex) -{ - NS_ASSERTION(aIndex, "no return buffer for index, we'll crash soon"); - *aIndex = 0; - - nsCOMPtr repeatEle = do_QueryInterface(aRepeat); - if (!repeatEle) { - // if aRepeat isn't a repeat element, then setting aIndex to -1 to tell - // XPath to return NaN. Per 7.8.5 in the spec (1.0, 2nd edition) - *aIndex = -1; - } else { - PRUint32 retIndex = 0; - nsresult rv = repeatEle->GetIndex(&retIndex); - NS_ENSURE_SUCCESS(rv, rv); - *aIndex = retIndex; - } - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsUtilityService::GetMonths(const nsAString & aValue, - PRInt32 * aMonths) -{ - NS_ASSERTION(aMonths, "no return buffer for months, we'll crash soon"); - - *aMonths = 0; - nsCOMPtr duration; - nsCOMPtr schemaValidator = - do_CreateInstance(NS_SCHEMAVALIDATOR_CONTRACTID); - NS_ENSURE_TRUE(schemaValidator, NS_ERROR_FAILURE); - - nsresult rv = schemaValidator->ValidateBuiltinTypeDuration(aValue, - getter_AddRefs(duration)); - NS_ENSURE_SUCCESS(rv, rv); - - PRInt32 sumMonths; - PRUint32 years; - PRUint32 months; - - duration->GetYears(&years); - duration->GetMonths(&months); - - sumMonths = months + years*12; - PRBool negative; - duration->GetNegative(&negative); - if (negative) { - // according to the spec, "the sign of the result will match the sign - // of the duration" - sumMonths *= -1; - } - - *aMonths = sumMonths; - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsUtilityService::GetSeconds(const nsAString & aValue, - double * aSeconds) -{ - nsCOMPtr duration; - nsCOMPtr schemaValidator = - do_CreateInstance(NS_SCHEMAVALIDATOR_CONTRACTID); - NS_ENSURE_TRUE(schemaValidator, NS_ERROR_FAILURE); - - nsresult rv = schemaValidator->ValidateBuiltinTypeDuration(aValue, - getter_AddRefs(duration)); - NS_ENSURE_SUCCESS(rv, rv); - double sumSeconds; - PRUint32 days; - PRUint32 hours; - PRUint32 minutes; - PRUint32 seconds; - double fractSecs; - - duration->GetDays(&days); - duration->GetHours(&hours); - duration->GetMinutes(&minutes); - duration->GetSeconds(&seconds); - duration->GetFractionSeconds(&fractSecs); - - sumSeconds = seconds + minutes*60 + hours*3600 + days*24*3600 + fractSecs; - - PRBool negative; - duration->GetNegative(&negative); - if (negative) { - // according to the spec, "the sign of the result will match the sign - // of the duration" - sumSeconds *= -1; - } - - *aSeconds = sumSeconds; - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsUtilityService::GetSecondsFromDateTime(const nsAString & aValue, - double * aSeconds) -{ - PRTime dateTime; - nsCOMPtr schemaValidator = - do_CreateInstance(NS_SCHEMAVALIDATOR_CONTRACTID); - NS_ENSURE_TRUE(schemaValidator, NS_ERROR_FAILURE); - - nsresult rv = schemaValidator->ValidateBuiltinTypeDateTime(aValue, &dateTime); - NS_ENSURE_SUCCESS(rv, rv); - - PRTime secs64 = dateTime, remain64; - PRInt64 usecPerSec; - PRInt32 secs32, remain32; - - // convert from PRTime (microseconds from epoch) to seconds. - LL_I2L(usecPerSec, PR_USEC_PER_SEC); - LL_MOD(remain64, secs64, usecPerSec); /* remainder after conversion */ - LL_DIV(secs64, secs64, usecPerSec); /* Conversion in whole seconds */ - - // convert whole seconds and remainder to PRInt32 - LL_L2I(secs32, secs64); - LL_L2I(remain32, remain64); - - // ready the result to send back to transformiix land now in case there are - // no fractional seconds or we end up having a problem parsing them out. If - // we do, we'll just ignore the fractional seconds. - double totalSeconds = secs32; - *aSeconds = totalSeconds; - - // We're not getting fractional seconds back in the PRTime we get from - // the schemaValidator. We'll have to figure out the fractions from - // the original value. Since ValidateBuiltinTypeDateTime returned - // successful for us to get this far, we know that the value is in - // the proper format. - int findFractionalSeconds = aValue.FindChar('.'); - if (findFractionalSeconds < 0) { - // no fractions of seconds, so we are good to go as we are - return NS_OK; - } - - const nsAString& fraction = Substring(aValue, findFractionalSeconds+1, - aValue.Length()); - - PRBool done = PR_FALSE; - PRUnichar currentChar; - nsCAutoString fractionResult; - nsAString::const_iterator start, end, buffStart; - fraction.BeginReading(start); - fraction.BeginReading(buffStart); - fraction.EndReading(end); - - while ((start != end) && !done) { - currentChar = *start++; - - // Time is usually terminated with Z or followed by a time zone - // (i.e. -05:00). Time can also be terminated by the end of the string, so - // test for that as well. All of this specified at: - // http://www.w3.org/TR/xmlschema-2/#dateTime - if ((currentChar == 'Z') || (currentChar == '+') || (currentChar == '-') || - (start == end)) { - fractionResult.AssignLiteral("0."); - AppendUTF16toUTF8(Substring(buffStart.get(), start.get()-1), - fractionResult); - } else if ((currentChar > '9') || (currentChar < '0')) { - // has to be a numerical character or else abort. This should have been - // caught by the schemavalidator, but it is worth double checking. - done = PR_TRUE; - } - } - - if (fractionResult.IsEmpty()) { - // couldn't successfully parse the fractional seconds, so we'll just return - // without them. - return NS_OK; - } - - // convert the result string that we have to a double and add it to the total - totalSeconds += PR_strtod(fractionResult.get(), nsnull); - *aSeconds = totalSeconds; - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsUtilityService::GetDaysFromDateTime(const nsAString & aValue, - PRInt32 * aDays) -{ - NS_ASSERTION(aDays, "no return buffer for days, we'll crash soon"); - *aDays = 0; - - PRTime date; - nsCOMPtr schemaValidator = - do_CreateInstance(NS_SCHEMAVALIDATOR_CONTRACTID); - NS_ENSURE_TRUE(schemaValidator, NS_ERROR_FAILURE); - - // aValue could be a xsd:date or a xsd:dateTime. If it is a dateTime, we - // should ignore the hours, minutes, and seconds according to 7.10.2 in - // the spec. So search for such things now. If they are there, strip 'em. - int findTime = aValue.FindChar('T'); - - nsAutoString dateString; - dateString.Assign(aValue); - if (findTime >= 0) { - dateString.Assign(Substring(dateString, 0, findTime)); - } - - nsresult rv = schemaValidator->ValidateBuiltinTypeDate(dateString, &date); - NS_ENSURE_SUCCESS(rv, rv); - - PRTime secs64 = date; - PRInt64 usecPerSec; - PRInt32 secs32; - - // convert from PRTime (microseconds from epoch) to seconds. Shouldn't - // have to worry about remainders since input is a date. Smallest value - // is in whole days. - LL_I2L(usecPerSec, PR_USEC_PER_SEC); - LL_DIV(secs64, secs64, usecPerSec); - - // convert whole seconds to PRInt32 - LL_L2I(secs32, secs64); - - // convert whole seconds to days. 86400 seconds in a day. - *aDays = secs32/86400; - - return NS_OK; -} - diff --git a/mozilla/extensions/xforms/nsXFormsUtilityService.h b/mozilla/extensions/xforms/nsXFormsUtilityService.h index caf0d15a8dc..6d3323fa359 100644 --- a/mozilla/extensions/xforms/nsXFormsUtilityService.h +++ b/mozilla/extensions/xforms/nsXFormsUtilityService.h @@ -42,24 +42,4 @@ class nsXFormsUtilityService : public nsIXFormsUtilityService { public: NS_DECL_ISUPPORTS - - // nsIXFormsUtilityService - NS_IMETHOD GetModelFromNode(nsIDOMNode *node, nsIDOMNode **aModel); - - NS_IMETHOD IsNodeAssocWithModel(nsIDOMNode *aNode, nsIDOMNode *aModel, - PRBool *aModelAssocWithNode); - - NS_IMETHOD GetInstanceDocumentRoot(const nsAString& aID, - nsIDOMNode *aModelNode, - nsIDOMNode **aInstanceRoot); - - NS_IMETHOD ValidateString(const nsAString& aValue, const nsAString & aType, - const nsAString& aNamespace, PRBool *aResult); - - NS_IMETHOD GetRepeatIndex(nsIDOMNode *aRepeat, PRInt32 *aIndex); - NS_IMETHOD GetMonths(const nsAString& aValue, PRInt32 *aMonths); - NS_IMETHOD GetSeconds(const nsAString& aValue, double *aSeconds); - NS_IMETHOD GetSecondsFromDateTime(const nsAString& aValue, double *aSeconds); - NS_IMETHOD GetDaysFromDateTime(const nsAString& aValue, PRInt32 *aDays); }; - diff --git a/mozilla/extensions/xforms/nsXFormsUtils.cpp b/mozilla/extensions/xforms/nsXFormsUtils.cpp index e3b74f83d2c..00b5660d148 100644 --- a/mozilla/extensions/xforms/nsXFormsUtils.cpp +++ b/mozilla/extensions/xforms/nsXFormsUtils.cpp @@ -45,9 +45,11 @@ #include "nsIDocument.h" #include "nsINameSpaceManager.h" #include "nsIDOMNodeList.h" -#include "nsIXFormsXPathEvaluator.h" +#include "nsIDOMXPathEvaluator.h" +#include "nsIDOMXPathExpression.h" #include "nsIDOMXPathResult.h" #include "nsIDOMXPathNSResolver.h" +#include "nsIXPathEvaluatorInternal.h" #include "nsIDOMDocument.h" #include "nsIDOMText.h" #include "nsIModelElementPrivate.h" @@ -79,16 +81,20 @@ #include "nsIScriptSecurityManager.h" #include "nsIPermissionManager.h" #include "nsServiceManagerUtils.h" -#include "nsIXFormsUtilityService.h" #include "nsIDOMAttr.h" #include "nsIDOM3Node.h" #include "nsIConsoleService.h" #include "nsIStringBundle.h" +#include "nsIXFormsRepeatElement.h" #include "nsIDOMNSEvent.h" #include "nsIURI.h" #include "nsIPrivateDOMEvent.h" #include "nsIDOMNamedNodeMap.h" #include "nsIParserService.h" +#include "nsISchemaValidator.h" +#include "nsISchemaDuration.h" +#include "nsXFormsSchemaValidator.h" +#include "prdtoa.h" #include "nsIPrefBranch.h" #include "nsIPrefService.h" @@ -418,6 +424,26 @@ nsXFormsUtils::GetModel(nsIDOMElement *aElement, return result; } +/* static */ nsresult +nsXFormsUtils::CreateExpression(nsIXPathEvaluatorInternal *aEvaluator, + const nsAString &aExpression, + nsIDOMXPathNSResolver *aResolver, + nsISupports *aState, + nsIDOMXPathExpression **aResult) +{ + nsStringArray ns; + nsCStringArray contractid; + nsCOMArray state; + + ns.AppendString(EmptyString()); + contractid.AppendCString(NS_LITERAL_CSTRING("@mozilla.org/xforms-xpath-functions;1")); + state.AppendObject(aState); + + nsCOMPtr expression; + return aEvaluator->CreateExpression(aExpression, aResolver, &ns, &contractid, + &state, aResult); +} + /* static */ nsresult nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, nsIDOMNode *aContextNode, @@ -432,13 +458,21 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; - nsCOMPtr eval = - do_CreateInstance("@mozilla.org/dom/xforms-xpath-evaluator;1"); - NS_ENSURE_STATE(eval); + nsCOMPtr doc; + aContextNode->GetOwnerDocument(getter_AddRefs(doc)); + + nsCOMPtr eval = do_QueryInterface(doc); + nsCOMPtr evalInternal = do_QueryInterface(eval); + NS_ENSURE_STATE(eval && evalInternal); + + nsCOMPtr resolver; + nsresult rv = eval->CreateNSResolver(aResolverNode, getter_AddRefs(resolver)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr expression; + rv = CreateExpression(evalInternal, aExpression, resolver, aResolverNode, + getter_AddRefs(expression)); - nsCOMPtr expression; - nsresult rv = eval->CreateExpression(aExpression, aResolverNode, - getter_AddRefs(expression)); PRBool throwException = PR_FALSE; if (!expression) { const nsPromiseFlatString& flat = PromiseFlatString(aExpression); @@ -447,13 +481,17 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, strings, 1, aContextNode, nsnull); throwException = PR_TRUE; } else { + nsCOMPtr nsExpr = + do_QueryInterface(expression, &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr supResult; - rv = expression->EvaluateWithContext(aContextNode, - aContextPosition, - aContextSize, - aResultType, - nsnull, - getter_AddRefs(supResult)); + rv = nsExpr->EvaluateWithContext(aContextNode, + aContextPosition, + aContextSize, + aResultType, + nsnull, + getter_AddRefs(supResult)); if (NS_SUCCEEDED(rv) && supResult) { /// @todo beaufour: This is somewhat "hackish". Hopefully, this will @@ -461,11 +499,11 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, /// @see http://bugzilla.mozilla.org/show_bug.cgi?id=265212 if (aSet) { nsXFormsXPathParser parser; - nsXFormsXPathAnalyzer analyzer(eval, aResolverNode); + nsXFormsXPathAnalyzer analyzer(evalInternal, resolver, aResolverNode); nsAutoPtr xNode(parser.Parse(aExpression)); rv = analyzer.Analyze(aContextNode, xNode, - expression, + nsExpr, &aExpression, aSet, aContextPosition, @@ -481,7 +519,7 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, return NS_OK; } - if (rv == NS_ERROR_XFORMS_CALCUATION_EXCEPTION) { + if (rv == NS_ERROR_XFORMS_CALCULATION_EXCEPTION) { const nsPromiseFlatString& flat = PromiseFlatString(aExpression); const PRUnichar *strings[] = { flat.get() }; nsXFormsUtils::ReportError(NS_LITERAL_STRING("exprEvaluateError"), @@ -493,7 +531,8 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, // Throw xforms-compute-exception if (throwException) { nsCOMPtr resolverElement = do_QueryInterface(aResolverNode); - nsCOMPtr modelPriv = nsXFormsUtils::GetModel(resolverElement); + nsCOMPtr modelPriv = + nsXFormsUtils::GetModel(resolverElement); nsCOMPtr model = do_QueryInterface(modelPriv); DispatchEvent(model, eEvent_ComputeException, nsnull, resolverElement); } @@ -501,6 +540,36 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, return rv; } +/* static */ nsresult +nsXFormsUtils::EvaluateXPath(nsIXPathEvaluatorInternal *aEvaluator, + const nsAString &aExpression, + nsIDOMNode *aContextNode, + nsIDOMXPathNSResolver *aResolver, + nsISupports *aState, + PRUint16 aResultType, + PRInt32 aContextPosition, + PRInt32 aContextSize, + nsIDOMXPathResult *aInResult, + nsIDOMXPathResult **aResult) +{ + nsCOMPtr expression; + nsresult rv = CreateExpression(aEvaluator, aExpression, aResolver, aState, + getter_AddRefs(expression)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr nsExpression = + do_QueryInterface(expression, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr supResult; + rv = nsExpression->EvaluateWithContext(aContextNode, aContextPosition, + aContextSize, aResultType, + aInResult, getter_AddRefs(supResult)); + NS_ENSURE_SUCCESS(rv, rv); + + return CallQueryInterface(supResult, aResult); +} + /* static */ nsresult nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement, PRUint32 aElementFlags, @@ -2233,3 +2302,326 @@ nsXFormsUtils::GetWindowFromDocument(nsIDOMDocument *aDoc, NS_ADDREF(*aWindow = internal); return NS_OK; } + +/* static */ nsresult +nsXFormsUtils::GetModelFromNode(nsIDOMNode *aNode, nsIDOMNode **aModel) +{ + nsCOMPtr element = do_QueryInterface(aNode); + NS_ASSERTION(aModel, "no return buffer, we'll crash soon"); + *aModel = nsnull; + + nsAutoString namespaceURI; + aNode->GetNamespaceURI(namespaceURI); + + // If the node is in the XForms namespace and XTF based, then it should + // be able to be handled by GetModel. Otherwise it is probably an instance + // node in a instance document. + if (!namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr modelPriv = nsXFormsUtils::GetModel(element); + nsCOMPtr modelElement = do_QueryInterface(modelPriv); + if( modelElement ) { + NS_IF_ADDREF(*aModel = modelElement); + } + + // No model found + NS_ENSURE_TRUE(*aModel, NS_ERROR_FAILURE); + + return NS_OK; +} + + +/* static */ PRBool +nsXFormsUtils::IsNodeAssocWithModel(nsIDOMNode *aNode, nsIDOMNode *aModel) +{ + + nsCOMPtr modelNode; + + nsAutoString namespaceURI; + aNode->GetNamespaceURI(namespaceURI); + + // If the node is in the XForms namespace and XTF based, then it should + // be able to be handled by GetModel. Otherwise it is probably an instance + // node in a instance document. + if (namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) { + nsCOMPtr element = do_QueryInterface(aNode); + nsCOMPtr modelPriv = GetModel(element); + modelNode = do_QueryInterface(modelPriv); + } else { + // We are assuming that if the node coming in isn't a proper XForms element, + // then it is an instance element in an instance doc. Now we just have + // to determine if the given model contains this instance document. + nsCOMPtr instNode; + nsresult rv = + nsXFormsUtils::GetInstanceNodeForData(aNode, getter_AddRefs(instNode)); + if (NS_SUCCEEDED(rv) && instNode) { + instNode->GetParentNode(getter_AddRefs(modelNode)); + } + } + + return modelNode && (modelNode == aModel); +} + +/* static */ nsresult +nsXFormsUtils::GetInstanceDocumentRoot(const nsAString &aID, + nsIDOMNode *aModelNode, + nsIDOMNode **aInstanceRoot) +{ + nsresult rv = NS_ERROR_FAILURE; + NS_ASSERTION(aInstanceRoot, "no return buffer, we'll crash soon"); + *aInstanceRoot = nsnull; + + if (aID.IsEmpty()) { + return rv; + } + + nsCOMPtr modelElement = do_QueryInterface(aModelNode); + nsCOMPtr doc; + rv = modelElement->GetInstanceDocument(aID, getter_AddRefs(doc)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr element; + rv = doc->GetDocumentElement(getter_AddRefs(element)); + NS_ENSURE_SUCCESS(rv, rv); + + NS_IF_ADDREF(*aInstanceRoot = element); + + return NS_OK; +} + +/* static */ PRBool +nsXFormsUtils::ValidateString(const nsAString &aValue, const nsAString & aType, + const nsAString & aNamespace) +{ + nsXFormsSchemaValidator validator; + + return validator.ValidateString(aValue, aType, aNamespace); +} + +/* static */ nsresult +nsXFormsUtils::GetRepeatIndex(nsIDOMNode *aRepeat, PRInt32 *aIndex) +{ + NS_ASSERTION(aIndex, "no return buffer for index, we'll crash soon"); + *aIndex = 0; + + nsCOMPtr repeatEle = do_QueryInterface(aRepeat); + if (!repeatEle) { + // if aRepeat isn't a repeat element, then setting aIndex to -1 to tell + // XPath to return NaN. Per 7.8.5 in the spec (1.0, 2nd edition) + *aIndex = -1; + } else { + PRUint32 retIndex = 0; + nsresult rv = repeatEle->GetIndex(&retIndex); + NS_ENSURE_SUCCESS(rv, rv); + + *aIndex = retIndex; + } + + return NS_OK; +} + +/* static */ nsresult +nsXFormsUtils::GetMonths(const nsAString & aValue, PRInt32 * aMonths) +{ + NS_ASSERTION(aMonths, "no return buffer for months, we'll crash soon"); + + *aMonths = 0; + nsCOMPtr duration; + nsCOMPtr schemaValidator = + do_CreateInstance("@mozilla.org/schemavalidator;1"); + NS_ENSURE_TRUE(schemaValidator, NS_ERROR_FAILURE); + + nsresult rv = schemaValidator->ValidateBuiltinTypeDuration(aValue, + getter_AddRefs(duration)); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt32 sumMonths; + PRUint32 years; + PRUint32 months; + + duration->GetYears(&years); + duration->GetMonths(&months); + + sumMonths = months + years*12; + PRBool negative; + duration->GetNegative(&negative); + if (negative) { + // according to the spec, "the sign of the result will match the sign + // of the duration" + sumMonths *= -1; + } + + *aMonths = sumMonths; + + return NS_OK; +} + +/* static */ nsresult +nsXFormsUtils::GetSeconds(const nsAString & aValue, double * aSeconds) +{ + nsCOMPtr duration; + nsCOMPtr schemaValidator = + do_CreateInstance("@mozilla.org/schemavalidator;1"); + NS_ENSURE_TRUE(schemaValidator, NS_ERROR_FAILURE); + + nsresult rv = schemaValidator->ValidateBuiltinTypeDuration(aValue, + getter_AddRefs(duration)); + NS_ENSURE_SUCCESS(rv, rv); + + double sumSeconds; + PRUint32 days; + PRUint32 hours; + PRUint32 minutes; + PRUint32 seconds; + double fractSecs; + + duration->GetDays(&days); + duration->GetHours(&hours); + duration->GetMinutes(&minutes); + duration->GetSeconds(&seconds); + duration->GetFractionSeconds(&fractSecs); + + sumSeconds = seconds + minutes*60 + hours*3600 + days*24*3600 + fractSecs; + + PRBool negative; + duration->GetNegative(&negative); + if (negative) { + // according to the spec, "the sign of the result will match the sign + // of the duration" + sumSeconds *= -1; + } + + *aSeconds = sumSeconds; + return NS_OK; +} + +/* static */ nsresult +nsXFormsUtils::GetSecondsFromDateTime(const nsAString & aValue, + double * aSeconds) +{ + PRTime dateTime; + nsCOMPtr schemaValidator = + do_CreateInstance("@mozilla.org/schemavalidator;1"); + NS_ENSURE_TRUE(schemaValidator, NS_ERROR_FAILURE); + + nsresult rv = schemaValidator->ValidateBuiltinTypeDateTime(aValue, &dateTime); + NS_ENSURE_SUCCESS(rv, rv); + + PRTime secs64 = dateTime, remain64; + PRInt64 usecPerSec; + PRInt32 secs32, remain32; + + // convert from PRTime (microseconds from epoch) to seconds. + LL_I2L(usecPerSec, PR_USEC_PER_SEC); + LL_MOD(remain64, secs64, usecPerSec); /* remainder after conversion */ + LL_DIV(secs64, secs64, usecPerSec); /* Conversion in whole seconds */ + + // convert whole seconds and remainder to PRInt32 + LL_L2I(secs32, secs64); + LL_L2I(remain32, remain64); + + // ready the result to send back to transformiix land now in case there are + // no fractional seconds or we end up having a problem parsing them out. If + // we do, we'll just ignore the fractional seconds. + double totalSeconds = secs32; + *aSeconds = totalSeconds; + + // We're not getting fractional seconds back in the PRTime we get from + // the schemaValidator. We'll have to figure out the fractions from + // the original value. Since ValidateBuiltinTypeDateTime returned + // successful for us to get this far, we know that the value is in + // the proper format. + int findFractionalSeconds = aValue.FindChar('.'); + if (findFractionalSeconds < 0) { + // no fractions of seconds, so we are good to go as we are + return NS_OK; + } + + const nsAString& fraction = Substring(aValue, findFractionalSeconds+1, + aValue.Length()); + + PRBool done = PR_FALSE; + PRUnichar currentChar; + nsCAutoString fractionResult; + nsAString::const_iterator start, end, buffStart; + fraction.BeginReading(start); + fraction.BeginReading(buffStart); + fraction.EndReading(end); + + while ((start != end) && !done) { + currentChar = *start++; + + // Time is usually terminated with Z or followed by a time zone + // (i.e. -05:00). Time can also be terminated by the end of the string, so + // test for that as well. All of this specified at: + // http://www.w3.org/TR/xmlschema-2/#dateTime + if ((currentChar == 'Z') || (currentChar == '+') || (currentChar == '-') || + (start == end)) { + fractionResult.AssignLiteral("0."); + AppendUTF16toUTF8(Substring(buffStart.get(), start.get()-1), + fractionResult); + } else if ((currentChar > '9') || (currentChar < '0')) { + // has to be a numerical character or else abort. This should have been + // caught by the schemavalidator, but it is worth double checking. + done = PR_TRUE; + } + } + + if (fractionResult.IsEmpty()) { + // couldn't successfully parse the fractional seconds, so we'll just return + // without them. + return NS_OK; + } + + // convert the result string that we have to a double and add it to the total + totalSeconds += PR_strtod(fractionResult.get(), nsnull); + *aSeconds = totalSeconds; + + return NS_OK; +} + +/* static */ nsresult +nsXFormsUtils::GetDaysFromDateTime(const nsAString & aValue, PRInt32 * aDays) +{ + NS_ASSERTION(aDays, "no return buffer for days, we'll crash soon"); + *aDays = 0; + + PRTime date; + nsCOMPtr schemaValidator = + do_CreateInstance("@mozilla.org/schemavalidator;1"); + NS_ENSURE_TRUE(schemaValidator, NS_ERROR_FAILURE); + + // aValue could be a xsd:date or a xsd:dateTime. If it is a dateTime, we + // should ignore the hours, minutes, and seconds according to 7.10.2 in + // the spec. So search for such things now. If they are there, strip 'em. + PRInt32 findTime = aValue.FindChar('T'); + + nsAutoString dateString; + dateString.Assign(aValue); + if (findTime >= 0) { + dateString.Assign(Substring(dateString, 0, findTime)); + } + + nsresult rv = schemaValidator->ValidateBuiltinTypeDate(dateString, &date); + NS_ENSURE_SUCCESS(rv, rv); + + PRTime secs64 = date; + PRInt64 usecPerSec; + PRInt32 secs32; + + // convert from PRTime (microseconds from epoch) to seconds. Shouldn't + // have to worry about remainders since input is a date. Smallest value + // is in whole days. + LL_I2L(usecPerSec, PR_USEC_PER_SEC); + LL_DIV(secs64, secs64, usecPerSec); + + // convert whole seconds to PRInt32 + LL_L2I(secs32, secs64); + + // convert whole seconds to days. 86400 seconds in a day. + *aDays = secs32/86400; + + return NS_OK; +} diff --git a/mozilla/extensions/xforms/nsXFormsUtils.h b/mozilla/extensions/xforms/nsXFormsUtils.h index 065ab486f00..c98d50e8844 100644 --- a/mozilla/extensions/xforms/nsXFormsUtils.h +++ b/mozilla/extensions/xforms/nsXFormsUtils.h @@ -57,6 +57,10 @@ class nsIURI; class nsString; class nsIMutableArray; class nsIDOMEvent; +class nsIDOMXPathEvaluator; +class nsIDOMXPathExpression; +class nsIDOMXPathNSResolver; +class nsIXPathEvaluatorInternal; #define NS_NAMESPACE_XFORMS "http://www.w3.org/2002/xforms" #define NS_NAMESPACE_XHTML "http://www.w3.org/1999/xhtml" @@ -66,6 +70,9 @@ class nsIDOMEvent; #define NS_NAMESPACE_SOAP_ENVELOPE "http://schemas.xmlsoap.org/soap/envelope/" #define NS_NAMESPACE_MOZ_XFORMS_LAZY "http://www.mozilla.org/projects/xforms/2005/lazy" +#define NS_ERROR_XFORMS_CALCULATION_EXCEPTION \ + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 3001) + /** * Error codes */ @@ -236,7 +243,7 @@ public: * and returned (addrefed) in |aModel| * * The return value is an XPathResult as returned from - * nsIXFormsXPathEvaluator::Evaluate(). + * nsIDOMXPathEvaluator::Evaluate(). */ static NS_HIDDEN_(nsresult) EvaluateNodeBinding(nsIDOMElement *aElement, @@ -251,10 +258,17 @@ public: nsCOMArray *aDeps = nsnull, nsStringArray *aIndexesUsed = nsnull); + static NS_HIDDEN_(nsresult) + CreateExpression(nsIXPathEvaluatorInternal *aEvaluator, + const nsAString &aExpression, + nsIDOMXPathNSResolver *aResolver, + nsISupports *aState, + nsIDOMXPathExpression **aResult); + /** * Convenience method for doing XPath evaluations. This gets a - * nsIXFormsXPathEvaluator from |aContextNode|'s ownerDocument, and calls - * nsIXFormsXPathEvaluator::Evalute using the given expression, context node, + * nsIDOMXPathEvaluator from |aContextNode|'s ownerDocument, and calls + * nsIDOMXPathEvaluator::Evaluate using the given expression, context node, * namespace resolver, and result type. */ static NS_HIDDEN_(nsresult) @@ -268,6 +282,18 @@ public: nsCOMArray *aSet = nsnull, nsStringArray *aIndexesUsed = nsnull); + static NS_HIDDEN_(nsresult) + EvaluateXPath(nsIXPathEvaluatorInternal *aEvaluator, + const nsAString &aExpression, + nsIDOMNode *aContextNode, + nsIDOMXPathNSResolver *aResolver, + nsISupports *aState, + PRUint16 aResultType, + PRInt32 aContextPosition, + PRInt32 aContextSize, + nsIDOMXPathResult *aInResult, + nsIDOMXPathResult **aResult); + /** * Given a node in the instance data, get its string value according * to section 8.1.1 of the XForms specification. @@ -552,6 +578,63 @@ public: static NS_HIDDEN_(nsresult) GetWindowFromDocument(nsIDOMDocument *aDoc, nsIDOMWindowInternal **aWindow); + /** + * Function to get the corresponding model element from a xforms node or + * a xforms instance data node. + */ + static NS_HIDDEN_(nsresult) GetModelFromNode(nsIDOMNode *aNode, + nsIDOMNode **aResult); + + /** + * Function to see if the given node is associated with the given model. + * Right now this function is only called by XPath in the case of the + * instance() function. + * The provided node can be an instance node from an instance + * document and thus be associated to the model in that way (model elements + * contain instance elements). Otherwise the node will be an XForms element + * that was used as the context node of the XPath expression (i.e the + * XForms control has an attribute that contains an XPath expression). + * Form controls are associated with model elements either explicitly through + * single-node binding or implicitly (if model cannot by calculated, it + * will use the first model element encountered in the document). The model + * can also be inherited from a containing element like xforms:group or + * xforms:repeat. + */ + static NS_HIDDEN_(PRBool) IsNodeAssocWithModel(nsIDOMNode *aNode, + nsIDOMNode *aModel); + + /** + * Function to get the instance document root for the instance element with + * the given id. The instance element must be associated with the given + * model. + */ + static NS_HIDDEN_(nsresult) GetInstanceDocumentRoot(const nsAString &aID, + nsIDOMNode *aModelNode, + nsIDOMNode **aResult); + + /** + * Function to ensure that aValue is of the schema type aType. Will basically + * be a forwarder to the nsISchemaValidator function of the same name. + */ + static NS_HIDDEN_(PRBool) ValidateString(const nsAString &aValue, + const nsAString & aType, + const nsAString & aNamespace); + + static NS_HIDDEN_(nsresult) GetRepeatIndex(nsIDOMNode *aRepeat, + PRInt32 *aIndex); + + static NS_HIDDEN_(nsresult) GetMonths(const nsAString & aValue, + PRInt32 * aMonths); + + static NS_HIDDEN_(nsresult) GetSeconds(const nsAString & aValue, + double * aSeconds); + + static NS_HIDDEN_(nsresult) GetSecondsFromDateTime(const nsAString & aValue, + double * aSeconds); + + static NS_HIDDEN_(nsresult) GetDaysFromDateTime(const nsAString & aValue, + PRInt32 * aDays); + private: /** * Do same origin checks on aBaseDocument and aTestURI. Hosts can be diff --git a/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.cpp b/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.cpp index 04ed9d373a6..992d646bea9 100644 --- a/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.cpp +++ b/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.cpp @@ -45,9 +45,12 @@ //#define DEBUG_XF_ANALYZER #endif -nsXFormsXPathAnalyzer::nsXFormsXPathAnalyzer(nsIXFormsXPathEvaluator *aEvaluator, - nsIDOMNode *aResolver) - : mEvaluator(aEvaluator), mResolver(aResolver) +nsXFormsXPathAnalyzer::nsXFormsXPathAnalyzer(nsIXPathEvaluatorInternal *aEvaluator, + nsIDOMXPathNSResolver *aResolver, + nsISupports *aState) + : mEvaluator(aEvaluator), + mResolver(aResolver), + mState(aState) { MOZ_COUNT_CTOR(nsXFormsXPathAnalyzer); } @@ -174,9 +177,10 @@ nsXFormsXPathAnalyzer::AnalyzeRecursively(nsIDOMNode *aContextNode, xp = Substring(*mCurExprString, aNode->mStartIndex, aNode->mEndIndex - aNode->mStartIndex); } - rv = mEvaluator->Evaluate(xp, aContextNode, mCurPosition, mCurSize, - mResolver, nsIDOMXPathResult::ANY_TYPE, - nsnull, getter_AddRefs(result)); + rv = nsXFormsUtils::EvaluateXPath(mEvaluator, xp, aContextNode, mResolver, + mState, nsIDOMXPathResult::ANY_TYPE, + mCurPosition, mCurSize, nsnull, + getter_AddRefs(result)); if (NS_FAILED(rv)) { const PRUnichar *strings[] = { xp.get() }; nsXFormsUtils::ReportError(NS_LITERAL_STRING("exprEvaluateError"), @@ -194,10 +198,13 @@ nsXFormsXPathAnalyzer::AnalyzeRecursively(nsIDOMNode *aContextNode, nsDependentSubstring indexExpr = Substring(xp, indexSize, xp.Length() - indexSize - 1); // remove final ')' too + nsCOMPtr stringRes; - rv = mEvaluator->Evaluate(indexExpr, aContextNode, mCurPosition, mCurSize, - mResolver, nsIDOMXPathResult::STRING_TYPE, - nsnull, getter_AddRefs(stringRes)); + rv = nsXFormsUtils::EvaluateXPath(mEvaluator, indexExpr, aContextNode, + mResolver, mState, + nsIDOMXPathResult::STRING_TYPE, + mCurPosition, mCurSize, nsnull, + getter_AddRefs(stringRes)); NS_ENSURE_SUCCESS(rv, rv); nsAutoString indexId; diff --git a/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.h b/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.h index b379f63bbf7..b6d0f747859 100644 --- a/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.h +++ b/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.h @@ -42,7 +42,7 @@ #include "nsCOMArray.h" #include "nsXFormsXPathNode.h" #include "nsIDOMNSXPathExpression.h" -#include "nsIXFormsXPathEvaluator.h" +#include "nsIXPathEvaluatorInternal.h" #include "nsIDOMXPathNSResolver.h" #include "nsIDOMNode.h" #include "nsCOMPtr.h" @@ -58,8 +58,9 @@ */ class nsXFormsXPathAnalyzer { private: - nsCOMPtr mEvaluator; - nsCOMPtr mResolver; + nsCOMPtr mEvaluator; + nsCOMPtr mResolver; + nsCOMPtr mState; nsCOMArray *mCurSet; nsCOMPtr mCurExpression; @@ -74,8 +75,9 @@ private: PRBool aCollect = PR_FALSE); public: - nsXFormsXPathAnalyzer(nsIXFormsXPathEvaluator *aEvaluator, - nsIDOMNode *aResolver); + nsXFormsXPathAnalyzer(nsIXPathEvaluatorInternal *aEvaluator, + nsIDOMXPathNSResolver *aResolver, + nsISupports *aState); ~nsXFormsXPathAnalyzer(); nsresult Analyze(nsIDOMNode *aContextNode, diff --git a/mozilla/extensions/xforms/nsXFormsXPathFunctions.cpp b/mozilla/extensions/xforms/nsXFormsXPathFunctions.cpp new file mode 100644 index 00000000000..386712dcec1 --- /dev/null +++ b/mozilla/extensions/xforms/nsXFormsXPathFunctions.cpp @@ -0,0 +1,426 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla XForms support. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Aaron Reed + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsXFormsXPathFunctions.h" +#include "nsAutoPtr.h" +#include "nsComponentManagerUtils.h" +#include "nsIDOMDocument.h" +#include "nsIDOMElement.h" +#include "nsString.h" +#include "nsXFormsUtils.h" +#include "prprf.h" +#include "txDouble.h" +#include "txIFunctionEvaluationContext.h" +#include "txINodeSet.h" +#include "nsIClassInfoImpl.h" + +#define NS_NAMESPACE_XFORMS "http://www.w3.org/2002/xforms" + +static const PRUint32 nanMask[2] = TX_DOUBLE_NaN; +#define kNaN *((double*)nanMask) + +NS_IMPL_ISUPPORTS1_CI(nsXFormsXPathFunctions, nsIXFormsXPathFunctions) + +NS_IMETHODIMP +nsXFormsXPathFunctions::Avg(txINodeSet *aNodeSet, double *aResult) +{ + PRUint32 length; + nsresult rv = aNodeSet->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + + double total = 0; + PRUint32 i; + for (i = 0; i < length; ++i) { + double item; + rv = aNodeSet->ItemAsNumber(i, &item); + NS_ENSURE_SUCCESS(rv, rv); + + if (TX_DOUBLE_IS_NaN(item)) { + // This will make aResult be set to kNaN below. + i = 0; + break; + } + + total += item; + } + + *aResult = (i > 0) ? (total / i) : kNaN; + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::BooleanFromString(const nsAString & aString, + PRBool *aResult) +{ + *aResult = aString.EqualsLiteral("1") || + aString.LowerCaseEqualsLiteral("true"); + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::CountNonEmpty(txINodeSet *aNodeSet, double *aResult) +{ + PRUint32 length; + nsresult rv = aNodeSet->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + + double result = 0; + PRUint32 i; + for (i = 0; i < length; ++i) { + nsAutoString item; + rv = aNodeSet->ItemAsString(i, item); + NS_ENSURE_SUCCESS(rv, rv); + + if (!item.IsEmpty()) { + ++result; + } + } + + *aResult = result; + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::DaysFromDate(const nsAString &aDateTime, + double *aResult) +{ + PRInt32 result = 0; + nsresult rv = nsXFormsUtils::GetDaysFromDateTime(aDateTime, &result); + if (rv == NS_ERROR_ILLEGAL_VALUE) { + *aResult = kNaN; + rv = NS_OK; + } + else { + *aResult = result; + } + + return rv; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::If(PRBool aValue, const nsAString &aIfString, + const nsAString &aElseString, nsAString &aResult) +{ + // XXX Avoid evaluating aIfString and aElseString until after checking + // aValue. Probably needs vararg support. + aResult = aValue ? aIfString : aElseString; + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::Index(txIFunctionEvaluationContext *aContext, + const nsAString &aID, double *aResult) +{ + // Given an element's id as the parameter, need to query the element and + // make sure that it is a xforms:repeat node. Given that, must query + // its index. + + nsCOMPtr state; + aContext->GetState(getter_AddRefs(state)); + nsCOMPtr resolverNode = do_QueryInterface(state); + NS_ENSURE_TRUE(resolverNode, NS_ERROR_FAILURE); + + // here document is the XForms document + nsCOMPtr document; + resolverNode->GetOwnerDocument(getter_AddRefs(document)); + NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); + + // aID should be the id of a nsIXFormsRepeatElement + nsCOMPtr repeatEle; + nsresult rv = document->GetElementById(aID, getter_AddRefs(repeatEle)); + NS_ENSURE_SUCCESS(rv, rv); + + // now get the index value from the xforms:repeat. + PRInt32 index; + rv = nsXFormsUtils::GetRepeatIndex(repeatEle, &index); + NS_ENSURE_SUCCESS(rv, rv); + + // repeat's index is 1-based. If it is 0, then that is still ok since + // repeat's index can be 0 if uninitialized or if the nodeset that it + // is bound to is empty (either initially or due to delete remove all + // of the instance nodes). If index == -1, then repeatEle isn't an + // XForms repeat element, so we need to return NaN per spec. + *aResult = index >= 0 ? index : kNaN; + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::Instance(txIFunctionEvaluationContext *aContext, + const nsAString &aInstanceId, + txINodeSet **aResult) +{ + *aResult = nsnull; + + // The state is the node in the XForms document that contained + // the expression we are evaluating. We'll use this to get the + // document. If this isn't here, then something is wrong. Bail. + nsCOMPtr state; + aContext->GetState(getter_AddRefs(state)); + nsCOMPtr resolverNode = do_QueryInterface(state); + NS_ENSURE_TRUE(resolverNode, NS_ERROR_FAILURE); + + // here document is the XForms document + nsCOMPtr document; + resolverNode->GetOwnerDocument(getter_AddRefs(document)); + NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); + + nsCOMPtr instEle; + nsresult rv = document->GetElementById(aInstanceId, + getter_AddRefs(instEle)); + NS_ENSURE_SUCCESS(rv, rv); + + PRBool foundInstance = PR_FALSE; + if (instEle) { + nsAutoString localname, namespaceURI; + instEle->GetLocalName(localname); + instEle->GetNamespaceURI(namespaceURI); + + foundInstance = localname.EqualsLiteral("instance") && + namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS); + } + + nsCOMPtr result = + do_CreateInstance("@mozilla.org/transformiix-nodeset;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + if (!foundInstance) { + // We didn't find an instance element with the given id. Return the + // empty result set. + result.swap(*aResult); + + return NS_OK; + } + + // Make sure that this element is contained in the same + // model as the context node of the expression as per + // the XForms 1.0 spec. + + // first step is to get the contextNode passed in to + // the evaluation + + nsCOMPtr xfContextNode; + rv = aContext->GetContextNode(getter_AddRefs(xfContextNode)); + NS_ENSURE_SUCCESS(rv, rv); + + // now see if the node we found (instEle) and the + // context node for the evaluation (xfContextNode) link + // back to the same model. + nsCOMPtr instNode, modelInstance; + instNode = do_QueryInterface(instEle); + rv = nsXFormsUtils::GetModelFromNode(instNode, + getter_AddRefs(modelInstance)); + NS_ENSURE_SUCCESS(rv, rv); + + PRBool modelContainsNode = + nsXFormsUtils::IsNodeAssocWithModel(xfContextNode, modelInstance); + + if (modelContainsNode) { + // ok, we've found an instance node with the proper id + // that fulfills the requirement of being from the + // same model as the context node. Now we need to + // return a 'node-set containing just the root + // element node of the referenced instance data'. + // Wonderful. + + nsCOMPtr root; + rv = nsXFormsUtils::GetInstanceDocumentRoot(aInstanceId, + modelInstance, + getter_AddRefs(root)); + NS_ENSURE_SUCCESS(rv, rv); + + if (root) { + result->Add(root); + } + + result.swap(*aResult); + + return NS_OK; + } + + // XXX where we need to do the work + + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::Max(txINodeSet *aNodeSet, double *aResult) +{ + PRUint32 length; + nsresult rv = aNodeSet->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + + double result = kNaN; + PRUint32 i; + for (i = 0; i < length; ++i) { + double item; + rv = aNodeSet->ItemAsNumber(i, &item); + NS_ENSURE_SUCCESS(rv, rv); + + if (!TX_DOUBLE_COMPARE(item, <=, result)) { + result = item; + } + + if (TX_DOUBLE_IS_NaN(result)) { + break; + } + } + + *aResult = result; + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::Min(txINodeSet *aNodeSet, double *aResult) +{ + PRUint32 length; + nsresult rv = aNodeSet->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + + double result = kNaN; + PRUint32 i; + for (i = 0; i < length; ++i) { + double item; + rv = aNodeSet->ItemAsNumber(i, &item); + NS_ENSURE_SUCCESS(rv, rv); + + if (!TX_DOUBLE_COMPARE(item, >=, result)) { + result = item; + } + + if (TX_DOUBLE_IS_NaN(result)) { + break; + } + } + + *aResult = result; + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::Months(const nsAString & aDuration, double *aResult) +{ + PRInt32 result = 0; + nsresult rv = nsXFormsUtils::GetMonths(aDuration, &result); + if (rv == NS_ERROR_ILLEGAL_VALUE) { + *aResult = kNaN; + + return NS_OK; + } + + *aResult = result; + + return rv; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::Now(nsAString & aResult) +{ + PRExplodedTime time; + char ctime[60]; + + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &time); + int gmtoffsethour = time.tm_params.tp_gmt_offset < 0 ? + -1*time.tm_params.tp_gmt_offset / 3600 : + time.tm_params.tp_gmt_offset / 3600; + int remainder = time.tm_params.tp_gmt_offset%3600; + int gmtoffsetminute = remainder ? remainder/60 : 00; + + char zone_location[40]; + const int zoneBufSize = sizeof(zone_location); + PR_snprintf(zone_location, zoneBufSize, "%c%02d:%02d\0", + time.tm_params.tp_gmt_offset < 0 ? '-' : '+', + gmtoffsethour, gmtoffsetminute); + + PR_FormatTime(ctime, sizeof(ctime), "%Y-%m-%dT%H:%M:%S\0", &time); + + aResult.AssignASCII(ctime); + AppendASCIItoUTF16(zone_location, aResult); + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::Property(const nsAString &aProperty, + nsAString &aResult) +{ + // This function can handle "version" and "conformance-level" + // which is all that the XForms 1.0 spec is worried about + if (aProperty.EqualsLiteral("version")) { + aResult.AssignLiteral("1.0"); + } + else if (aProperty.EqualsLiteral("conformance-level")) { + aResult.AssignLiteral("basic"); + } + else { + aResult.Truncate(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::Seconds(const nsAString &aDuration, double *aResult) +{ + nsresult rv = nsXFormsUtils::GetSeconds(aDuration, aResult); + if (rv == NS_ERROR_ILLEGAL_VALUE) { + *aResult = kNaN; + rv = NS_OK; + } + + return rv; +} + +NS_IMETHODIMP +nsXFormsXPathFunctions::SecondsFromDateTime(const nsAString &aDateTime, + double *aResult) +{ + nsresult rv = nsXFormsUtils::GetSecondsFromDateTime(aDateTime, aResult); + if (rv == NS_ERROR_ILLEGAL_VALUE) { + *aResult = kNaN; + rv = NS_OK; + } + + return rv; +} diff --git a/mozilla/content/xslt/src/xpath/txXFormsFunctions.h b/mozilla/extensions/xforms/nsXFormsXPathFunctions.h similarity index 58% rename from mozilla/content/xslt/src/xpath/txXFormsFunctions.h rename to mozilla/extensions/xforms/nsXFormsXPathFunctions.h index 668d3835c39..f1873b40888 100644 --- a/mozilla/content/xslt/src/xpath/txXFormsFunctions.h +++ b/mozilla/extensions/xforms/nsXFormsXPathFunctions.h @@ -36,49 +36,11 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef TRANSFRMX_XFORMS_FUNCTIONS_H -#define TRANSFRMX_XFORMS_FUNCTIONS_H - -#include "txExpr.h" -#include "nsIDOMNode.h" - -#define NS_NAMESPACE_XFORMS "http://www.w3.org/2002/xforms" -#define NS_NAMESPACE_SCHEMA "http://www.w3.org/1999/XMLSchema" - -/* - * Represents the XPath XForms Function Calls - */ -class XFormsFunctionCall : public FunctionCall { +#include "nsIXFormsXPathFunctions.h" +class nsXFormsXPathFunctions : public nsIXFormsXPathFunctions +{ public: - - enum XFormsFunctions { - AVG, // avg() - BOOLEANFROMSTRING, // boolean-from-string() - COUNTNONEMPTY, // count-non-empty() - DAYSFROMDATE, // days-from-date() - IF, // if() - INDEX, // index() - INSTANCE, // instance() - MAX, // max() - MIN, // min() - MONTHS, // months() - NOW, // now() - PROPERTY, // property() - SECONDS, // seconds() - SECONDSFROMDATETIME // seconds-from-dateTime() - }; - - /* - * Creates a Number function of the given type - */ - XFormsFunctionCall(XFormsFunctions aType, nsIDOMNode *resolverNode=nsnull); - - TX_DECL_FUNCTION; - -private: - XFormsFunctions mType; - nsCOMPtr mResolverNode; + NS_DECL_ISUPPORTS + NS_DECL_NSIXFORMSXPATHFUNCTIONS }; - -#endif diff --git a/mozilla/layout/build/nsLayoutModule.cpp b/mozilla/layout/build/nsLayoutModule.cpp index 8fc867ba369..007a6dea000 100644 --- a/mozilla/layout/build/nsLayoutModule.cpp +++ b/mozilla/layout/build/nsLayoutModule.cpp @@ -108,10 +108,9 @@ // Transformiix stuff #include "nsXPathEvaluator.h" #include "txMozillaXSLTProcessor.h" +#include "txNodeSetAdaptor.h" #include "txXSLTProcessor.h" #include "nsXPath1Scheme.h" -#include "nsXFormsXPathEvaluator.h" -#include "txXSLTProcessor.h" #include "nsDOMParser.h" #include "nsDOMSerializer.h" @@ -200,12 +199,19 @@ static void Shutdown(); #define TRANSFORMIIX_XPATH1_SCHEME_CID \ { 0xc351177, 0x159, 0x4500, { 0x86, 0xb0, 0xa2, 0x19, 0xdf, 0xde, 0x42, 0x58 } } +/* 5d5d92cd-6bf8-11d9-bf4a-000a95dc234c */ +#define TRANSFORMIIX_NODESET_CID \ +{ 0x5d5d92cd, 0x6bf8, 0x11d9, { 0xbf, 0x4a, 0x0, 0x0a, 0x95, 0xdc, 0x23, 0x4c } } + +#define TRANSFORMIIX_NODESET_CONTRACTID \ +"@mozilla.org/transformiix-nodeset;1" + NS_GENERIC_FACTORY_CONSTRUCTOR(nsXPath1SchemeProcessor) // Factory Constructor NS_GENERIC_FACTORY_CONSTRUCTOR(txMozillaXSLTProcessor) NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(nsXPathEvaluator, Init) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsXFormsXPathEvaluator) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(txNodeSetAdaptor, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMSerializer) NS_GENERIC_FACTORY_CONSTRUCTOR(nsXMLHttpRequest) NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMParser) @@ -1253,16 +1259,16 @@ static const nsModuleComponentInfo gComponents[] = { NS_XPATH_EVALUATOR_CONTRACTID, nsXPathEvaluatorConstructor }, - { "XFormsXPathEvaluator", - TRANSFORMIIX_XFORMS_XPATH_EVALUATOR_CID, - NS_XFORMS_XPATH_EVALUATOR_CONTRACTID, - nsXFormsXPathEvaluatorConstructor }, - { "XPath1 XPointer Scheme Processor", TRANSFORMIIX_XPATH1_SCHEME_CID, NS_XPOINTER_SCHEME_PROCESSOR_BASE "xpath1", nsXPath1SchemeProcessorConstructor }, + { "Transformiix NodeSet", + TRANSFORMIIX_NODESET_CID, + TRANSFORMIIX_NODESET_CONTRACTID, + txNodeSetAdaptorConstructor }, + { "XML Serializer", NS_XMLSERIALIZER_CID, NS_XMLSERIALIZER_CONTRACTID,