Example #1
0
        //  * 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;
        }