// * If aVariantMask is VARIANT_NUMBER, this function parses the // <number-multiplicative-expression> production. // * If aVariantMask does not contain VARIANT_NUMBER, this function // parses the <value-multiplicative-expression> production. // * Otherwise (VARIANT_NUMBER and other bits) this function parses // whichever one of the productions matches ***and modifies // aVariantMask*** to reflect which one it has parsed by either // removing VARIANT_NUMBER or removing all other bits. // It does so iteratively, but builds the correct recursive data // structure. // This function always consumes *trailing* whitespace when it returns // true; whether there was any such whitespace is returned in the // aHadFinalWS parameter. internal bool ParseCalcMultiplicativeExpression(ref nsCSSValue aValue, ref int32_t aVariantMask, ref bool aHadFinalWS) { Debug.Assert(aVariantMask != 0, "unexpected variant mask"); bool gotValue = false; // already got the part with the unit bool afterDivision = false; nsCSSValue storage = aValue; for (;;) { int32_t variantMask = 0; if (afterDivision || gotValue) { variantMask = VARIANT_NUMBER; } else { variantMask = aVariantMask | VARIANT_NUMBER; } if (!ParseCalcTerm(ref storage, ref variantMask)) return false; Debug.Assert(variantMask != 0, "ParseCalcTerm did not set variantMask appropriately"); if ((variantMask & VARIANT_NUMBER) != 0) { // Simplify the value immediately so we can check for division by // zero. var ops = new ReduceNumberCalcOps(); float number = CommonUtil.ComputeCalc(storage, ops); if (number == 0.0 && afterDivision) return false; storage.SetFloatValue(number, nsCSSUnit.Number); } else { gotValue = true; if (storage != aValue) { // Simplify any numbers in the Times_L position (which are // not simplified by the check above). Debug.Assert(storage == aValue.GetArrayValue().Item(1), "unexpected relationship to current storage"); nsCSSValue leftValue = aValue.GetArrayValue().Item(0); var ops = new ReduceNumberCalcOps(); float number = CommonUtil.ComputeCalc(leftValue, ops); leftValue.SetFloatValue(number, nsCSSUnit.Number); } } bool hadWS = RequireWhitespace(); if (!GetToken(false)) { aHadFinalWS = hadWS; break; } nsCSSUnit unit = 0; if (mToken.IsSymbol('*')) { unit = gotValue ? nsCSSUnit.CalcTimesR : nsCSSUnit.CalcTimesL; afterDivision = false; } else if (mToken.IsSymbol('/')) { unit = nsCSSUnit.CalcDivided; afterDivision = true; } else { UngetToken(); aHadFinalWS = hadWS; break; } nsCSSValue[] arr = new nsCSSValue[2]; arr[0] = aValue; storage = arr[1]; aValue.SetArrayValue(arr, unit); } // Adjust aVariantMask (see comments above function) to reflect which // option we took. if ((aVariantMask & VARIANT_NUMBER) != 0) { if (gotValue) { aVariantMask &= ~((int32_t)(VARIANT_NUMBER)); } else { aVariantMask = VARIANT_NUMBER; } } else { if (!gotValue) { // We had to find a value, but we didn't. return false; } } return true; }