diff --git a/mozilla/content/xslt/src/base/txList.cpp b/mozilla/content/xslt/src/base/txList.cpp index fb965582945..bf7d67f3828 100644 --- a/mozilla/content/xslt/src/base/txList.cpp +++ b/mozilla/content/xslt/src/base/txList.cpp @@ -231,6 +231,26 @@ void txList::clear() itemCount = 0; } +void* +txList::replace(PRUint32 aIndex, void* aObjPtr) +{ + PRUint32 i = 0; + ListItem* item = firstItem; + while (i < aIndex && item) { + item = item->nextItem; + ++i; + } + + if (!item) { + return nsnull; + } + + void* oldObj = item->objPtr; + item->objPtr = aObjPtr; + + return oldObj; +} + //------------------------------------/ //- Implementation of txListIterator -/ //------------------------------------/ diff --git a/mozilla/content/xslt/src/base/txList.h b/mozilla/content/xslt/src/base/txList.h index 8b7fba13491..d506aa17c7e 100644 --- a/mozilla/content/xslt/src/base/txList.h +++ b/mozilla/content/xslt/src/base/txList.h @@ -74,6 +74,14 @@ public: **/ PRInt32 getLength(); + /** + * Returns true if there are no items in this txList + */ + inline PRBool isEmpty() + { + return itemCount == 0; + } + /** * Adds the given Object to the specified position in the list **/ @@ -94,6 +102,14 @@ public: */ void clear(); + /** + * Replaces the Object at the given index with a new Object. + * If the given index is outside the list null is returned. + * @param aIndex index of Object to replace. + * @param aObjPtr new Object to put in the list. + * @return the old Object pointer + */ + void* replace(PRUint32 aIndex, void* aObjPtr); protected: diff --git a/mozilla/content/xslt/src/xpath/Makefile.in b/mozilla/content/xslt/src/xpath/Makefile.in index 65fd43aa36c..d8cf293b168 100644 --- a/mozilla/content/xslt/src/xpath/Makefile.in +++ b/mozilla/content/xslt/src/xpath/Makefile.in @@ -78,6 +78,7 @@ CPPSRCS = txAdditiveExpr.cpp \ txNumberFunctionCall.cpp \ txNumberResult.cpp \ txPathExpr.cpp \ + txPredicatedNodeTest.cpp \ txPredicateList.cpp \ txRelationalExpr.cpp \ txRootExpr.cpp \ @@ -86,6 +87,7 @@ CPPSRCS = txAdditiveExpr.cpp \ txErrorExpr.cpp \ txLiteralExpr.cpp \ txNameTest.cpp \ + txNamedAttributeStep.cpp \ txNodeSet.cpp \ txNodeTypeTest.cpp \ txForwardContext.cpp \ @@ -93,7 +95,8 @@ CPPSRCS = txAdditiveExpr.cpp \ txResultRecycler.cpp \ txUnionExpr.cpp \ txUnaryExpr.cpp \ - txVariableRefExpr.cpp + txVariableRefExpr.cpp \ + txXPathOptimizer.cpp ifndef MOZ_XSLT_STANDALONE CPPSRCS += nsXPathEvaluator.cpp \ nsXPathExpression.cpp \ diff --git a/mozilla/content/xslt/src/xpath/txAdditiveExpr.cpp b/mozilla/content/xslt/src/xpath/txAdditiveExpr.cpp index 0000579d404..030231a7189 100644 --- a/mozilla/content/xslt/src/xpath/txAdditiveExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txAdditiveExpr.cpp @@ -83,6 +83,15 @@ AdditiveExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return aContext->recycler()->getNumberResult(result, aResult); } //-- evaluate +TX_IMPL_EXPR_STUBS_2(AdditiveExpr, NUMBER_RESULT, leftExpr, rightExpr) + +PRBool +AdditiveExpr::isSensitiveTo(ContextSensitivity aContext) +{ + return leftExpr->isSensitiveTo(aContext) || + rightExpr->isSensitiveTo(aContext); +} + #ifdef TX_TO_STRING void AdditiveExpr::toString(nsAString& str) @@ -103,4 +112,3 @@ AdditiveExpr::toString(nsAString& str) } #endif - diff --git a/mozilla/content/xslt/src/xpath/txBooleanExpr.cpp b/mozilla/content/xslt/src/xpath/txBooleanExpr.cpp index ea6908a6bde..bf5d211f389 100644 --- a/mozilla/content/xslt/src/xpath/txBooleanExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txBooleanExpr.cpp @@ -85,6 +85,15 @@ BooleanExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_OK; } //-- evaluate +TX_IMPL_EXPR_STUBS_2(BooleanExpr, BOOLEAN_RESULT, leftExpr, rightExpr) + +PRBool +BooleanExpr::isSensitiveTo(ContextSensitivity aContext) +{ + return leftExpr->isSensitiveTo(aContext) || + rightExpr->isSensitiveTo(aContext); +} + #ifdef TX_TO_STRING void BooleanExpr::toString(nsAString& str) diff --git a/mozilla/content/xslt/src/xpath/txBooleanFunctionCall.cpp b/mozilla/content/xslt/src/xpath/txBooleanFunctionCall.cpp index 33ea13df6de..f648a0b5336 100644 --- a/mozilla/content/xslt/src/xpath/txBooleanFunctionCall.cpp +++ b/mozilla/content/xslt/src/xpath/txBooleanFunctionCall.cpp @@ -143,6 +143,19 @@ BooleanFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_ERROR_UNEXPECTED; } +Expr::ResultType +BooleanFunctionCall::getReturnType() +{ + return BOOLEAN_RESULT; +} + +PRBool +BooleanFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + return argsSensitiveTo(aContext) || + (mType == TX_LANG && (aContext & NODE_CONTEXT)); +} + #ifdef TX_TO_STRING nsresult BooleanFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xpath/txErrorExpr.cpp b/mozilla/content/xslt/src/xpath/txErrorExpr.cpp index 54a5f593361..c64f84e7206 100755 --- a/mozilla/content/xslt/src/xpath/txErrorExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txErrorExpr.cpp @@ -57,6 +57,16 @@ txErrorExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_ERROR_XPATH_INVALID_EXPRESSION_EVALUATED; } +TX_IMPL_EXPR_STUBS_0(txErrorExpr, ANY_RESULT) + +PRBool +txErrorExpr::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 void txErrorExpr::toString(nsAString& aStr) diff --git a/mozilla/content/xslt/src/xpath/txExpr.h b/mozilla/content/xslt/src/xpath/txExpr.h index 7aea1524c3f..7ad1dc2cd92 100644 --- a/mozilla/content/xslt/src/xpath/txExpr.h +++ b/mozilla/content/xslt/src/xpath/txExpr.h @@ -87,6 +87,69 @@ public: virtual nsresult evaluate(txIEvalContext* aContext, txAExprResult** aResult) = 0; + + /** + * Returns the type of this expression. + */ + enum ExprType { + LOCATIONSTEP_ATTRIBUTE_EXPR, + LOCATIONSTEP_OTHER_EXPR, + OTHER_EXPR + }; + virtual ExprType getType() + { + return OTHER_EXPR; + } + + /** + * Returns the type or types of results this Expr return. + */ + typedef PRUint16 ResultType; + enum { + NODESET_RESULT = 0x01, + BOOLEAN_RESULT = 0x02, + NUMBER_RESULT = 0x04, + STRING_RESULT = 0x08, + RTF_RESULT = 0x10, + ANY_RESULT = 0xFFFF + }; + virtual ResultType getReturnType() = 0; + PRBool canReturnType(ResultType aType) + { + return (getReturnType() & aType) != 0; + } + + typedef PRUint16 ContextSensitivity; + enum { + NO_CONTEXT = 0x00, + DOCUMENT_CONTEXT = 0x01, + NODE_ONLY_CONTEXT = 0x02, + NODE_CONTEXT = DOCUMENT_CONTEXT | NODE_ONLY_CONTEXT, + POSITION_CONTEXT = 0x04, + SIZE_CONTEXT = 0x08, + NODESET_CONTEXT = POSITION_CONTEXT | SIZE_CONTEXT, + VARIABLES_CONTEXT = 0x10, + PRIVATE_CONTEXT = 0x20, + ANY_CONTEXT = 0xFFFF + }; + + /** + * Returns true if this expression is sensitive to *any* of + * the requested contexts in aContexts. + */ + virtual PRBool isSensitiveTo(ContextSensitivity aContexts) = 0; + + /** + * Returns sub-expression at given position + */ + virtual Expr* getSubExprAt(PRUint32 aPos) = 0; + + /** + * Replace sub-expression at given position. Does not delete the old + * expression, that is the responsibility of the caller. + */ + virtual void setSubExprAt(PRUint32 aPos, Expr* aExpr) = 0; + #ifdef TX_TO_STRING /** * Returns the String representation of this Expr. @@ -100,21 +163,118 @@ public: #endif }; //-- Expr -#define TX_DECL_EVALUATE \ - nsresult evaluate(txIEvalContext* aContext, txAExprResult** aResult) - -#ifndef TX_TO_STRING -#define TX_DECL_EXPR TX_DECL_EVALUATE -#define TX_DECL_FUNCTION TX_DECL_EVALUATE +#ifdef TX_TO_STRING +#define TX_DECL_TOSTRING \ + void toString(nsAString& aDest); +#define TX_DECL_GETNAMEATOM \ + nsresult getNameAtom(nsIAtom** aAtom); #else +#define TX_DECL_TOSTRING +#define TX_DECL_GETNAMEATOM +#endif + +#define TX_DECL_EXPR_BASE \ + nsresult evaluate(txIEvalContext* aContext, txAExprResult** aResult); \ + ResultType getReturnType(); \ + PRBool isSensitiveTo(ContextSensitivity aContexts) + #define TX_DECL_EXPR \ - TX_DECL_EVALUATE; \ - void toString(nsAString& aDest) + TX_DECL_EXPR_BASE; \ + TX_DECL_TOSTRING \ + Expr* getSubExprAt(PRUint32 aPos); \ + void setSubExprAt(PRUint32 aPos, Expr* aExpr) + +#define TX_DECL_OPTIMIZABLE_EXPR \ + TX_DECL_EXPR; \ + ExprType getType() + #define TX_DECL_FUNCTION \ - TX_DECL_EVALUATE; \ - nsresult getNameAtom(nsIAtom** aAtom) -#endif + TX_DECL_GETNAMEATOM \ + TX_DECL_EXPR_BASE + +#define TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \ +Expr::ResultType \ +_class::getReturnType() \ +{ \ + return _ReturnType; \ +} + +#define TX_IMPL_EXPR_STUBS_0(_class, _ReturnType) \ +TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \ +Expr* \ +_class::getSubExprAt(PRUint32 aPos) \ +{ \ + return nsnull; \ +} \ +void \ +_class::setSubExprAt(PRUint32 aPos, Expr* aExpr) \ +{ \ + NS_NOTREACHED("setting bad subexpression index"); \ +} + +#define TX_IMPL_EXPR_STUBS_1(_class, _ReturnType, _Expr1) \ +TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \ +Expr* \ +_class::getSubExprAt(PRUint32 aPos) \ +{ \ + if (aPos == 0) { \ + return _Expr1; \ + } \ + return nsnull; \ +} \ +void \ +_class::setSubExprAt(PRUint32 aPos, Expr* aExpr) \ +{ \ + NS_ASSERTION(aPos < 1, "setting bad subexpression index");\ + _Expr1.forget(); \ + _Expr1 = aExpr; \ +} + +#define TX_IMPL_EXPR_STUBS_2(_class, _ReturnType, _Expr1, _Expr2) \ +TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \ +Expr* \ +_class::getSubExprAt(PRUint32 aPos) \ +{ \ + switch(aPos) { \ + case 0: \ + return _Expr1; \ + case 1: \ + return _Expr2; \ + default: \ + break; \ + } \ + return nsnull; \ +} \ +void \ +_class::setSubExprAt(PRUint32 aPos, Expr* aExpr) \ +{ \ + NS_ASSERTION(aPos < 2, "setting bad subexpression index");\ + if (aPos == 0) { \ + _Expr1.forget(); \ + _Expr1 = aExpr; \ + } \ + else { \ + _Expr2.forget(); \ + _Expr2 = aExpr; \ + } \ +} + +#define TX_IMPL_EXPR_STUBS_LIST(_class, _ReturnType, _ExprList) \ +TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \ +Expr* \ +_class::getSubExprAt(PRUint32 aPos) \ +{ \ + return NS_STATIC_CAST(Expr*, _ExprList.get(aPos)); \ +} \ +void \ +_class::setSubExprAt(PRUint32 aPos, Expr* aExpr) \ +{ \ + NS_ASSERTION(aPos < (PRUint32)_ExprList.getLength(), \ + "setting bad subexpression index"); \ + _ExprList.replace(aPos, aExpr); \ +} + /** * This class represents a FunctionCall as defined by the XPath 1.0 @@ -149,9 +309,9 @@ public: PRInt32 aParamCountMax, txIEvalContext* aContext); -#ifdef TX_TO_STRING - void toString(nsAString& aDest); -#endif + TX_DECL_TOSTRING + Expr* getSubExprAt(PRUint32 aPos); + void setSubExprAt(PRUint32 aPos, Expr* aExpr); protected: @@ -183,6 +343,12 @@ protected: nsresult evaluateToNodeSet(Expr* aExpr, txIEvalContext* aContext, txNodeSet** aResult); + /** + * Returns true if any argument is sensitive to the given context. + */ + PRBool argsSensitiveTo(ContextSensitivity aContexts); + + #ifdef TX_TO_STRING /* * Returns the name of the function as an atom. @@ -232,22 +398,34 @@ public: txIMatchContext* aContext) = 0; virtual double getDefaultPriority() = 0; + /** + * Returns the type of this nodetest. + */ + enum NodeTestType { + NAME_TEST, + OTHER_TEST + }; + virtual NodeTestType getType() + { + return OTHER_TEST; + } + + /** + * Returns true if this expression is sensitive to *any* of + * the requested flags. + */ + virtual PRBool isSensitiveTo(Expr::ContextSensitivity aContext) = 0; + #ifdef TX_TO_STRING virtual void toString(nsAString& aDest) = 0; #endif }; -#define TX_DECL_NODE_TEST_BASE \ - PRBool matches(const txXPathNode& aNode, txIMatchContext* aContext); \ - double getDefaultPriority() - -#ifndef TX_TO_STRING -#define TX_DECL_NODE_TEST TX_DECL_NODE_TEST_BASE -#else #define TX_DECL_NODE_TEST \ - TX_DECL_NODE_TEST_BASE; \ - void toString(nsAString& aDest) -#endif + TX_DECL_TOSTRING \ + PRBool matches(const txXPathNode& aNode, txIMatchContext* aContext); \ + double getDefaultPriority(); \ + PRBool isSensitiveTo(Expr::ContextSensitivity aContext); /* * This class represents a NameTest as defined by the XPath spec @@ -262,14 +440,14 @@ public: txNameTest(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID, PRUint16 aNodeType); - ~txNameTest(); + NodeTestType getType(); TX_DECL_NODE_TEST; -private: nsCOMPtr mPrefix; nsCOMPtr mLocalName; PRInt32 mNamespace; +private: PRUint16 mNodeType; }; @@ -291,8 +469,6 @@ public: */ txNodeTypeTest(NodeType aNodeType); - ~txNodeTypeTest(); - /* * Sets the name of the node to match. Only availible for pi nodes */ @@ -305,6 +481,21 @@ private: nsCOMPtr mNodeName; }; +/** + * Class representing a nodetest combined with a predicate. May only be used + * if the predicate is not sensitive to the context-nodelist. + */ +class txPredicatedNodeTest : public txNodeTest +{ +public: + txPredicatedNodeTest(txNodeTest* aNodeTest, Expr* aPredicate); + TX_DECL_NODE_TEST; + +private: + nsAutoPtr mNodeTest; + nsAutoPtr mPredicate; +}; + /** * Represents an ordered list of Predicates, * for use with Step and Filter Expressions @@ -334,6 +525,11 @@ public: nsresult evaluatePredicates(txNodeSet* aNodes, txIMatchContext* aContext); + /** + * Drops the first predicate without deleting it. + */ + void dropFirst(); + /** * returns true if this predicate list is empty **/ @@ -352,6 +548,10 @@ public: #endif protected: + PRBool isSensitiveTo(Expr::ContextSensitivity aContext); + Expr* getSubExprAt(PRUint32 aPos); + void setSubExprAt(PRUint32 aPos, Expr* aExpr); + //-- list of predicates List predicates; }; //-- PredicateList @@ -388,7 +588,17 @@ public: { } - TX_DECL_EXPR; + TX_DECL_OPTIMIZABLE_EXPR; + + txNodeTest* getNodeTest() + { + return mNodeTest; + } + void setNodeTest(txNodeTest* aNodeTest) + { + mNodeTest.forget(); + mNodeTest = aNodeTest; + } private: void fromDescendants(const txXPathNode& aNode, txIMatchContext* aCs, @@ -588,7 +798,6 @@ class VariableRefExpr : public Expr { public: VariableRefExpr(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID); - ~VariableRefExpr(); TX_DECL_EXPR; @@ -717,6 +926,24 @@ private: }; //-- UnionExpr +/** + * Class specializing in executing expressions like "@foo" where we are + * interested in different result-types, and expressions like "@foo = 'hi'" + */ +class txNamedAttributeStep : public Expr +{ +public: + txNamedAttributeStep(PRInt32 aNsID, nsIAtom* aPrefix, + nsIAtom* aLocalName); + + TX_DECL_EXPR; + +private: + PRInt32 mNamespace; + nsCOMPtr mPrefix; + nsCOMPtr mLocalName; +}; + /** * Expression that failed to parse */ diff --git a/mozilla/content/xslt/src/xpath/txExprParser.cpp b/mozilla/content/xslt/src/xpath/txExprParser.cpp index cbd369e0e9f..d1f8744449b 100644 --- a/mozilla/content/xslt/src/xpath/txExprParser.cpp +++ b/mozilla/content/xslt/src/xpath/txExprParser.cpp @@ -51,6 +51,7 @@ #include "txIXPathContext.h" #include "txStringUtils.h" #include "txXPathNode.h" +#include "txXPathOptimizer.h" /** * Creates an Attribute Value Template using the given value @@ -193,10 +194,9 @@ txExprParser::createExprInternal(const nsSubstring& aExpression, aContext->SetErrorOffset(lexer.mPosition - start + aSubStringPos); return rv; } - rv = createExpr(lexer, aContext, aExpr); + nsAutoPtr expr; + rv = createExpr(lexer, aContext, getter_Transfers(expr)); if (NS_SUCCEEDED(rv) && lexer.peek()->mType != Token::END) { - delete *aExpr; - *aExpr = nsnull; rv = NS_ERROR_XPATH_BINARY_EXPECTED; } if (NS_FAILED(rv)) { @@ -204,7 +204,15 @@ txExprParser::createExprInternal(const nsSubstring& aExpression, aExpression.BeginReading(start); aContext->SetErrorOffset(lexer.peek()->mStart - start + aSubStringPos); } - return rv; + + txXPathOptimizer optimizer; + Expr* newExpr = nsnull; + rv = optimizer.optimize(expr, &newExpr); + NS_ENSURE_SUCCESS(rv, rv); + + *aExpr = newExpr ? newExpr : expr.forget(); + + return NS_OK; } /** diff --git a/mozilla/content/xslt/src/xpath/txExprResult.h b/mozilla/content/xslt/src/xpath/txExprResult.h index 82f1cbb40ad..c68b9f4de9f 100644 --- a/mozilla/content/xslt/src/xpath/txExprResult.h +++ b/mozilla/content/xslt/src/xpath/txExprResult.h @@ -58,8 +58,10 @@ class txAExprResult : public TxObject { public: friend class txResultRecycler; + + // Update txLiteralExpr::getReturnType if this enum is changed. enum ResultType { - NODESET, + NODESET = 0, BOOLEAN, NUMBER, STRING, diff --git a/mozilla/content/xslt/src/xpath/txFilterExpr.cpp b/mozilla/content/xslt/src/xpath/txFilterExpr.cpp index 3dd213ac280..65d2fe2d9df 100644 --- a/mozilla/content/xslt/src/xpath/txFilterExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txFilterExpr.cpp @@ -86,6 +86,36 @@ FilterExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_OK; } //-- evaluate +TX_IMPL_EXPR_STUBS_BASE(FilterExpr, NODESET_RESULT) + +Expr* +FilterExpr::getSubExprAt(PRUint32 aPos) +{ + if (aPos == 0) { + return expr; + } + return PredicateList::getSubExprAt(aPos - 1); +} + +void +FilterExpr::setSubExprAt(PRUint32 aPos, Expr* aExpr) +{ + if (aPos == 0) { + expr.forget(); + expr = aExpr; + } + else { + PredicateList::setSubExprAt(aPos - 1, aExpr); + } +} + +PRBool +FilterExpr::isSensitiveTo(ContextSensitivity aContext) +{ + return expr->isSensitiveTo(aContext) || + PredicateList::isSensitiveTo(aContext); +} + #ifdef TX_TO_STRING void FilterExpr::toString(nsAString& str) diff --git a/mozilla/content/xslt/src/xpath/txFunctionCall.cpp b/mozilla/content/xslt/src/xpath/txFunctionCall.cpp index 94ffd0841da..31e42197aec 100644 --- a/mozilla/content/xslt/src/xpath/txFunctionCall.cpp +++ b/mozilla/content/xslt/src/xpath/txFunctionCall.cpp @@ -171,6 +171,33 @@ PRBool FunctionCall::requireParams(PRInt32 aParamCountMin, return PR_TRUE; } +Expr* +FunctionCall::getSubExprAt(PRUint32 aPos) +{ + return NS_STATIC_CAST(Expr*, params.get(aPos)); +} + +void +FunctionCall::setSubExprAt(PRUint32 aPos, Expr* aExpr) +{ + NS_ASSERTION(aPos < (PRUint32)params.getLength(), + "setting bad subexpression index"); + params.replace(aPos, aExpr); +} + +PRBool +FunctionCall::argsSensitiveTo(ContextSensitivity aContext) +{ + txListIterator iter(¶ms); + while (iter.hasNext()) { + if (NS_STATIC_CAST(Expr*, iter.next())->isSensitiveTo(aContext)) { + return PR_TRUE; + } + } + + return PR_FALSE; +} + #ifdef TX_TO_STRING void FunctionCall::toString(nsAString& aDest) diff --git a/mozilla/content/xslt/src/xpath/txLiteralExpr.cpp b/mozilla/content/xslt/src/xpath/txLiteralExpr.cpp index e444ff2d1e6..c2b1f710bdd 100644 --- a/mozilla/content/xslt/src/xpath/txLiteralExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txLiteralExpr.cpp @@ -60,6 +60,38 @@ txLiteralExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_OK; } +static Expr::ResultType resultTypes[] = +{ + Expr::NODESET_RESULT, // NODESET + Expr::BOOLEAN_RESULT, // BOOLEAN + Expr::NUMBER_RESULT, // NUMBER + Expr::STRING_RESULT, // STRING + Expr::RTF_RESULT // RESULT_TREE_FRAGMENT +}; + +Expr::ResultType +txLiteralExpr::getReturnType() +{ + return resultTypes[mValue->getResultType()]; +} + +Expr* +txLiteralExpr::getSubExprAt(PRUint32 aPos) +{ + return nsnull; +} +void +txLiteralExpr::setSubExprAt(PRUint32 aPos, Expr* aExpr) +{ + NS_NOTREACHED("setting bad subexpression index"); +} + +PRBool +txLiteralExpr::isSensitiveTo(ContextSensitivity aContext) +{ + return PR_FALSE; +} + #ifdef TX_TO_STRING void txLiteralExpr::toString(nsAString& aStr) diff --git a/mozilla/content/xslt/src/xpath/txLocationStep.cpp b/mozilla/content/xslt/src/xpath/txLocationStep.cpp index a5f5bb6450f..82a33f12d0f 100644 --- a/mozilla/content/xslt/src/xpath/txLocationStep.cpp +++ b/mozilla/content/xslt/src/xpath/txLocationStep.cpp @@ -276,6 +276,37 @@ void LocationStep::fromDescendantsRev(const txXPathNode& aNode, } while (walker.moveToPreviousSibling()); } +Expr::ExprType +LocationStep::getType() +{ + return mAxisIdentifier == ATTRIBUTE_AXIS ? + LOCATIONSTEP_ATTRIBUTE_EXPR : + LOCATIONSTEP_OTHER_EXPR; +} + + +TX_IMPL_EXPR_STUBS_BASE(LocationStep, NODESET_RESULT) + +Expr* +LocationStep::getSubExprAt(PRUint32 aPos) +{ + return PredicateList::getSubExprAt(aPos); +} + +void +LocationStep::setSubExprAt(PRUint32 aPos, Expr* aExpr) +{ + return PredicateList::setSubExprAt(aPos, aExpr); +} + +PRBool +LocationStep::isSensitiveTo(ContextSensitivity aContext) +{ + return (aContext & NODE_CONTEXT) || + mNodeTest->isSensitiveTo(aContext) || + PredicateList::isSensitiveTo(aContext); +} + #ifdef TX_TO_STRING void LocationStep::toString(nsAString& str) diff --git a/mozilla/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp b/mozilla/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp index 812755cdb0a..6fbeb797f58 100644 --- a/mozilla/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp +++ b/mozilla/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp @@ -151,6 +151,25 @@ txXPathTreeWalker::moveToValidAttribute(PRUint32 aStartIndex) return PR_FALSE; } +PRBool +txXPathTreeWalker::moveToNamedAttribute(nsIAtom* aLocalName, PRInt32 aNSID) +{ + if (!mPosition.isContent()) { + return PR_FALSE; + } + + const nsAttrName* name; + PRUint32 i; + for (i = 0; (name = mPosition.mContent->GetAttrNameAt(i)); ++i) { + if (name->Equals(aLocalName, aNSID)) { + mPosition.mIndex = i; + + return PR_TRUE; + } + } + return PR_FALSE; +} + PRBool txXPathTreeWalker::moveToFirstChild() { diff --git a/mozilla/content/xslt/src/xpath/txMultiplicativeExpr.cpp b/mozilla/content/xslt/src/xpath/txMultiplicativeExpr.cpp index ae89b1ed270..0e717af612c 100644 --- a/mozilla/content/xslt/src/xpath/txMultiplicativeExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txMultiplicativeExpr.cpp @@ -114,6 +114,15 @@ MultiplicativeExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return aContext->recycler()->getNumberResult(result, aResult); } //-- evaluate +TX_IMPL_EXPR_STUBS_2(MultiplicativeExpr, NUMBER_RESULT, leftExpr, rightExpr) + +PRBool +MultiplicativeExpr::isSensitiveTo(ContextSensitivity aContext) +{ + return leftExpr->isSensitiveTo(aContext) || + rightExpr->isSensitiveTo(aContext); +} + #ifdef TX_TO_STRING void MultiplicativeExpr::toString(nsAString& str) diff --git a/mozilla/content/xslt/src/xpath/txNameTest.cpp b/mozilla/content/xslt/src/xpath/txNameTest.cpp index baa3c24c39a..26671504daf 100644 --- a/mozilla/content/xslt/src/xpath/txNameTest.cpp +++ b/mozilla/content/xslt/src/xpath/txNameTest.cpp @@ -56,10 +56,6 @@ txNameTest::txNameTest(nsIAtom* aPrefix, nsIAtom* aLocalName, PRInt32 aNSID, "Go fix txNameTest::matches"); } -txNameTest::~txNameTest() -{ -} - PRBool txNameTest::matches(const txXPathNode& aNode, txIMatchContext* aContext) { if ((mNodeType == txXPathNodeType::ELEMENT_NODE && @@ -100,6 +96,18 @@ double txNameTest::getDefaultPriority() return 0; } +txNodeTest::NodeTestType +txNameTest::getType() +{ + return NAME_TEST; +} + +PRBool +txNameTest::isSensitiveTo(Expr::ContextSensitivity aContext) +{ + return !!(aContext & Expr::NODE_CONTEXT); +} + #ifdef TX_TO_STRING void txNameTest::toString(nsAString& aDest) diff --git a/mozilla/content/xslt/src/xpath/txNamedAttributeStep.cpp b/mozilla/content/xslt/src/xpath/txNamedAttributeStep.cpp new file mode 100755 index 00000000000..ec1c7d8d80d --- /dev/null +++ b/mozilla/content/xslt/src/xpath/txNamedAttributeStep.cpp @@ -0,0 +1,96 @@ +/* -*- 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 TransforMiiX XSLT processor. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corporation + * + * 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 "nsIAtom.h" +#include "txIXPathContext.h" +#include "txNodeSet.h" +#include "txExpr.h" + +txNamedAttributeStep::txNamedAttributeStep(PRInt32 aNsID, + nsIAtom* aPrefix, + nsIAtom* aLocalName) + : mNamespace(aNsID), + mPrefix(aPrefix), + mLocalName(aLocalName) +{ +} + +nsresult +txNamedAttributeStep::evaluate(txIEvalContext* aContext, + txAExprResult** aResult) +{ + *aResult = nsnull; + + nsRefPtr nodes; + nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes)); + NS_ENSURE_SUCCESS(rv, rv); + + txXPathTreeWalker walker(aContext->getContextNode()); + if (walker.moveToNamedAttribute(mLocalName, mNamespace)) { + rv = nodes->append(walker.getCurrentPosition()); + NS_ENSURE_SUCCESS(rv, rv); + } + NS_ADDREF(*aResult = nodes); + + return NS_OK; +} + +TX_IMPL_EXPR_STUBS_0(txNamedAttributeStep, NODESET_RESULT); + +PRBool +txNamedAttributeStep::isSensitiveTo(ContextSensitivity aContext) +{ + return !!(aContext & NODE_CONTEXT); +} + +#ifdef TX_TO_STRING +void +txNamedAttributeStep::toString(nsAString& aDest) +{ + aDest.Append(PRUnichar('@')); + if (mPrefix) { + nsAutoString prefix; + mPrefix->ToString(prefix); + aDest.Append(prefix); + aDest.Append(PRUnichar(':')); + } + nsAutoString localName; + mLocalName->ToString(localName); + aDest.Append(localName); +} +#endif diff --git a/mozilla/content/xslt/src/xpath/txNodeSetFunctionCall.cpp b/mozilla/content/xslt/src/xpath/txNodeSetFunctionCall.cpp index 498a164948b..50754addc25 100644 --- a/mozilla/content/xslt/src/xpath/txNodeSetFunctionCall.cpp +++ b/mozilla/content/xslt/src/xpath/txNodeSetFunctionCall.cpp @@ -227,6 +227,59 @@ NodeSetFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_ERROR_UNEXPECTED; } +static Expr::ResultType resultTypes[] = +{ + Expr::NUMBER_RESULT, // COUNT + Expr::NODESET_RESULT, // ID + Expr::NUMBER_RESULT, // LAST + Expr::STRING_RESULT, // LOCAL_NAME + Expr::STRING_RESULT, // NAMESPACE_URI + Expr::STRING_RESULT, // NAME + Expr::NUMBER_RESULT // POSITION +}; + +Expr::ResultType +NodeSetFunctionCall::getReturnType() +{ + return resultTypes[mType]; +} + +PRBool +NodeSetFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + switch (mType) { + case COUNT: + { + return argsSensitiveTo(aContext); + } + case ID: + { + return (aContext & DOCUMENT_CONTEXT) || + argsSensitiveTo(aContext); + } + case LAST: + { + return !!(aContext & SIZE_CONTEXT); + } + case LOCAL_NAME: + case NAME: + case NAMESPACE_URI: + { + if (params.isEmpty()) { + return !!(aContext & NODE_CONTEXT); + } + return argsSensitiveTo(aContext); + } + case POSITION: + { + return !!(aContext & POSITION_CONTEXT); + } + } + + NS_NOTREACHED("how'd we get here?"); + return PR_TRUE; +} + #ifdef TX_TO_STRING nsresult NodeSetFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xpath/txNodeTypeTest.cpp b/mozilla/content/xslt/src/xpath/txNodeTypeTest.cpp index a50e6ee90cd..297803fa334 100644 --- a/mozilla/content/xslt/src/xpath/txNodeTypeTest.cpp +++ b/mozilla/content/xslt/src/xpath/txNodeTypeTest.cpp @@ -49,10 +49,6 @@ txNodeTypeTest::txNodeTypeTest(NodeType aNodeType) { } -txNodeTypeTest::~txNodeTypeTest() -{ -} - void txNodeTypeTest::setNodeName(const nsAString& aName) { mNodeName = do_GetAtom(aName); @@ -94,6 +90,12 @@ double txNodeTypeTest::getDefaultPriority() return mNodeName ? 0 : -0.5; } +PRBool +txNodeTypeTest::isSensitiveTo(Expr::ContextSensitivity aContext) +{ + return !!(aContext & Expr::NODE_CONTEXT); +} + #ifdef TX_TO_STRING void txNodeTypeTest::toString(nsAString& aDest) diff --git a/mozilla/content/xslt/src/xpath/txNumberFunctionCall.cpp b/mozilla/content/xslt/src/xpath/txNumberFunctionCall.cpp index be9ef7806fc..c5bf11958e5 100644 --- a/mozilla/content/xslt/src/xpath/txNumberFunctionCall.cpp +++ b/mozilla/content/xslt/src/xpath/txNumberFunctionCall.cpp @@ -153,6 +153,22 @@ NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_ERROR_UNEXPECTED; } +Expr::ResultType +NumberFunctionCall::getReturnType() +{ + return NUMBER_RESULT; +} + +PRBool +NumberFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + if (mType == NUMBER && params.isEmpty()) { + return !!(aContext & NODE_CONTEXT); + } + + return argsSensitiveTo(aContext); +} + #ifdef TX_TO_STRING nsresult NumberFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xpath/txPathExpr.cpp b/mozilla/content/xslt/src/xpath/txPathExpr.cpp index b124ce7fd42..50bbfd3c7cd 100644 --- a/mozilla/content/xslt/src/xpath/txPathExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txPathExpr.cpp @@ -102,13 +102,29 @@ PathExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) { *aResult = nsnull; - nsRefPtr nodes; - nsresult rv = aContext->recycler()->getNodeSet(aContext->getContextNode(), - getter_AddRefs(nodes)); + // We need to evaluate the first step with the current context since it + // can depend on the context size and position. For example: + // key('books', concat('book', position())) + txListIterator iter(&expressions); + PathExprItem* pxi = NS_STATIC_CAST(PathExprItem*, iter.next()); + nsRefPtr res; + nsresult rv = pxi->expr->evaluate(aContext, getter_AddRefs(res)); NS_ENSURE_SUCCESS(rv, rv); - txListIterator iter(&expressions); - PathExprItem* pxi; + NS_ENSURE_TRUE(res->getResultType() == txAExprResult::NODESET, + NS_ERROR_XSLT_NODESET_EXPECTED); + + nsRefPtr nodes = NS_STATIC_CAST(txNodeSet*, + NS_STATIC_CAST(txAExprResult*, + res)); + if (nodes->isEmpty()) { + res.swap(*aResult); + + return NS_OK; + } + res = nsnull; // To allow recycling + + // Evaluate remaining steps while ((pxi = (PathExprItem*)iter.next())) { nsRefPtr tmpNodes; txNodeSetContext eContext(nodes, aContext); @@ -216,6 +232,53 @@ PathExpr::evalDescendants(Expr* aStep, const txXPathNode& aNode, return NS_OK; } //-- evalDescendants +TX_IMPL_EXPR_STUBS_BASE(PathExpr, NODESET_RESULT) + +Expr* +PathExpr::getSubExprAt(PRUint32 aPos) +{ + PathExprItem* pxi = NS_STATIC_CAST(PathExprItem*, expressions.get(aPos)); + + return pxi ? pxi->expr.get() : nsnull; +} +void +PathExpr::setSubExprAt(PRUint32 aPos, Expr* aExpr) +{ + NS_ASSERTION(aPos < (PRUint32)expressions.getLength(), + "setting bad subexpression index"); + PathExprItem* pxi = NS_STATIC_CAST(PathExprItem*, expressions.get(aPos)); + pxi->expr.forget(); + pxi->expr = aExpr; +} + + +PRBool +PathExpr::isSensitiveTo(ContextSensitivity aContext) +{ + txListIterator iter(&expressions); + PathExprItem* pxi = NS_STATIC_CAST(PathExprItem*, iter.next()); + if (pxi->expr->isSensitiveTo(aContext)) { + return PR_TRUE; + } + + // We're creating a new node/nodeset so we can ignore those bits. + Expr::ContextSensitivity context = + aContext & ~(Expr::NODE_CONTEXT | Expr::NODESET_CONTEXT); + if (context == NO_CONTEXT) { + return PR_FALSE; + } + + while ((pxi = NS_STATIC_CAST(PathExprItem*, iter.next()))) { + NS_ASSERTION(!pxi->expr->isSensitiveTo(Expr::NODESET_CONTEXT), + "Step cannot depend on nodeset-context"); + if (pxi->expr->isSensitiveTo(context)) { + return PR_TRUE; + } + } + + return PR_FALSE; +} + #ifdef TX_TO_STRING void PathExpr::toString(nsAString& dest) diff --git a/mozilla/content/xslt/src/xpath/txPredicateList.cpp b/mozilla/content/xslt/src/xpath/txPredicateList.cpp index 419faefad87..e787f9d3c87 100644 --- a/mozilla/content/xslt/src/xpath/txPredicateList.cpp +++ b/mozilla/content/xslt/src/xpath/txPredicateList.cpp @@ -116,6 +116,12 @@ PredicateList::evaluatePredicates(txNodeSet* nodes, return NS_OK; } +void +PredicateList::dropFirst() +{ + predicates.remove(predicates.get(0)); +} + /* * returns true if this predicate list is empty */ @@ -124,6 +130,40 @@ MBool PredicateList::isEmpty() return (MBool)(predicates.getLength() == 0); } // isEmpty +Expr* +PredicateList::getSubExprAt(PRUint32 aPos) +{ + return NS_STATIC_CAST(Expr*, predicates.get(aPos)); +} + +void +PredicateList::setSubExprAt(PRUint32 aPos, Expr* aExpr) +{ + NS_ASSERTION(aPos < (PRUint32)predicates.getLength(), + "setting bad subexpression index"); + predicates.replace(aPos, aExpr); +} + +PRBool +PredicateList::isSensitiveTo(Expr::ContextSensitivity aContext) +{ + // We're creating a new node/nodeset so we can ignore those bits. + Expr::ContextSensitivity context = + aContext & ~(Expr::NODE_CONTEXT | Expr::NODESET_CONTEXT); + if (context == Expr::NO_CONTEXT) { + return PR_FALSE; + } + + txListIterator iter(&predicates); + while (iter.hasNext()) { + if (NS_STATIC_CAST(Expr*, iter.next())->isSensitiveTo(context)) { + return PR_TRUE; + } + } + + return PR_FALSE; +} + #ifdef TX_TO_STRING void PredicateList::toString(nsAString& dest) { diff --git a/mozilla/content/xslt/src/xpath/txPredicatedNodeTest.cpp b/mozilla/content/xslt/src/xpath/txPredicatedNodeTest.cpp new file mode 100755 index 00000000000..e3a61eac2a0 --- /dev/null +++ b/mozilla/content/xslt/src/xpath/txPredicatedNodeTest.cpp @@ -0,0 +1,90 @@ +/* -*- 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 TransforMiiX XSLT processor. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corporation + * + * 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 "txExpr.h" +#include "txExprResult.h" +#include "txSingleNodeContext.h" + +txPredicatedNodeTest::txPredicatedNodeTest(txNodeTest* aNodeTest, + Expr* aPredicate) + : mNodeTest(aNodeTest), + mPredicate(aPredicate) +{ + NS_ASSERTION(!mPredicate->isSensitiveTo(Expr::NODESET_CONTEXT), + "predicate must not be context-nodeset-sensitive"); +} + +PRBool +txPredicatedNodeTest::matches(const txXPathNode& aNode, + txIMatchContext* aContext) +{ + if (!mNodeTest->matches(aNode, aContext)) { + return PR_FALSE; + } + + txSingleNodeContext context(aNode, aContext); + nsRefPtr res; + nsresult rv = mPredicate->evaluate(&context, getter_AddRefs(res)); + NS_ENSURE_SUCCESS(rv, PR_FALSE); + + return res->booleanValue(); +} + +double +txPredicatedNodeTest::getDefaultPriority() +{ + return 0.5; +} + +PRBool +txPredicatedNodeTest::isSensitiveTo(Expr::ContextSensitivity aContext) +{ + return mNodeTest->isSensitiveTo(aContext) || + mPredicate->isSensitiveTo(aContext); +} + +#ifdef TX_TO_STRING +void +txPredicatedNodeTest::toString(nsAString& aDest) +{ + mNodeTest->toString(aDest); + aDest.Append(PRUnichar('[')); + mPredicate->toString(aDest); + aDest.Append(PRUnichar(']')); +} +#endif diff --git a/mozilla/content/xslt/src/xpath/txRelationalExpr.cpp b/mozilla/content/xslt/src/xpath/txRelationalExpr.cpp index 5f280c468b8..3101214d5ba 100644 --- a/mozilla/content/xslt/src/xpath/txRelationalExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txRelationalExpr.cpp @@ -205,6 +205,15 @@ RelationalExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_OK; } +TX_IMPL_EXPR_STUBS_2(RelationalExpr, BOOLEAN_RESULT, mLeftExpr, mRightExpr) + +PRBool +RelationalExpr::isSensitiveTo(ContextSensitivity aContext) +{ + return mLeftExpr->isSensitiveTo(aContext) || + mRightExpr->isSensitiveTo(aContext); +} + #ifdef TX_TO_STRING void RelationalExpr::toString(nsAString& str) diff --git a/mozilla/content/xslt/src/xpath/txRootExpr.cpp b/mozilla/content/xslt/src/xpath/txRootExpr.cpp index 0b233b43bf1..d089aeb45d9 100644 --- a/mozilla/content/xslt/src/xpath/txRootExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txRootExpr.cpp @@ -67,6 +67,14 @@ RootExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return aContext->recycler()->getNodeSet(*document, aResult); } //-- evaluate +TX_IMPL_EXPR_STUBS_0(RootExpr, NODESET_RESULT) + +PRBool +RootExpr::isSensitiveTo(ContextSensitivity aContext) +{ + return !!(aContext & DOCUMENT_CONTEXT); +} + #ifdef TX_TO_STRING void RootExpr::toString(nsAString& dest) diff --git a/mozilla/content/xslt/src/xpath/txStandaloneXPathTreeWalker.cpp b/mozilla/content/xslt/src/xpath/txStandaloneXPathTreeWalker.cpp index e01ea53f56c..07f9bb6837e 100644 --- a/mozilla/content/xslt/src/xpath/txStandaloneXPathTreeWalker.cpp +++ b/mozilla/content/xslt/src/xpath/txStandaloneXPathTreeWalker.cpp @@ -133,6 +133,31 @@ txXPathTreeWalker::moveToNextAttribute() return PR_FALSE; } +PRBool +txXPathTreeWalker::moveToNamedAttribute(nsIAtom* aLocalName, PRInt32 aNSID) +{ + if (INNER->nodeType != Node::ELEMENT_NODE) { + return PR_FALSE; + } + + Element* element = NS_STATIC_CAST(Element*, INNER); + NamedNodeMap* attrs = element->getAttributes(); + NodeListDefinition::ListItem* item = attrs->firstItem; + // find requested attribute + nsCOMPtr localName; + while (item && (item->node->getNamespaceID() != aNSID || + !item->node->getLocalName(getter_AddRefs(localName)) || + localName != aLocalName) { + item = item->next; + } + if (!item) { + return PR_FALSE; + } + + INNER = NS_STATIC_CAST(NodeDefinition*, item->node); + return PR_TRUE; +} + PRBool txXPathTreeWalker::moveToFirstChild() { diff --git a/mozilla/content/xslt/src/xpath/txStringFunctionCall.cpp b/mozilla/content/xslt/src/xpath/txStringFunctionCall.cpp index b39b33b43df..5f48f1c35cf 100644 --- a/mozilla/content/xslt/src/xpath/txStringFunctionCall.cpp +++ b/mozilla/content/xslt/src/xpath/txStringFunctionCall.cpp @@ -350,6 +350,39 @@ StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_ERROR_UNEXPECTED; } +static Expr::ResultType resultTypes[] = +{ + Expr::STRING_RESULT, // CONCAT + Expr::BOOLEAN_RESULT, // CONTAINS + Expr::STRING_RESULT, // NORMALIZE_SPACE + Expr::BOOLEAN_RESULT, // STARTS_WITH + Expr::STRING_RESULT, // STRING + Expr::NUMBER_RESULT, // STRING_LENGTH + Expr::STRING_RESULT, // SUBSTRING + Expr::STRING_RESULT, // SUBSTRING_AFTER + Expr::STRING_RESULT, // SUBSTRING_BEFORE + Expr::STRING_RESULT // TRANSLATE +}; + +Expr::ResultType +StringFunctionCall::getReturnType() +{ + return resultTypes[mType]; +} + +PRBool +StringFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + if (params.isEmpty() && + (mType == NORMALIZE_SPACE || + mType == STRING || + mType == STRING_LENGTH)) { + return !!(aContext & NODE_CONTEXT); + } + + return argsSensitiveTo(aContext); +} + #ifdef TX_TO_STRING nsresult StringFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xpath/txUnaryExpr.cpp b/mozilla/content/xslt/src/xpath/txUnaryExpr.cpp index 44853a3f594..f1b88ef608e 100644 --- a/mozilla/content/xslt/src/xpath/txUnaryExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txUnaryExpr.cpp @@ -69,6 +69,14 @@ UnaryExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) #endif } +TX_IMPL_EXPR_STUBS_1(UnaryExpr, NODESET_RESULT, expr) + +PRBool +UnaryExpr::isSensitiveTo(ContextSensitivity aContext) +{ + return expr->isSensitiveTo(aContext); +} + #ifdef TX_TO_STRING void UnaryExpr::toString(nsAString& str) diff --git a/mozilla/content/xslt/src/xpath/txUnionExpr.cpp b/mozilla/content/xslt/src/xpath/txUnionExpr.cpp index bf6a51f5167..47fa598455e 100644 --- a/mozilla/content/xslt/src/xpath/txUnionExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txUnionExpr.cpp @@ -125,6 +125,21 @@ UnionExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_OK; } //-- evaluate +TX_IMPL_EXPR_STUBS_LIST(UnionExpr, NODESET_RESULT, expressions) + +PRBool +UnionExpr::isSensitiveTo(ContextSensitivity aContext) +{ + txListIterator iter(&expressions); + while (iter.hasNext()) { + if (NS_STATIC_CAST(Expr*, iter.next())->isSensitiveTo(aContext)) { + return PR_TRUE; + } + } + + return PR_FALSE; +} + #ifdef TX_TO_STRING void UnionExpr::toString(nsAString& dest) diff --git a/mozilla/content/xslt/src/xpath/txVariableRefExpr.cpp b/mozilla/content/xslt/src/xpath/txVariableRefExpr.cpp index 7617705c705..f10ef9b9459 100644 --- a/mozilla/content/xslt/src/xpath/txVariableRefExpr.cpp +++ b/mozilla/content/xslt/src/xpath/txVariableRefExpr.cpp @@ -58,13 +58,6 @@ VariableRefExpr::VariableRefExpr(nsIAtom* aPrefix, nsIAtom* aLocalName, mPrefix = 0; } -/* - * Release the local name atom - */ -VariableRefExpr::~VariableRefExpr() -{ -} - /** * Evaluates this Expr based on the given context node and processor state * @param context the context node for evaluation of this Expr @@ -83,6 +76,14 @@ VariableRefExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_OK; } +TX_IMPL_EXPR_STUBS_0(VariableRefExpr, ANY_RESULT) + +PRBool +VariableRefExpr::isSensitiveTo(ContextSensitivity aContext) +{ + return !!(aContext & VARIABLES_CONTEXT); +} + #ifdef TX_TO_STRING void VariableRefExpr::toString(nsAString& aDest) diff --git a/mozilla/content/xslt/src/xpath/txXFormsFunctionCall.cpp b/mozilla/content/xslt/src/xpath/txXFormsFunctionCall.cpp index b0bc5e5f05a..b246754390e 100644 --- a/mozilla/content/xslt/src/xpath/txXFormsFunctionCall.cpp +++ b/mozilla/content/xslt/src/xpath/txXFormsFunctionCall.cpp @@ -517,6 +517,22 @@ XFormsFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) 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) diff --git a/mozilla/content/xslt/src/xpath/txXPathOptimizer.cpp b/mozilla/content/xslt/src/xpath/txXPathOptimizer.cpp new file mode 100755 index 00000000000..ef91510427b --- /dev/null +++ b/mozilla/content/xslt/src/xpath/txXPathOptimizer.cpp @@ -0,0 +1,126 @@ +/* -*- 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 TransforMiiX XSLT processor. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corporation + * + * 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 "txXPathOptimizer.h" +#include "txExprResult.h" +#include "nsIAtom.h" +#include "txAtoms.h" +#include "txXPathNode.h" +#include "txExpr.h" + +nsresult +txXPathOptimizer::optimize(Expr* aInExpr, Expr** aOutExpr) +{ + *aOutExpr = nsnull; + nsresult rv = NS_OK; + + // First optimize sub expressions + PRUint32 i = 0; + Expr* subExpr; + while ((subExpr = aInExpr->getSubExprAt(i))) { + Expr* newExpr = nsnull; + rv = optimize(subExpr, &newExpr); + NS_ENSURE_SUCCESS(rv, rv); + if (newExpr) { + delete subExpr; + aInExpr->setSubExprAt(i, newExpr); + } + + ++i; + } + + // Then see if current expression can be optimized + switch (aInExpr->getType()) { + case Expr::LOCATIONSTEP_ATTRIBUTE_EXPR: + return optimizeAttributeStep(aInExpr, aOutExpr); + + case Expr::LOCATIONSTEP_OTHER_EXPR: + return optimizeStep(aInExpr, aOutExpr); + + default: + break; + } + + return NS_OK; +} + +nsresult +txXPathOptimizer::optimizeAttributeStep(Expr* aInExpr, Expr** aOutExpr) +{ + LocationStep* step = NS_STATIC_CAST(LocationStep*, aInExpr); + + // Test for @foo type steps. + txNameTest* nameTest = nsnull; + if (!step->getSubExprAt(0) && + step->getNodeTest()->getType() == txNameTest::NAME_TEST && + (nameTest = NS_STATIC_CAST(txNameTest*, step->getNodeTest()))-> + mLocalName != txXPathAtoms::_asterix) { + + *aOutExpr = new txNamedAttributeStep(nameTest->mNamespace, + nameTest->mPrefix, + nameTest->mLocalName); + NS_ENSURE_TRUE(*aOutExpr, NS_ERROR_OUT_OF_MEMORY); + + return NS_OK; // return since we no longer have a step-object. + } + + // Do general step optimizations + + return optimizeStep(aInExpr, aOutExpr); +} + + +nsresult +txXPathOptimizer::optimizeStep(Expr* aInExpr, Expr** aOutExpr) +{ + LocationStep* step = NS_STATIC_CAST(LocationStep*, aInExpr); + + // Test for predicates that can be combined into the nodetest + Expr* pred; + while ((pred = step->getSubExprAt(0)) && + !pred->canReturnType(Expr::NUMBER_RESULT) && + !pred->isSensitiveTo(Expr::NODESET_CONTEXT)) { + txNodeTest* predTest = new txPredicatedNodeTest(step->getNodeTest(), pred); + NS_ENSURE_TRUE(predTest, NS_ERROR_OUT_OF_MEMORY); + + step->dropFirst(); + step->setNodeTest(predTest); + } + + return NS_OK; +} diff --git a/mozilla/content/xslt/src/xpath/txXPathOptimizer.h b/mozilla/content/xslt/src/xpath/txXPathOptimizer.h new file mode 100755 index 00000000000..3a16216f9d1 --- /dev/null +++ b/mozilla/content/xslt/src/xpath/txXPathOptimizer.h @@ -0,0 +1,63 @@ +/* -*- 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 TransforMiiX XSLT processor. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corporation + * + * 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 txXPathOptimizer_h__ +#define txXPathOptimizer_h__ + +#include "txCore.h" + +class Expr; + +class txXPathOptimizer +{ +public: + /** + * Optimize the given expression. + * @param aInExpr Expression to optimize. + * @param aOutExpr Resulting expression, null if optimization didn't + * result in a new expression. + */ + nsresult optimize(Expr* aInExpr, Expr** aOutExpr); + +private: + // Helper methods for optimizing specific classes + nsresult optimizeAttributeStep(Expr* aInExpr, Expr** aOutExpr); + nsresult optimizeStep(Expr* aInExpr, Expr** aOutExpr); +}; + +#endif diff --git a/mozilla/content/xslt/src/xpath/txXPathTreeWalker.h b/mozilla/content/xslt/src/xpath/txXPathTreeWalker.h index 63c8e4d24cf..fc66ad5f380 100644 --- a/mozilla/content/xslt/src/xpath/txXPathTreeWalker.h +++ b/mozilla/content/xslt/src/xpath/txXPathTreeWalker.h @@ -87,6 +87,7 @@ public: PRBool moveToElementById(const nsAString& aID); PRBool moveToFirstAttribute(); PRBool moveToNextAttribute(); + PRBool moveToNamedAttribute(nsIAtom* aLocalName, PRInt32 aNSID); PRBool moveToFirstChild(); PRBool moveToLastChild(); PRBool moveToNextSibling(); diff --git a/mozilla/content/xslt/src/xslt/Makefile.in b/mozilla/content/xslt/src/xslt/Makefile.in index 740917e776e..92fa26062e0 100644 --- a/mozilla/content/xslt/src/xslt/Makefile.in +++ b/mozilla/content/xslt/src/xslt/Makefile.in @@ -94,6 +94,7 @@ CPPSRCS = \ txToplevelItems.cpp \ txXSLTNumber.cpp \ txXSLTNumberCounters.cpp \ + txPatternOptimizer.cpp \ txXSLTPatterns.cpp \ txXSLTProcessor.cpp \ txPatternParser.cpp \ diff --git a/mozilla/content/xslt/src/xslt/txCurrentFunctionCall.cpp b/mozilla/content/xslt/src/xslt/txCurrentFunctionCall.cpp index d3aca6defe1..7aa74ca7e84 100644 --- a/mozilla/content/xslt/src/xslt/txCurrentFunctionCall.cpp +++ b/mozilla/content/xslt/src/xslt/txCurrentFunctionCall.cpp @@ -35,7 +35,19 @@ CurrentFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_ERROR_UNEXPECTED; } return aContext->recycler()->getNodeSet( - es->getEvalContext()->getContextNode(), aResult); + es->getEvalContext()->getContextNode(), aResult); +} + +Expr::ResultType +CurrentFunctionCall::getReturnType() +{ + return NODESET_RESULT; +} + +PRBool +CurrentFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + return (aContext & PRIVATE_CONTEXT); } #ifdef TX_TO_STRING diff --git a/mozilla/content/xslt/src/xslt/txDocumentFunctionCall.cpp b/mozilla/content/xslt/src/xslt/txDocumentFunctionCall.cpp index f35015ffdb8..3da11070a1d 100644 --- a/mozilla/content/xslt/src/xslt/txDocumentFunctionCall.cpp +++ b/mozilla/content/xslt/src/xslt/txDocumentFunctionCall.cpp @@ -177,6 +177,18 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext, return NS_OK; } +Expr::ResultType +DocumentFunctionCall::getReturnType() +{ + return NODESET_RESULT; +} + +PRBool +DocumentFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + return argsSensitiveTo(aContext); +} + #ifdef TX_TO_STRING nsresult DocumentFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xslt/txElementAvailableFnCall.cpp b/mozilla/content/xslt/src/xslt/txElementAvailableFnCall.cpp index 7d94c463b06..4d6ec524bac 100644 --- a/mozilla/content/xslt/src/xslt/txElementAvailableFnCall.cpp +++ b/mozilla/content/xslt/src/xslt/txElementAvailableFnCall.cpp @@ -130,6 +130,18 @@ ElementAvailableFunctionCall::evaluate(txIEvalContext* aContext, return NS_OK; } +Expr::ResultType +ElementAvailableFunctionCall::getReturnType() +{ + return BOOLEAN_RESULT; +} + +PRBool +ElementAvailableFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + return argsSensitiveTo(aContext); +} + #ifdef TX_TO_STRING nsresult ElementAvailableFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp b/mozilla/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp index f8faabc7ba2..4c005aef550 100644 --- a/mozilla/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp +++ b/mozilla/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp @@ -406,6 +406,18 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext, return aContext->recycler()->getStringResult(res, aResult); } //-- evaluate +Expr::ResultType +txFormatNumberFunctionCall::getReturnType() +{ + return STRING_RESULT; +} + +PRBool +txFormatNumberFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + return argsSensitiveTo(aContext); +} + #ifdef TX_TO_STRING nsresult txFormatNumberFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xslt/txFunctionAvailableFnCall.cpp b/mozilla/content/xslt/src/xslt/txFunctionAvailableFnCall.cpp index 27596b43245..208b1c2e8d9 100644 --- a/mozilla/content/xslt/src/xslt/txFunctionAvailableFnCall.cpp +++ b/mozilla/content/xslt/src/xslt/txFunctionAvailableFnCall.cpp @@ -129,6 +129,18 @@ FunctionAvailableFunctionCall::evaluate(txIEvalContext* aContext, } +Expr::ResultType +FunctionAvailableFunctionCall::getReturnType() +{ + return BOOLEAN_RESULT; +} + +PRBool +FunctionAvailableFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + return argsSensitiveTo(aContext); +} + #ifdef TX_TO_STRING nsresult FunctionAvailableFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xslt/txGenerateIdFunctionCall.cpp b/mozilla/content/xslt/src/xslt/txGenerateIdFunctionCall.cpp index ea8d1f91c89..ef6f9f46716 100644 --- a/mozilla/content/xslt/src/xslt/txGenerateIdFunctionCall.cpp +++ b/mozilla/content/xslt/src/xslt/txGenerateIdFunctionCall.cpp @@ -105,6 +105,22 @@ GenerateIdFunctionCall::evaluate(txIEvalContext* aContext, return NS_OK; } +Expr::ResultType +GenerateIdFunctionCall::getReturnType() +{ + return STRING_RESULT; +} + +PRBool +GenerateIdFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + if (params.isEmpty()) { + return !!(aContext & NODE_CONTEXT); + } + + return argsSensitiveTo(aContext); +} + #ifdef TX_TO_STRING nsresult GenerateIdFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xslt/txKeyFunctionCall.cpp b/mozilla/content/xslt/src/xslt/txKeyFunctionCall.cpp index 00044383a90..36217934b3f 100644 --- a/mozilla/content/xslt/src/xslt/txKeyFunctionCall.cpp +++ b/mozilla/content/xslt/src/xslt/txKeyFunctionCall.cpp @@ -126,6 +126,18 @@ txKeyFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) return NS_OK; } +Expr::ResultType +txKeyFunctionCall::getReturnType() +{ + return NODESET_RESULT; +} + +PRBool +txKeyFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + return (aContext & DOCUMENT_CONTEXT) || argsSensitiveTo(aContext); +} + #ifdef TX_TO_STRING nsresult txKeyFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xslt/txPatternOptimizer.cpp b/mozilla/content/xslt/src/xslt/txPatternOptimizer.cpp new file mode 100755 index 00000000000..6cbc496b6d1 --- /dev/null +++ b/mozilla/content/xslt/src/xslt/txPatternOptimizer.cpp @@ -0,0 +1,109 @@ +/* -*- 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 TransforMiiX XSLT processor. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corporation + * + * 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 "txPatternOptimizer.h" +#include "txXSLTPatterns.h" + +nsresult +txPatternOptimizer::optimize(txPattern* aInPattern, txPattern** aOutPattern) +{ + *aOutPattern = nsnull; + nsresult rv = NS_OK; + + // First optimize sub expressions + PRUint32 i = 0; + Expr* subExpr; + while ((subExpr = aInPattern->getSubExprAt(i))) { + Expr* newExpr = nsnull; + rv = mXPathOptimizer.optimize(subExpr, &newExpr); + NS_ENSURE_SUCCESS(rv, rv); + if (newExpr) { + delete subExpr; + aInPattern->setSubExprAt(i, newExpr); + } + + ++i; + } + + // Then optimize sub patterns + txPattern* subPattern; + i = 0; + while ((subPattern = aInPattern->getSubPatternAt(i))) { + txPattern* newPattern = nsnull; + rv = optimize(subPattern, &newPattern); + NS_ENSURE_SUCCESS(rv, rv); + if (newPattern) { + delete subPattern; + aInPattern->setSubPatternAt(i, newPattern); + } + + ++i; + } + + // Finally see if current pattern can be optimized + switch (aInPattern->getType()) { + case txPattern::STEP_PATTERN: + return optimizeStep(aInPattern, aOutPattern); + + default: + break; + } + + return NS_OK; +} + + +nsresult +txPatternOptimizer::optimizeStep(txPattern* aInPattern, + txPattern** aOutPattern) +{ + txStepPattern* step = NS_STATIC_CAST(txStepPattern*, aInPattern); + + // Test for predicates that can be combined into the nodetest + Expr* pred; + while ((pred = step->getSubExprAt(0)) && + !pred->canReturnType(Expr::NUMBER_RESULT) && + !pred->isSensitiveTo(Expr::NODESET_CONTEXT)) { + txNodeTest* predTest = new txPredicatedNodeTest(step->getNodeTest(), + pred); + step->dropFirst(); + step->setNodeTest(predTest); + } + + return NS_OK; +} diff --git a/mozilla/content/xslt/src/xslt/txPatternOptimizer.h b/mozilla/content/xslt/src/xslt/txPatternOptimizer.h new file mode 100755 index 00000000000..ca0aabcb437 --- /dev/null +++ b/mozilla/content/xslt/src/xslt/txPatternOptimizer.h @@ -0,0 +1,65 @@ +/* -*- 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 TransforMiiX XSLT processor. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corporation + * + * 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 txPatternOptimizer_h__ +#define txPatternOptimizer_h__ + +#include "txXPathOptimizer.h" + +class txPattern; + +class txPatternOptimizer +{ +public: + /** + * Optimize the given pattern. + * @param aInPattern Pattern to optimize. + * @param aOutPattern Resulting pattern, null if optimization didn't + * result in a new pattern. + */ + nsresult optimize(txPattern* aInPattern, txPattern** aOutPattern); + +private: + + // Helper methods for optimizing specific classes + nsresult optimizeStep(txPattern* aInPattern, txPattern** aOutPattern); + + txXPathOptimizer mXPathOptimizer; +}; + +#endif //txPatternOptimizer_h__ diff --git a/mozilla/content/xslt/src/xslt/txPatternParser.cpp b/mozilla/content/xslt/src/xslt/txPatternParser.cpp index e1c7c7ca3a9..d302115d120 100644 --- a/mozilla/content/xslt/src/xslt/txPatternParser.cpp +++ b/mozilla/content/xslt/src/xslt/txPatternParser.cpp @@ -43,23 +43,31 @@ #include "txStringUtils.h" #include "txXSLTPatterns.h" #include "txIXPathContext.h" +#include "txPatternOptimizer.h" + txPattern* txPatternParser::createPattern(const nsAFlatString& aPattern, txIParseContext* aContext) { - txPattern* pattern = 0; txExprLexer lexer; nsresult rv = lexer.parse(aPattern); if (NS_FAILED(rv)) { // XXX error report parsing error return 0; } - rv = createUnionPattern(lexer, aContext, pattern); + nsAutoPtr pattern; + rv = createUnionPattern(lexer, aContext, *getter_Transfers(pattern)); if (NS_FAILED(rv)) { // XXX error report parsing error return 0; } - return pattern; + + txPatternOptimizer optimizer; + txPattern* newPattern = nsnull; + rv = optimizer.optimize(pattern, &newPattern); + NS_ENSURE_SUCCESS(rv, nsnull); + + return newPattern ? newPattern : pattern.forget(); } nsresult txPatternParser::createUnionPattern(txExprLexer& aLexer, diff --git a/mozilla/content/xslt/src/xslt/txStylesheetCompiler.cpp b/mozilla/content/xslt/src/xslt/txStylesheetCompiler.cpp index e700ea495e4..d482e53a6c0 100644 --- a/mozilla/content/xslt/src/xslt/txStylesheetCompiler.cpp +++ b/mozilla/content/xslt/src/xslt/txStylesheetCompiler.cpp @@ -884,6 +884,22 @@ txErrorFunctionCall::evaluate(txIEvalContext* aContext, return NS_ERROR_XPATH_BAD_EXTENSION_FUNCTION; } +Expr::ResultType +txErrorFunctionCall::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 +txErrorFunctionCall::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 txErrorFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xslt/txSystemPropertyFunctionCall.cpp b/mozilla/content/xslt/src/xslt/txSystemPropertyFunctionCall.cpp index 0f7f15a9025..8384db27cad 100644 --- a/mozilla/content/xslt/src/xslt/txSystemPropertyFunctionCall.cpp +++ b/mozilla/content/xslt/src/xslt/txSystemPropertyFunctionCall.cpp @@ -109,6 +109,18 @@ SystemPropertyFunctionCall::evaluate(txIEvalContext* aContext, } +Expr::ResultType +SystemPropertyFunctionCall::getReturnType() +{ + return STRING_RESULT | NUMBER_RESULT; +} + +PRBool +SystemPropertyFunctionCall::isSensitiveTo(ContextSensitivity aContext) +{ + return argsSensitiveTo(aContext); +} + #ifdef TX_TO_STRING nsresult SystemPropertyFunctionCall::getNameAtom(nsIAtom** aAtom) diff --git a/mozilla/content/xslt/src/xslt/txXSLTPatterns.cpp b/mozilla/content/xslt/src/xslt/txXSLTPatterns.cpp index cabcdb9c2a2..2bd8b7400d7 100644 --- a/mozilla/content/xslt/src/xslt/txXSLTPatterns.cpp +++ b/mozilla/content/xslt/src/xslt/txXSLTPatterns.cpp @@ -129,6 +129,22 @@ nsresult txUnionPattern::getSimplePatterns(txList& aList) return NS_OK; } +TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(txUnionPattern); +txPattern* +txUnionPattern::getSubPatternAt(PRUint32 aPos) +{ + return NS_STATIC_CAST(txPattern*, mLocPathPatterns.get(aPos)); +} + +void +txUnionPattern::setSubPatternAt(PRUint32 aPos, txPattern* aPattern) +{ + NS_ASSERTION(aPos < (PRUint32)mLocPathPatterns.getLength(), + "setting bad subexpression index"); + mLocPathPatterns.replace(aPos, aPattern); +} + + #ifdef TX_TO_STRING void txUnionPattern::toString(nsAString& aDest) @@ -254,6 +270,25 @@ double txLocPathPattern::getDefaultPriority() return ((Step*)mSteps.get(0))->pattern->getDefaultPriority(); } +TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(txLocPathPattern); +txPattern* +txLocPathPattern::getSubPatternAt(PRUint32 aPos) +{ + Step* step = NS_STATIC_CAST(Step*, mSteps.get(aPos)); + + return step ? step->pattern.get() : nsnull; +} + +void +txLocPathPattern::setSubPatternAt(PRUint32 aPos, txPattern* aPattern) +{ + NS_ASSERTION(aPos < (PRUint32)mSteps.getLength(), + "setting bad subexpression index"); + Step* step = NS_STATIC_CAST(Step*, mSteps.get(aPos)); + step->pattern.forget(); + step->pattern = aPattern; +} + #ifdef TX_TO_STRING void txLocPathPattern::toString(nsAString& aDest) @@ -300,6 +335,9 @@ double txRootPattern::getDefaultPriority() return 0.5; } +TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(txRootPattern); +TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(txRootPattern); + #ifdef TX_TO_STRING void txRootPattern::toString(nsAString& aDest) @@ -383,6 +421,9 @@ double txIdPattern::getDefaultPriority() return 0.5; } +TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(txIdPattern); +TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(txIdPattern); + #ifdef TX_TO_STRING void txIdPattern::toString(nsAString& aDest) @@ -436,6 +477,9 @@ double txKeyPattern::getDefaultPriority() return 0.5; } +TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(txKeyPattern); +TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(txKeyPattern); + #ifdef TX_TO_STRING void txKeyPattern::toString(nsAString& aDest) @@ -467,11 +511,6 @@ txKeyPattern::toString(nsAString& aDest) * a txPattern to hold the NodeTest and the Predicates of a StepPattern */ -txStepPattern::~txStepPattern() -{ - delete mNodeTest; -} - MBool txStepPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext) { NS_ASSERTION(mNodeTest, "Internal error"); @@ -586,6 +625,25 @@ double txStepPattern::getDefaultPriority() return 0.5; } +txPattern::Type +txStepPattern::getType() +{ + return STEP_PATTERN; +} + +TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(txStepPattern); +Expr* +txStepPattern::getSubExprAt(PRUint32 aPos) +{ + return PredicateList::getSubExprAt(aPos); +} + +void +txStepPattern::setSubExprAt(PRUint32 aPos, Expr* aExpr) +{ + return PredicateList::setSubExprAt(aPos, aExpr); +} + #ifdef TX_TO_STRING void txStepPattern::toString(nsAString& aDest) diff --git a/mozilla/content/xslt/src/xslt/txXSLTPatterns.h b/mozilla/content/xslt/src/xslt/txXSLTPatterns.h index 043ec6782e0..bfbbc4853f3 100644 --- a/mozilla/content/xslt/src/xslt/txXSLTPatterns.h +++ b/mozilla/content/xslt/src/xslt/txXSLTPatterns.h @@ -74,6 +74,40 @@ public: */ virtual nsresult getSimplePatterns(txList &aList); + /** + * Returns the type of this pattern. + */ + enum Type { + STEP_PATTERN, + OTHER_PATTERN + }; + virtual Type getType() + { + return OTHER_PATTERN; + } + + /** + * Returns sub-expression at given position + */ + virtual Expr* getSubExprAt(PRUint32 aPos) = 0; + + /** + * Replace sub-expression at given position. Does not delete the old + * expression, that is the responsibility of the caller. + */ + virtual void setSubExprAt(PRUint32 aPos, Expr* aExpr) = 0; + + /** + * Returns sub-pattern at given position + */ + virtual txPattern* getSubPatternAt(PRUint32 aPos) = 0; + + /** + * Replace sub-pattern at given position. Does not delete the old + * pattern, that is the responsibility of the caller. + */ + virtual void setSubPatternAt(PRUint32 aPos, txPattern* aPattern) = 0; + #ifdef TX_TO_STRING /* * Returns the String representation of this Pattern. @@ -89,7 +123,11 @@ public: #define TX_DECL_PATTERN_BASE \ MBool matches(const txXPathNode& aNode, txIMatchContext* aContext); \ - double getDefaultPriority() + double getDefaultPriority(); \ + virtual Expr* getSubExprAt(PRUint32 aPos); \ + virtual void setSubExprAt(PRUint32 aPos, Expr* aExpr); \ + virtual txPattern* getSubPatternAt(PRUint32 aPos); \ + virtual void setSubPatternAt(PRUint32 aPos, txPattern* aPattern) #ifndef TX_TO_STRING #define TX_DECL_PATTERN TX_DECL_PATTERN_BASE @@ -103,6 +141,29 @@ public: TX_DECL_PATTERN; \ nsresult getSimplePatterns(txList &aList) +#define TX_IMPL_PATTERN_STUBS_NO_SUB_EXPR(_class) \ +Expr* \ +_class::getSubExprAt(PRUint32 aPos) \ +{ \ + return nsnull; \ +} \ +void \ +_class::setSubExprAt(PRUint32 aPos, Expr* aExpr) \ +{ \ + NS_NOTREACHED("setting bad subexpression index"); \ +} + +#define TX_IMPL_PATTERN_STUBS_NO_SUB_PATTERN(_class) \ +txPattern* \ +_class::getSubPatternAt(PRUint32 aPos) \ +{ \ + return nsnull; \ +} \ +void \ +_class::setSubPatternAt(PRUint32 aPos, txPattern* aPattern) \ +{ \ + NS_NOTREACHED("setting bad subexpression index"); \ +} class txUnionPattern : public txPattern { @@ -142,12 +203,7 @@ private: { } - ~Step() - { - delete pattern; - } - - txPattern* pattern; + nsAutoPtr pattern; MBool isChild; }; @@ -221,12 +277,21 @@ public: { } - ~txStepPattern(); - TX_DECL_PATTERN; + Type getType(); + + txNodeTest* getNodeTest() + { + return mNodeTest; + } + void setNodeTest(txNodeTest* aNodeTest) + { + mNodeTest.forget(); + mNodeTest = aNodeTest; + } private: - txNodeTest* mNodeTest; + nsAutoPtr mNodeTest; MBool mIsAttr; };