static inline PRUint32 HexDigitValue(PRInt32 ch) { if (IsDigit(ch)) { return DecimalDigitValue(ch); } else { // Note: c&7 just keeps the low three bits which causes // upper and lower case alphabetics to both yield their // "relative to 10" value for computing the hex value. return (ch & 0x7) + 9; } }
PRBool nsCSSScanner::ParseNumber(PRInt32 c, nsCSSToken& aToken) { NS_PRECONDITION(c == '.' || c == '+' || c == '-' || IsDigit(c), "Why did we get called?"); aToken.mHasSign = (c == '+' || c == '-'); // Our sign. PRInt32 sign = c == '-' ? -1 : 1; // Absolute value of the integer part of the mantissa. This is a double so // we don't run into overflow issues for consumers that only care about our // floating-point value while still being able to express the full PRInt32 // range for consumers who want integers. double intPart = 0; // Fractional part of the mantissa. This is a double so that when we convert // to float at the end we'll end up rounding to nearest float instead of // truncating down (as we would if fracPart were a float and we just // effectively lost the last several digits). double fracPart = 0; // Absolute value of the power of 10 that we should multiply by (only // relevant for numbers in scientific notation). Has to be a signed integer, // because multiplication of signed by unsigned converts the unsigned to // signed, so if we plan to actually multiply by expSign... PRInt32 exponent = 0; // Sign of the exponent. PRInt32 expSign = 1; if (aToken.mHasSign) { NS_ASSERTION(c != '.', "How did that happen?"); c = Read(); } PRBool gotDot = (c == '.'); if (!gotDot) { // Parse the integer part of the mantisssa NS_ASSERTION(IsDigit(c), "Why did we get called?"); do { intPart = 10*intPart + DecimalDigitValue(c); c = Read(); // The IsDigit check will do the right thing even if Read() returns < 0 } while (IsDigit(c)); gotDot = (c == '.') && IsDigit(Peek()); } if (gotDot) { // Parse the fractional part of the mantissa. c = Read(); NS_ASSERTION(IsDigit(c), "How did we get here?"); // Power of ten by which we need to divide our next digit float divisor = 10; do { fracPart += DecimalDigitValue(c) / divisor; divisor *= 10; c = Read(); // The IsDigit check will do the right thing even if Read() returns < 0 } while (IsDigit(c)); } PRBool gotE = PR_FALSE; if (IsSVGMode() && (c == 'e' || c == 'E')) { PRInt32 nextChar = Peek(); PRInt32 expSignChar = 0; if (nextChar == '-' || nextChar == '+') { expSignChar = Read(); nextChar = Peek(); } if (IsDigit(nextChar)) { gotE = PR_TRUE; if (expSignChar == '-') { expSign = -1; } c = Read(); NS_ASSERTION(IsDigit(c), "Peek() must have lied"); do { exponent = 10*exponent + DecimalDigitValue(c); c = Read(); // The IsDigit check will do the right thing even if Read() returns < 0 } while (IsDigit(c)); } else { if (expSignChar) { Pushback(expSignChar); } } } nsCSSTokenType type = eCSSToken_Number; // Set mIntegerValid for all cases (except %, below) because we need // it for the "2n" in :nth-child(2n). aToken.mIntegerValid = PR_FALSE; // Time to reassemble our number. float value = float(sign * (intPart + fracPart)); if (gotE) { // pow(), not powf(), because at least wince doesn't have the latter. // And explicitly cast everything to doubles to avoid issues with // overloaded pow() on Windows. value *= pow(10.0, double(expSign * exponent)); } else if (!gotDot) { // Clamp values outside of integer range. if (sign > 0) { aToken.mInteger = PRInt32(NS_MIN(intPart, double(PR_INT32_MAX))); } else { aToken.mInteger = PRInt32(NS_MAX(-intPart, double(PR_INT32_MIN))); } aToken.mIntegerValid = PR_TRUE; } nsString& ident = aToken.mIdent; ident.Truncate(); // Look at character that terminated the number if (c >= 0) { if (StartsIdent(c, Peek())) { if (!GatherIdent(c, ident)) { return PR_FALSE; } type = eCSSToken_Dimension; } else if ('%' == c) { type = eCSSToken_Percentage; value = value / 100.0f; aToken.mIntegerValid = PR_FALSE; } else { // Put back character that stopped numeric scan Pushback(c); } } aToken.mNumber = value; aToken.mType = type; return PR_TRUE; }
/** * Scan a Number, Percentage, or Dimension token (all of which begin * like a Number). Can produce a Symbol when a '.' is not followed by * digits, or when '+' or '-' are not followed by either a digit or a * '.' and then a digit. Can also produce a HTMLComment when it * encounters '-->'. */ bool nsCSSScanner::ScanNumber(nsCSSToken& aToken) { int32_t c = Peek(); #ifdef DEBUG { int32_t c2 = Peek(1); int32_t c3 = Peek(2); MOZ_ASSERT(IsDigit(c) || (IsDigit(c2) && (c == '.' || c == '+' || c == '-')) || (IsDigit(c3) && (c == '+' || c == '-') && c2 == '.'), "should not have been called"); } #endif // Sign of the mantissa (-1 or 1). int32_t sign = c == '-' ? -1 : 1; // Absolute value of the integer part of the mantissa. This is a double so // we don't run into overflow issues for consumers that only care about our // floating-point value while still being able to express the full int32_t // range for consumers who want integers. double intPart = 0; // Fractional part of the mantissa. This is a double so that when we convert // to float at the end we'll end up rounding to nearest float instead of // truncating down (as we would if fracPart were a float and we just // effectively lost the last several digits). double fracPart = 0; // Absolute value of the power of 10 that we should multiply by (only // relevant for numbers in scientific notation). Has to be a signed integer, // because multiplication of signed by unsigned converts the unsigned to // signed, so if we plan to actually multiply by expSign... int32_t exponent = 0; // Sign of the exponent. int32_t expSign = 1; aToken.mHasSign = (c == '+' || c == '-'); if (aToken.mHasSign) { Advance(); c = Peek(); } bool gotDot = (c == '.'); if (!gotDot) { // Scan the integer part of the mantissa. MOZ_ASSERT(IsDigit(c), "should have been excluded by logic above"); do { intPart = 10*intPart + DecimalDigitValue(c); Advance(); c = Peek(); } while (IsDigit(c)); gotDot = (c == '.') && IsDigit(Peek(1)); } if (gotDot) { // Scan the fractional part of the mantissa. Advance(); c = Peek(); MOZ_ASSERT(IsDigit(c), "should have been excluded by logic above"); // Power of ten by which we need to divide our next digit double divisor = 10; do { fracPart += DecimalDigitValue(c) / divisor; divisor *= 10; Advance(); c = Peek(); } while (IsDigit(c)); } bool gotE = false; if (c == 'e' || c == 'E') { int32_t expSignChar = Peek(1); int32_t nextChar = Peek(2); if (IsDigit(expSignChar) || ((expSignChar == '-' || expSignChar == '+') && IsDigit(nextChar))) { gotE = true; if (expSignChar == '-') { expSign = -1; } Advance(); // consumes the E if (expSignChar == '-' || expSignChar == '+') { Advance(); c = nextChar; } else { c = expSignChar; } MOZ_ASSERT(IsDigit(c), "should have been excluded by logic above"); do { exponent = 10*exponent + DecimalDigitValue(c); Advance(); c = Peek(); } while (IsDigit(c)); } } nsCSSTokenType type = eCSSToken_Number; // Set mIntegerValid for all cases (except %, below) because we need // it for the "2n" in :nth-child(2n). aToken.mIntegerValid = false; // Time to reassemble our number. // Do all the math in double precision so it's truncated only once. double value = sign * (intPart + fracPart); if (gotE) { // Explicitly cast expSign*exponent to double to avoid issues with // overloaded pow() on Windows. value *= pow(10.0, double(expSign * exponent)); } else if (!gotDot) { // Clamp values outside of integer range. if (sign > 0) { aToken.mInteger = int32_t(std::min(intPart, double(INT32_MAX))); } else { aToken.mInteger = int32_t(std::max(-intPart, double(INT32_MIN))); } aToken.mIntegerValid = true; } nsString& ident = aToken.mIdent; // Check for Dimension and Percentage tokens. if (c >= 0) { if (StartsIdent(c, Peek(1))) { if (GatherText(IS_IDCHAR, ident)) { type = eCSSToken_Dimension; } } else if (c == '%') { Advance(); type = eCSSToken_Percentage; value = value / 100.0f; aToken.mIntegerValid = false; } } aToken.mNumber = value; aToken.mType = type; return true; }