public virtual MatchResultInfo Match(VisualElement element, ref RuleMatcher matcher, int selectorIndex)
        {
            if (element == null)
            {
                return(default(MatchResultInfo));
            }
            bool          match    = true;
            StyleSelector selector = matcher.complexSelector.selectors[selectorIndex];
            int           count    = selector.parts.Length;

            int  triggerPseudoStateMask   = 0;
            int  dependencyPseudoMask     = 0;
            bool failedOnlyOnPseudoStates = true;

            for (int i = 0; i < count; i++)
            {
                bool isPartMatch = MatchSelectorPart(element, selector, selector.parts[i]);

                if (!isPartMatch)
                {
                    if (selector.parts[i].type == StyleSelectorType.PseudoClass)
                    {
                        // if the element had those flags defined, it would match this selector
                        triggerPseudoStateMask |= selector.pseudoStateMask;
                        // if the element didnt' have those flags, it would match this selector
                        dependencyPseudoMask |= selector.negatedPseudoStateMask;
                    }
                    else
                    {
                        failedOnlyOnPseudoStates = false;
                    }
                }
                else
                {
                    if (selector.parts[i].type == StyleSelectorType.PseudoClass)
                    {
                        // the element matches this selector because it has those flags
                        dependencyPseudoMask |= selector.pseudoStateMask;
                        // the element matches this selector because it does not have those flags
                        triggerPseudoStateMask |= selector.negatedPseudoStateMask;
                    }
                }

                match &= isPartMatch;
            }

            var result = new MatchResultInfo()
            {
                success = match
            };

            if (match || failedOnlyOnPseudoStates)
            {
                result.triggerPseudoMask    = (PseudoStates)triggerPseudoStateMask;
                result.dependencyPseudoMask = (PseudoStates)dependencyPseudoMask;
            }

            return(result);
        }
Example #2
0
 public override void OnProcessMatchResult(UIElements.VisualElement element, ref StyleSheets.RuleMatcher matcher, ref MatchResultInfo matchInfo)
 {
     element.triggerPseudoMask    |= matchInfo.triggerPseudoMask;
     element.dependencyPseudoMask |= matchInfo.dependencyPseudoMask;
 }
        private bool MatchRightToLeft(VisualElement element, ref RuleMatcher matcher)
        {
            // see https://speakerdeck.com/constellation/css-jit-just-in-time-compiled-css-selectors-in-webkit for
            // a detailed explaination of the algorithm

            var           current   = element;
            int           nextIndex = matcher.complexSelector.selectors.Length - 1;
            VisualElement saved     = null;
            int           savedIdx  = -1;

            // go backward
            while (nextIndex >= 0)
            {
                if (current == null)
                {
                    break;
                }

                MatchResultInfo matchInfo = Match(current, ref matcher, nextIndex);
                OnProcessMatchResult(current, ref matcher, ref matchInfo);

                if (!matchInfo.success)
                {
                    // if we have a descendent relationship, keep trying on the parent
                    // ie. "div span", div failed on this element, try on the parent
                    // happens earlier than the backtracking saving below
                    if (nextIndex < matcher.complexSelector.selectors.Length - 1 &&
                        matcher.complexSelector.selectors[nextIndex + 1].previousRelationship == StyleSelectorRelationship.Descendent)
                    {
                        current = current.parent;
                        continue;
                    }

                    // otherwise, if there's a previous relationship, it's a 'child' one. backtrack from the saved point and try again
                    // ie.  for "#x > .a .b", #x failed, backtrack to .a on the saved element
                    if (saved != null)
                    {
                        current   = saved;
                        nextIndex = savedIdx;
                        continue;
                    }

                    break;
                }

                // backtracking save
                // for "a > b c": we're considering the b matcher. c's previous relationship is Descendent
                // save the current element parent to try to match b again
                if (nextIndex < matcher.complexSelector.selectors.Length - 1 &&
                    matcher.complexSelector.selectors[nextIndex + 1].previousRelationship == StyleSelectorRelationship.Descendent)
                {
                    saved    = current.parent;
                    savedIdx = nextIndex;
                }

                // from now, the element is a match
                if (--nextIndex < 0)
                {
                    //TODO: abort if return false
                    if (OnRuleMatchedElement(matcher, element))
                    {
                        return(true);
                    }
                }
                current = current.parent;
            }
            return(false);
        }
 public virtual void OnProcessMatchResult(VisualElement element, ref RuleMatcher matcher, ref MatchResultInfo matchInfo)
 {
 }