--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbcore/cssparser/hbexpressionparser_p.cpp Mon Oct 04 00:38:12 2010 +0300
@@ -0,0 +1,329 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbCore module of the UI Extensions for Mobile.
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at developer.feedback@nokia.com.
+**
+****************************************************************************/
+
+#include "hbexpressionparser_p.h"
+#include "hbhash_p.h"
+
+#include <QStack>
+
+
+static bool parseExpressionOperand(
+ const QString &str,
+ HbExpressionParser::Token &type,
+ int &value)
+{
+ QString valueString = str;
+ if (valueString.startsWith("var(") && valueString.endsWith(")")) {
+ // remove var( and last )
+ type = HbExpressionParser::Variable;
+ value = hbHash(valueString.midRef(4, valueString.size()-5));
+ } else {
+ if (valueString.endsWith(QLatin1String("un"), Qt::CaseInsensitive)) {
+ valueString.chop(2);
+ type = HbExpressionParser::LengthInUnits;
+ } else if (valueString.endsWith(QLatin1String("px"), Qt::CaseInsensitive)) {
+ valueString.chop(2);
+ type = HbExpressionParser::LengthInPixels;
+ } else if (valueString.endsWith(QLatin1String("mm"), Qt::CaseInsensitive)) {
+ valueString.chop(2);
+ type = HbExpressionParser::LengthInMillimeters;
+ } else {
+ // assume pixels
+ type = HbExpressionParser::LengthInPixels;
+ }
+ bool ok(true);
+ value = HbExpressionParser::toFixed(valueString.toFloat(&ok));
+ if (!ok) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static int precedence(HbExpressionParser::Token op)
+{
+ switch (op) {
+ case HbExpressionParser::Addition:
+ case HbExpressionParser::Subtraction:
+ return 1;
+ case HbExpressionParser::Multiplication:
+ case HbExpressionParser::Division:
+ return 2;
+ case HbExpressionParser::Negation:
+ return 3;
+ default:
+ return 0;
+ }
+}
+
+static bool isLeft(HbExpressionParser::Token op)
+{
+ switch (op) {
+ case HbExpressionParser::Addition:
+ case HbExpressionParser::Subtraction:
+ case HbExpressionParser::Multiplication:
+ case HbExpressionParser::Division:
+ return true;
+ case HbExpressionParser::Negation:
+ default:
+ return false;
+ }
+}
+
+
+bool HbExpressionParser::parse(const QString &str, QList<int> &tokens)
+{
+ tokens.clear();
+
+ // Parse the infix notation to "tempTokens"
+ QList<int> tempTokens;
+
+ const QChar SPACE(' ');
+ const QChar OPENPARENTHESIS('(');
+ const QChar CLOSEPARENTHESIS(')');
+ const QChar PLUS('+');
+ const QChar MINUS('-');
+ const QChar STAR('*');
+ const QChar SLASH('/');
+
+ int position = 0;
+
+ if (str.startsWith("expr(") && str.endsWith(")")) {
+ position = 4;
+ } else if (str.startsWith("-expr(") && str.endsWith(")")) {
+ position = 5;
+ tempTokens.append(LengthInPixels);
+ tempTokens.append(toFixed(-1.0));
+ tempTokens.append(Multiplication);
+ }
+
+ int begin = -1;
+ int nestingLevel = 0;
+ bool parseVariable = false;
+ bool endMark = false;
+ int operatorCount = 1;//there can only be 2 sequental operators if the latter one is negation
+ while (position < str.size()) {
+ endMark = false;
+ bool appendCloseParenthesis(false);
+ if (str.at(position) == SPACE) {
+ endMark = true;
+ } else if ((str.at(position) == OPENPARENTHESIS) && !parseVariable) {
+ tempTokens.append(OpenParenthesis);
+ nestingLevel++;
+ position++;
+ operatorCount = 1;
+ continue;
+ } else if (str.at(position) == CLOSEPARENTHESIS) {
+ if (parseVariable) {
+ parseVariable = false;
+ position++;
+ continue;
+ }
+ appendCloseParenthesis = true;
+ nestingLevel--;
+ endMark = true;
+ } else if ((str.at(position) == MINUS) && !parseVariable) {
+ endMark = true;
+ } else if ((str.at(position) == PLUS) ||
+ (str.at(position) == STAR) ||
+ (str.at(position) == SLASH)) {
+ endMark = true;
+ }
+
+ if (endMark) {
+ if (begin >= 0) {
+ // parse operand
+ QString valueString = str.mid(begin, position - begin);
+ if (operatorCount==0) {
+ // an operand without operator
+ return false;
+ }
+ HbExpressionParser::Token type;
+ int val;
+ if ( !parseExpressionOperand(valueString, type, val ) ) {
+ return false;
+ }
+ tempTokens.append(type);
+ tempTokens.append(val);
+ operatorCount = 0;
+ }
+ begin = -1;
+ if (str.at(position) == PLUS) {
+ if (operatorCount > 0) {
+ return false;
+ }
+ tempTokens.append(Addition);
+ operatorCount++;
+ } else if (str.at(position) == MINUS) {
+ if (operatorCount == 1) {
+ tempTokens.append(Negation);
+ } else if (operatorCount > 1) {
+ return false;
+ } else {
+ tempTokens.append(Subtraction);
+ }
+ operatorCount++;
+ } else if (str.at(position) == STAR) {
+ if (operatorCount > 0) {
+ return false;
+ }
+ tempTokens.append(Multiplication);
+ operatorCount++;
+ } else if (str.at(position) == SLASH) {
+ if (operatorCount > 0) {
+ return false;
+ }
+ tempTokens.append(Division);
+ operatorCount++;
+ }
+ if (appendCloseParenthesis) {
+ tempTokens.append(CloseParenthesis);
+ if (operatorCount != 0) {
+ // an operator without operand
+ return false;
+ }
+ }
+ position++;
+ continue;
+ }
+
+ if (begin == -1) {
+ begin = position;
+ }
+
+ // flag variable parsing (variable syntax contains parenthesis)
+ if ((str.at(position) == QChar('v')) && !parseVariable) {
+ parseVariable = true;
+ position++;
+ continue;
+ }
+ position++;
+ }
+
+ // check for unmatching parentheses
+ if (nestingLevel != 0) {
+ return false;
+ }
+
+ // parse last value
+ if (begin >= 0) {
+ // parse operand
+ if (operatorCount==0) {
+ // an operand without operator
+ return false;
+ }
+ QString valueString = str.mid(begin, position - begin);
+ HbExpressionParser::Token type;
+ int val;
+ if ( !parseExpressionOperand(valueString, type, val ) ) {
+ return false;
+ }
+ tempTokens.append(type);
+ tempTokens.append(val);
+ } else {
+ if (operatorCount!=0) {
+ // an operator without operand
+ return false;
+ }
+ }
+
+ if (tempTokens.count()<2) {
+ return false;
+ }
+
+ // Convert the infix notation to RPN with "shunting-yard" algorithm
+
+ QStack<Token> operatorStack;
+ for (int i=0; i<tempTokens.count(); i++) {
+ Token t = (Token)tempTokens.at(i);
+ switch (t) {
+ case Variable:
+ case LengthInPixels:
+ case LengthInUnits:
+ case LengthInMillimeters:
+ tokens.append(tempTokens.at(i));
+ i++;
+ tokens.append(tempTokens.at(i));
+ break;
+ case OpenParenthesis:
+ operatorStack.push(t);
+ break;
+ case CloseParenthesis:
+ while (operatorStack.count()) {
+ Token op = operatorStack.pop();
+ if (op == OpenParenthesis) {
+ break;
+ } else {
+ tokens.append(op);
+ }
+ }
+ break;
+ case Addition:
+ case Subtraction:
+ case Multiplication:
+ case Division:
+ case Negation:
+ while (operatorStack.count()) {
+ Token op = operatorStack.top();
+ if ((isLeft(t) && (precedence(t) <= precedence(op))) ||
+ (!isLeft(t) && (precedence(t) < precedence(op)))) {
+ tokens.append(op);
+ operatorStack.pop();
+ } else {
+ break;
+ }
+ }
+ operatorStack.push(t);
+ break;
+ default:
+ break;
+ }
+ }
+ while (operatorStack.count()) {
+ tokens.append(operatorStack.pop());
+ }
+
+ return true;
+}
+
+int HbExpressionParser::toFixed(float f)
+{
+ Q_ASSERT( sizeof(quint32) == sizeof(float) );
+ quint32 u;
+ memcpy(&u, &f, sizeof(quint32));
+ return u;
+}
+
+int HbExpressionParser::toFixed(double d)
+{
+ return toFixed((float)d);
+}
+
+qreal HbExpressionParser::fromFixed(int i)
+{
+ float f;
+ memcpy(&f, &i, sizeof(float));
+ return f;
+}