blob: 3e9f60b0ac314fc2bbc55f9a9ef43f89267e2bfc [file] [log] [blame]
// Copyright 2022 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_CONTAINER_SELECTOR_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CONTAINER_SELECTOR_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/media_query_exp.h"
#include "third_party/blink/renderer/core/layout/geometry/axis.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
namespace blink {
class Element;
// Not to be confused with regular selectors. This refers to container
// selection by e.g. a given name, or by implicit container selection
// according to the queried features.
//
// https://drafts.csswg.org/css-contain-3/#container-rule
class CORE_EXPORT ContainerSelector {
public:
ContainerSelector() = default;
explicit ContainerSelector(WTF::HashTableDeletedValueType) {
WTF::HashTraits<AtomicString>::ConstructDeletedValue(name_);
}
explicit ContainerSelector(PhysicalAxes physical_axes)
: physical_axes_(physical_axes) {}
ContainerSelector(AtomicString name,
PhysicalAxes physical_axes,
LogicalAxes logical_axes)
: name_(std::move(name)),
physical_axes_(physical_axes),
logical_axes_(logical_axes) {}
ContainerSelector(AtomicString name, const MediaQueryExpNode&);
bool IsHashTableDeletedValue() const {
return WTF::HashTraits<AtomicString>::IsDeletedValue(name_);
}
bool operator==(const ContainerSelector& o) const {
return (name_ == o.name_) && (physical_axes_ == o.physical_axes_) &&
(logical_axes_ == o.logical_axes_) &&
(has_style_query_ == o.has_style_query_) &&
(has_sticky_query_ == o.has_sticky_query_) &&
(has_snap_query_ == o.has_snap_query_);
}
bool operator!=(const ContainerSelector& o) const { return !(*this == o); }
unsigned GetHash() const;
const AtomicString& Name() const { return name_; }
// Given the specified writing mode, return the EContainerTypes required
// for this selector to match.
unsigned Type(WritingMode) const;
bool SelectsSizeContainers() const {
return physical_axes_ != kPhysicalAxesNone ||
logical_axes_ != kLogicalAxesNone;
}
bool SelectsStyleContainers() const { return has_style_query_; }
bool SelectsStickyContainers() const { return has_sticky_query_; }
bool SelectsSnapContainers() const { return has_snap_query_; }
bool SelectsStateContainers() const {
return SelectsStickyContainers() || SelectsSnapContainers();
}
bool HasUnknownFeature() const { return has_unknown_feature_; }
PhysicalAxes GetPhysicalAxes() const { return physical_axes_; }
LogicalAxes GetLogicalAxes() const { return logical_axes_; }
private:
AtomicString name_;
PhysicalAxes physical_axes_{kPhysicalAxesNone};
LogicalAxes logical_axes_{kLogicalAxesNone};
bool has_style_query_{false};
bool has_sticky_query_{false};
bool has_snap_query_{false};
bool has_unknown_feature_{false};
};
class ScopedContainerSelector
: public GarbageCollected<ScopedContainerSelector> {
public:
ScopedContainerSelector(ContainerSelector selector,
const TreeScope* tree_scope)
: selector_(selector), tree_scope_(tree_scope) {}
unsigned GetHash() const {
unsigned hash = selector_.GetHash();
WTF::AddIntToHash(hash, WTF::GetHash(tree_scope_.Get()));
return hash;
}
bool operator==(const ScopedContainerSelector& other) const {
return selector_ == other.selector_ && tree_scope_ == other.tree_scope_;
}
void Trace(Visitor* visitor) const;
private:
ContainerSelector selector_;
WeakMember<const TreeScope> tree_scope_;
};
struct ScopedContainerSelectorHashTraits
: WTF::MemberHashTraits<ScopedContainerSelector> {
static unsigned GetHash(
const Member<ScopedContainerSelector>& scoped_selector) {
return scoped_selector->GetHash();
}
static bool Equal(const Member<ScopedContainerSelector>& a,
const Member<ScopedContainerSelector>& b) {
return *a == *b;
}
static constexpr bool kSafeToCompareToEmptyOrDeleted = false;
};
// Helper needed to allow calling Find() with a ScopedContainerSelector instead
// of Member<ScopedContainerSelector>
struct ScopedContainerSelectorHashTranslator {
STATIC_ONLY(ScopedContainerSelectorHashTranslator);
static unsigned GetHash(const ScopedContainerSelector& selector) {
return selector.GetHash();
}
static bool Equal(const Member<ScopedContainerSelector>& a,
const ScopedContainerSelector& b) {
return a && *a == b;
}
};
} // namespace blink
namespace WTF {
template <>
struct HashTraits<blink::ContainerSelector>
: SimpleClassHashTraits<blink::ContainerSelector> {
static unsigned GetHash(const blink::ContainerSelector& selector) {
return selector.GetHash();
}
static constexpr bool kSafeToCompareToEmptyOrDeleted =
HashTraits<AtomicString>::kSafeToCompareToEmptyOrDeleted;
static const bool kEmptyValueIsZero = false;
};
} // namespace WTF
namespace blink {
using ContainerSelectorCache = HeapHashMap<Member<ScopedContainerSelector>,
Member<Element>,
ScopedContainerSelectorHashTraits>;
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CONTAINER_SELECTOR_H_