#ifndef CC_INPUT_SCROLL_SNAP_DATA_H_
#define CC_INPUT_SCROLL_SNAP_DATA_H_
#include <vector>
#include "base/gtest_prod_util.h"
#include "cc/cc_export.h"
#include "cc/paint/element_id.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/range/range_f.h"
namespace cc {
class SnapSelectionStrategy;
enum class SnapAxis : unsigned {
kBoth,
kX,
kY,
kBlock,
kInline,
};
enum class SearchAxis : unsigned { kX, kY };
enum class SnapStrictness : unsigned { kProximity, kMandatory };
enum class SnapAlignment : unsigned { kNone, kStart, kEnd, kCenter };
struct ScrollSnapType {
ScrollSnapType()
: is_none(true),
axis(SnapAxis::kBoth),
strictness(SnapStrictness::kProximity) {}
ScrollSnapType(bool snap_type_none, SnapAxis axis, SnapStrictness strictness)
: is_none(snap_type_none), axis(axis), strictness(strictness) {}
bool operator==(const ScrollSnapType& other) const {
return is_none == other.is_none && axis == other.axis &&
strictness == other.strictness;
}
bool operator!=(const ScrollSnapType& other) const {
return !(*this == other);
}
bool is_none;
SnapAxis axis;
SnapStrictness strictness;
};
struct ScrollSnapAlign {
ScrollSnapAlign()
: alignment_block(SnapAlignment::kNone),
alignment_inline(SnapAlignment::kNone) {}
explicit ScrollSnapAlign(SnapAlignment alignment)
: alignment_block(alignment), alignment_inline(alignment) {}
ScrollSnapAlign(SnapAlignment b, SnapAlignment i)
: alignment_block(b), alignment_inline(i) {}
bool operator==(const ScrollSnapAlign& other) const {
return alignment_block == other.alignment_block &&
alignment_inline == other.alignment_inline;
}
bool operator!=(const ScrollSnapAlign& other) const {
return !(*this == other);
}
SnapAlignment alignment_block;
SnapAlignment alignment_inline;
};
class SnapSearchResult {
public:
SnapSearchResult() {}
SnapSearchResult(float offset, const gfx::RangeF& range);
void Clip(float max_snap, float max_visible);
void Union(const SnapSearchResult& other);
float snap_offset() const { return snap_offset_; }
void set_snap_offset(float offset) { snap_offset_ = offset; }
gfx::RangeF visible_range() const { return visible_range_; }
void set_visible_range(const gfx::RangeF& range);
ElementId element_id() const { return element_id_; }
void set_element_id(ElementId id) { element_id_ = id; }
private:
float snap_offset_;
gfx::RangeF visible_range_;
ElementId element_id_;
};
struct SnapAreaData {
static const int kInvalidScrollPosition = -1;
SnapAreaData() {}
SnapAreaData(const ScrollSnapAlign& align,
const gfx::RectF& rec,
bool msnap,
ElementId id)
: scroll_snap_align(align), rect(rec), must_snap(msnap), element_id(id) {}
bool operator==(const SnapAreaData& other) const {
return (other.element_id == element_id) &&
(other.scroll_snap_align == scroll_snap_align) &&
(other.rect == rect) && (other.must_snap == must_snap);
}
bool operator!=(const SnapAreaData& other) const { return !(*this == other); }
ScrollSnapAlign scroll_snap_align;
gfx::RectF rect;
bool must_snap;
ElementId element_id;
};
struct TargetSnapAreaElementIds {
TargetSnapAreaElementIds() = default;
TargetSnapAreaElementIds(ElementId x_id, ElementId y_id) : x(x_id), y(y_id) {}
bool operator==(const TargetSnapAreaElementIds& other) const {
return (other.x == x) && (other.y == y);
}
bool operator!=(const TargetSnapAreaElementIds& other) const {
return !(*this == other);
}
ElementId x;
ElementId y;
};
typedef std::vector<SnapAreaData> SnapAreaList;
class CC_EXPORT SnapContainerData {
public:
SnapContainerData();
explicit SnapContainerData(ScrollSnapType type);
SnapContainerData(ScrollSnapType type,
const gfx::RectF& rect,
const gfx::PointF& max);
SnapContainerData(const SnapContainerData& other);
SnapContainerData(SnapContainerData&& other);
~SnapContainerData();
SnapContainerData& operator=(const SnapContainerData& other);
SnapContainerData& operator=(SnapContainerData&& other);
bool operator==(const SnapContainerData& other) const {
return (other.scroll_snap_type_ == scroll_snap_type_) &&
(other.rect_ == rect_) && (other.max_position_ == max_position_) &&
(other.proximity_range_ == proximity_range_) &&
(other.snap_area_list_ == snap_area_list_) &&
(other.target_snap_area_element_ids_ ==
target_snap_area_element_ids_);
}
bool operator!=(const SnapContainerData& other) const {
return !(*this == other);
}
bool FindSnapPosition(const SnapSelectionStrategy& strategy,
gfx::PointF* snap_position,
TargetSnapAreaElementIds* target_element_ids,
const ElementId& active_element_id = ElementId()) const;
const TargetSnapAreaElementIds& GetTargetSnapAreaElementIds() const;
bool SetTargetSnapAreaElementIds(TargetSnapAreaElementIds ids);
void AddSnapAreaData(SnapAreaData snap_area_data);
size_t size() const { return snap_area_list_.size(); }
const SnapAreaData& at(size_t index) const { return snap_area_list_[index]; }
void set_scroll_snap_type(ScrollSnapType type) { scroll_snap_type_ = type; }
ScrollSnapType scroll_snap_type() const { return scroll_snap_type_; }
void set_rect(const gfx::RectF& rect) { rect_ = rect; }
gfx::RectF rect() const { return rect_; }
void set_max_position(gfx::PointF position) { max_position_ = position; }
gfx::PointF max_position() const { return max_position_; }
void set_proximity_range(const gfx::PointF& range) {
proximity_range_ = range;
}
gfx::PointF proximity_range() const { return proximity_range_; }
private:
absl::optional<SnapSearchResult> FindClosestValidAreaInternal(
SearchAxis axis,
const SnapSelectionStrategy& strategy,
const SnapSearchResult& cross_axis_snap_result,
const ElementId& active_element_id,
bool should_consider_covering = true) const;
absl::optional<SnapSearchResult> FindClosestValidArea(
SearchAxis axis,
const SnapSelectionStrategy& strategy,
const SnapSearchResult& cross_axis_snap_result,
const ElementId& active_element_id) const;
bool FindSnapPositionForMutualSnap(const SnapSelectionStrategy& strategy,
gfx::PointF* snap_position) const;
absl::optional<SnapSearchResult> GetTargetSnapAreaSearchResult(
const SnapSelectionStrategy& strategy,
SearchAxis axis) const;
SnapSearchResult GetSnapSearchResult(SearchAxis axis,
const SnapAreaData& data) const;
bool IsSnapportCoveredOnAxis(SearchAxis axis,
float current_offset,
const gfx::RectF& area_rect) const;
void UpdateSnapAreaForTesting(ElementId element_id,
SnapAreaData snap_area_data);
ScrollSnapType scroll_snap_type_;
gfx::RectF rect_;
gfx::PointF max_position_;
gfx::PointF proximity_range_;
std::vector<SnapAreaData> snap_area_list_;
TargetSnapAreaElementIds target_snap_area_element_ids_;
FRIEND_TEST_ALL_PREFIXES(ScrollSnapDataTest, SnapToFocusedElementHorizontal);
FRIEND_TEST_ALL_PREFIXES(ScrollSnapDataTest, SnapToFocusedElementVertical);
FRIEND_TEST_ALL_PREFIXES(ScrollSnapDataTest, SnapToFocusedElementBoth);
};
CC_EXPORT std::ostream& operator<<(std::ostream&, const SnapAreaData&);
CC_EXPORT std::ostream& operator<<(std::ostream&, const SnapContainerData&);
}
#endif