blob: 6b19d663b40b5cdd684c4963ec4efd45ff7ecd6a [file] [log] [blame]
// Copyright 2024 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_ANCHOR_EVALUATOR_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_ANCHOR_EVALUATOR_H_
#include <optional>
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_anchor_query_enums.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
class AnchorQuery;
class AnchorScope;
class ComputedStyleBuilder;
class ScopedCSSName;
class CORE_EXPORT AnchorEvaluator {
DISALLOW_NEW();
public:
AnchorEvaluator() = default;
// The evaluation of anchor() and anchor-size() functions is affected
// by the context they are used in. For example, it is not allowed to
// do anchor() queries "cross-axis" (e.g. left:anchor(--a top)),
// and anchor-size() queries are only valid in sizing properties.
// Queries that violate these rules instead resolve to their fallback
// values (or 0px if no fallback value exists).
//
// The default mode of AnchorEvaluator (kNone) is to return nullopt (i.e.
// fallback) for any query. This represents a context where no anchor query
// is valid, e.g. a property unrelated to insets or sizing.
//
// The values kLeft, kRight, kTop and kBottom represent the corresponding
// inset properties, and allow anchor() queries [1] (with restrictions),
// but not anchor-size() queries.
//
// The value kSize represents supported sizing properties [2], and allows
// anchor-size(), but not anchor().
//
// The current mode can be set by placing an AnchorScope object on the
// stack.
//
// [1] https://drafts.csswg.org/css-anchor-position-1/#anchor-valid
// [2] https://drafts.csswg.org/css-anchor-position-1/#anchor-size-valid
enum class Mode {
kNone,
// anchor()
kLeft,
kRight,
kTop,
kBottom,
// anchor-size()
kSize
};
// Evaluates an anchor() or anchor-size() query.
// Returns |nullopt| if the query is invalid (e.g., no targets or wrong
// axis.), in which case the fallback should be used.
virtual std::optional<LayoutUnit> Evaluate(const AnchorQuery&) = 0;
virtual void Trace(Visitor*) const;
protected:
explicit AnchorEvaluator(const ScopedCSSName* position_anchor_name)
: position_anchor_name_(position_anchor_name) {}
const ScopedCSSName* GetPositionAnchorName() const {
return position_anchor_name_;
}
Mode GetMode() const { return mode_; }
private:
friend class AnchorScope;
// The computed position-anchor in use for the current try option.
Member<const ScopedCSSName> position_anchor_name_;
// The computed position-anchor in use for the current try option.
Mode mode_ = Mode::kNone;
};
// Temporarily changes Mode, default anchor (position-anchor), and apply the
// current inset-area to modify the containing block position / size. When going
// out of scope the AnchorEvaluator is reset back to its previous state with
// caches that need to be invalidated cleared.
//
// If the anchor_evaluator is nullptr the AnchorScope should have no effect.
//
// See AnchorEvaluator::Mode for more information.
class CORE_EXPORT AnchorScope {
STACK_ALLOCATED();
public:
using Mode = AnchorEvaluator::Mode;
// Temporarily change Mode, applied inset-area and position-anchor.
AnchorScope(Mode, const ComputedStyleBuilder&, AnchorEvaluator*);
AnchorScope(Mode,
const ScopedCSSName* position_anchor_name,
AnchorEvaluator*);
// Temporarily change Mode only. Applied inset-area and position-anchor stay
// the same.
AnchorScope(Mode, AnchorEvaluator*);
~AnchorScope() {
if (anchor_evaluator_) {
anchor_evaluator_->mode_ = original_mode_;
anchor_evaluator_->position_anchor_name_ = original_position_anchor_name_;
}
}
private:
AnchorEvaluator* anchor_evaluator_ = nullptr;
const ScopedCSSName* original_position_anchor_name_ = nullptr;
Mode original_mode_ = Mode::kNone;
// TODO(329584105): Add inset-area
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_ANCHOR_EVALUATOR_H_