// Copyright 2021 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CHECK_PSEUDO_HAS_ARGUMENT_CONTEXT_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CHECK_PSEUDO_HAS_ARGUMENT_CONTEXT_H_ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/css/css_selector.h" #include "third_party/blink/renderer/core/dom/element.h" namespace blink { enum CheckPseudoHasArgumentTraversalScope { … }; // Unique value of each traversal type. The value can be used as a key of // fast reject filter cache. // // These 3 values are stored by dividing the 4-byte field by: // - depth limit : 0 ~ 13 (14bits) // - adjacent distance limit : 14 ~ 27 (14 bits) // - traversal scope : 28 ~ 31 (4 bits) CheckPseudoHasArgumentTraversalType; class CORE_EXPORT CheckPseudoHasArgumentContext { … }; // Subtree traversal iterator class for :has() argument checking. To solve the // following issues, this traversal uses the reversed DOM tree order, and // provides a functionality to limit the traversal depth. // // 1. Cache 'Matched' and 'NotMatched' candidate elements while checking the // :has() argument selector. // // SelectorChecker::CheckPseudoHas() can get all 'Matched' candidates (elements // that can be a :has() anchor element) while checking the :has() argument // selector on an element in the traversal range. And when it found the // elements, it caches those as 'Matched' candidates. // By following the reversed DOM tree order, we can get these two advantages. // - Maximize the number of 'Matched' candidates that can be cached while // checking :has() argument selector. // - Can cache 'NotMatched' candidates (elements that cannot be a :has() anchor // element) in case of these 4 traversal scope types: // - kSubtree // - kAllNextSiblings // - kOneNextSiblingSubtree // - kAllNextSiblingSubtrees // While traversing, we can cache an element as 'NotMatched' if the element is // not cached as 'Matched' because it must be cached as 'Matched' previously // if it is a :has() anchor element. (Reversed DOM tree order guarantees that // all the descendants, next siblings and next sibling subtrees were already // traversed) // // 2. Prevent unnecessary subtree traversal when it can be limited with // child combinator or direct adjacent combinator. // // We can limit the tree traversal range when we count the leftmost combinators // of a :has() argument selector. For example, when we check ':has(> .a > .b)' // on an element, instead of traversing all the descendants of the :has() anchor // element, we can limit the traversal only for the elements at depth 2 of the // :has() anchor element. When we check ':has(+ .a > .b)', we can limit the // traversal only for the child elements of the direct adjacent sibling of the // :has() anchor element. To implement this, we need a way to limit the // traversal depth and a way to check whether the iterator is currently at the // fixed depth or not. class CORE_EXPORT CheckPseudoHasArgumentTraversalIterator { … }; } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CHECK_PSEUDO_HAS_ARGUMENT_CONTEXT_H_