public override bool OnReadValue(Style styleBlock, Css.Value value, int start, out int size)
        {
            // Check if it's inherit or initial:
            if (value is Css.Keywords.Initial || value is Css.Keywords.Inherit)
            {
                // Apply it!
                size = 1;

                if (SetInfo != null)
                {
                    // Indicate that we've been set:
                    SetInfo.Set = true;
                }

                styleBlock[RawProperty] = value;

                return(true);
            }

            Css.Spec.Value spec = RawProperty.Specification;

            if (spec.OnReadValue(styleBlock, value, start, out size))
            {
                // Apply it!
                if (SetInfo != null)
                {
                    // Indicate that we've been set:
                    SetInfo.Set = true;
                }

                if (size == 1)
                {
                    styleBlock[RawProperty] = value[start];
                }
                else
                {
                    // Chop out a segment:
                    Css.ValueSet set = new Css.ValueSet(new Css.Value[size]);

                    for (int i = 0; i < size; i++)
                    {
                        set[i] = value[start + i];
                    }

                    // Apply:
                    styleBlock[RawProperty] = set;
                }

                return(true);
            }

            size = 0;
            return(false);
        }
        /// <summary>Loads the given segment of the given value.</summary>
        private static SupportsQuery LoadSection(Value value, ref int i, int endInclusive)
        {
            Value currentValue = value[i];

            if (currentValue == null || currentValue == Css.Value.Empty)
            {
                return(null);
            }

            // Is it an expression?
            ValueSet expr = currentValue as ValueSet;

            SupportsQuery current;

            if (expr == null)
            {
                // Always textual here:
                string token = currentValue.Text;

                if (token == "not")
                {
                    i++;
                    current = new SupportsQueryNot(LoadSection(value, ref i, endInclusive));
                }
                else
                {
                    current = null;
                }
            }
            else
            {
                if (expr.Count == 2 && expr[1] is ValueSet)
                {
                    // Nested functions:
                    int nestedI = 0;
                    current = LoadSection(expr, ref nestedI, 1);
                }
                else
                {
                    // Got e.g. (min-width:400px) etc.
                    // Essentially it's a feature in brackets.
                    current = LoadPropertyExpression(expr);
                }
            }

            // Check for 'and'/'or'
            if ((i + 1) <= endInclusive)
            {
                currentValue = value[i + 1];

                if (currentValue != null && currentValue != Css.Value.Empty)
                {
                    if (currentValue.Text == "and")
                    {
                        // Got the 'and' keyword!
                        i += 2;

                        return(new SupportsQueryAnd(current, LoadSection(value, ref i, endInclusive)));
                    }
                    else if (currentValue.Text == "or")
                    {
                        // Got the 'or' keyword!
                        i += 2;

                        return(new SupportsQueryList(new SupportsQuery[] { current, LoadSection(value, ref i, endInclusive) }));
                    }
                }
            }

            return(current);
        }
Exemple #3
0
        /// <summary>Reads a function with the given lowercase name. There must be a bracket at the current read head.</summary>
        public Css.Value ReadFunction(string name)
        {
            // Read off the open bracket:
            Read();

            // Get the global instance for the given function name (lowercase):
            CssFunction globalInstance = name == "" ? null : CssFunctions.Get(name);

            // Read the args:
            Css.Value parameters = null;

            if (globalInstance == null)
            {
                // Unsupported function.
                parameters = ReadValue();
            }
            else
            {
                // Set literal value:
                if (globalInstance.LiteralValue)
                {
                    parameters = ReadLiteralValue();
                }
                else
                {
                    parameters = ReadValue();
                }
            }

            // Skip any junk (which may be e.g. after a quote):
            SkipJunk();

            // Read off the close bracket:
            Read();

            if (name == "")
            {
                // This occurs with nested brackets - it's just a set.
                return(parameters);
            }

            if (globalInstance == null)
            {
                // Don't know what this function is - act like it's not even there.
                return(null);
            }

            // Copy the global instance:
            CssFunction result = globalInstance.Copy() as CssFunction;

            // Make sure params are a set:
            ValueSet set = parameters as ValueSet;

            if (set == null)
            {
                // It's a single value, or null

                if (parameters != null)
                {
                    // Push the single value:
                    result.Values = new Css.Value[] { parameters };
                }
            }
            else
            {
                // Apply the parameters:
                result.Values = set.Values;
            }

            // Tell it that it's ready:
            result.OnValueReady(this);

            // Ok:
            return(result);
        }
Exemple #4
0
        /// <summary>Converts a value to a rule. Note that it can be a set of rules (RuleSet).</summary>
        public static Rule ConvertToRule(Rule parentRule, Css.Value value, StyleSheet sheet, out Rule[] ruleSet)
        {
            ruleSet = null;

            if (value == null)
            {
                // Nothing else.
                return(null);
            }

            // Is it an @ rule? Note that they can actually be 'nested' inside an,array,of,selectors (happens with @media)
            AtRuleUnit atRule = value[0] as AtRuleUnit;

            if (atRule != null)
            {
                // Let the @ rule handle the value:
                return(atRule.AtRule.LoadRule(parentRule, sheet, value));
            }

            // One or more selectors followed by a block unit.
            // Get the block:
            int max = value.Count - 1;

            SelectorBlockUnit block = value[max] as SelectorBlockUnit;

            if (block == null)
            {
                // Try as a set instead:
                ValueSet set = value[max] as ValueSet;

                if (set == null)
                {
                    // Invalid/ unrecognised selector block. Ignore it.
                    return(null);
                }

                // Get last one in the set:
                block = set[set.Count - 1] as SelectorBlockUnit;

                // still null?
                if (block == null)
                {
                    // Invalid/ unrecognised selector block. Ignore it.
                    return(null);
                }

                // Check again for an @rule:
                Css.Value v0 = value[0];

                if (v0 != null && v0[0] is AtRuleUnit)
                {
                    // Got an at rule!
                    atRule = v0[0] as AtRuleUnit;

                    return(atRule.AtRule.LoadRule(parentRule, sheet, value));
                }

                // Clear last one:
                set[set.Count - 1] = null;
            }
            else
            {
                // Clear the block from the value:
                value[max] = null;
            }

            // Get the style object:
            Style style = block.Style;

            // Read the selector(s):
            List <Selector> into = new List <Selector>();

            ReadSelectors(sheet, value, into);

            if (into.Count == 0)
            {
                return(null);
            }

            if (into.Count != 1)
            {
                ruleSet = new Rule[into.Count];
            }

            // Got a specifity override? -spark-specifity:x
            Css.Value specifityOverride = null;
            int       specOverride      = -1;

            if (style.Properties.TryGetValue(Css.Properties.SparkSpecifity.GlobalProperty, out specifityOverride))
            {
                // Yep! Pull the integer value:
                specOverride = specifityOverride.GetInteger(null, null);
            }

            for (int i = 0; i < into.Count; i++)
            {
                // Get it:
                Selector s = into[i];

                // Create the rule:
                StyleRule rule = new StyleRule(style);
                rule.ParentStyleSheet = sheet;
                rule.Selector         = s;
                s.Rule = rule;

                // Must use a copy of the style if its a secondary selector.
                // This is because the 'specifity' of CSS properties is defined by how specific
                // a selector is. So, when there's multiple selectors, we have to clone the style.

                Style currentStyle = i == 0?style:style.Clone();

                // Apply the selectors specifity to the style:
                int specifity = s.Specifity;

                if (specOverride != -1)
                {
                    specifity = specOverride;
                }

                foreach (KeyValuePair <CssProperty, Css.Value> kvp in currentStyle.Properties)
                {
                    // Apply:
                    kvp.Value.SetSpecifity(specifity);
                }

                if (ruleSet == null)
                {
                    return(rule);
                }

                ruleSet[i] = rule;
            }

            return(null);
        }
Exemple #5
0
        /// <summary>The lexer must be in literal mode for this. Reads a value from the stream.
        /// May read a whole set or null if there's a ) or ; at the read head.</summary>
        public Css.Value ReadValue()
        {
            Value        result       = null;
            List <Value> values       = null;
            ValueSet     bottomSet    = null;
            List <Value> bottomValues = null;
            bool         important    = false;

            // Skip junk:
            SkipJunk();


            char current = Peek();

            while (current != ')' && current != '}' && current != '\0' && current != ';')
            {
                if (current == ',')
                {
                    // read it off:
                    Read();

                    // Setup bottom set, if we need to:
                    if (bottomSet == null)
                    {
                        bottomSet        = new ValueSet();
                        bottomSet.Spacer = ",";
                        bottomValues     = new List <Value>();
                    }

                    //"Push" values into bottom set.
                    if (result != null)
                    {
                        if (values != null)
                        {
                            // Result is a set.
                            ApplyList(result, values);
                            values = null;
                        }

                        bottomValues.Add(result);

                        result = null;
                    }
                }
                else if (current == '!')
                {
                    // Special lookout for "important".
                    // We don't want it to create a set.
                    Read();

                    // Skip whitespaces.
                    SkipJunk();

                    // Read:
                    Css.Value importantTest = ReadSingleValue();

                    // Skip whitespaces.
                    SkipJunk();

                    // Got important?
                    if (importantTest is Css.Keywords.ImportantKeyword)
                    {
                        // Important!
                        important = true;
                    }
                    else
                    {
                        // Act like we added both ! and importantTest.
                        // Note that there might have been no spaces before it; they could be one value (but it's unlikely).

                        if (result == null)
                        {
                            result = new TextUnit("!");
                        }
                        else if (values == null)
                        {
                            values = new List <Value>();
                            values.Add(result);
                            result = new ValueSet();
                            values.Add(new TextUnit("!"));
                        }
                        else
                        {
                            values.Add(new TextUnit("!"));
                        }

                        if (importantTest != null)
                        {
                            if (values == null)
                            {
                                values = new List <Value>();
                                values.Add(result);
                                result = new ValueSet();
                                values.Add(importantTest);
                            }
                            else
                            {
                                values.Add(importantTest);
                            }
                        }
                    }

                    // Update current:
                    current = Peek();

                    continue;
                }

                if (result == null)
                {
                    result = ReadSingleValue();

                    if (result == null)
                    {
                        // Invalid rule

                        // Skip whitespaces.
                        SkipJunk();

                        // Update current:
                        current = Peek();

                        if (current == '}' || current == ';')
                        {
                            AtRuleMode = false;
                            Read();
                        }

                        return(null);
                    }
                }
                else if (values == null)
                {
                    values = new List <Value>();
                    values.Add(result);
                    result = new ValueSet();
                    values.Add(ReadSingleValue());
                }
                else
                {
                    values.Add(ReadSingleValue());
                }

                if (SelectorMode && !AtRuleMode)
                {
                    // Check if we have a whitespace:
                    if (Peek() == ' ')
                    {
                        if (values == null)
                        {
                            values = new List <Value>();
                            values.Add(result);
                            result = new ValueSet();
                            values.Add(new TextUnit(" "));
                        }
                        else
                        {
                            values.Add(new TextUnit(" "));
                        }
                    }
                }

                // Skip whitespaces.
                SkipJunk();

                // Update current:
                current = Peek();
            }

            if (current == '}' || current == ';')
            {
                AtRuleMode = false;
                Read();
            }

            if (values != null)
            {
                // Update result with the values set:
                ApplyList(result, values);
            }

            if (bottomSet != null)
            {
                // Push result into it:
                bottomValues.Add(result);
                ApplyList(bottomSet, bottomValues);
                result = bottomSet;
            }

            if (important && result != null)
            {
                result.SetImportant(true);
            }

            return(result);
        }