blob: 1ae42c3340577f33911712cf1bcb45f7a22c83dc [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CC_INPUT_SCROLL_SNAP_DATA_H_
#define CC_INPUT_SCROLL_SNAP_DATA_H_
#include <vector>
#include "cc/cc_export.h"
#include "ui/gfx/geometry/scroll_offset.h"
namespace cc {
// See https://www.w3.org/TR/css-scroll-snap-1/#snap-axis
enum class SnapAxis : unsigned {
kBoth,
kX,
kY,
kBlock,
kInline,
};
// See https://www.w3.org/TR/css-scroll-snap-1/#snap-strictness
// TODO(sunyunjia): Add kNone for SnapStrictness to match the spec.
// crbug.com/791663
enum class SnapStrictness : unsigned { kProximity, kMandatory };
// See https://www.w3.org/TR/css-scroll-snap-1/#scroll-snap-align
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);
}
// Whether the scroll-snap-type is none or the snap-strictness field has the
// value None.
// TODO(sunyunjia): Consider combining is_none with SnapStrictness.
bool is_none;
SnapAxis axis;
SnapStrictness strictness;
};
struct ScrollSnapAlign {
ScrollSnapAlign()
: alignmentX(SnapAlignment::kNone), alignmentY(SnapAlignment::kNone) {}
explicit ScrollSnapAlign(SnapAlignment alignment)
: alignmentX(alignment), alignmentY(alignment) {}
ScrollSnapAlign(SnapAlignment x, SnapAlignment y)
: alignmentX(x), alignmentY(y) {}
bool operator==(const ScrollSnapAlign& other) const {
return alignmentX == other.alignmentX && alignmentY == other.alignmentY;
}
bool operator!=(const ScrollSnapAlign& other) const {
return !(*this == other);
}
SnapAlignment alignmentX;
SnapAlignment alignmentY;
};
// Snap area is a bounding box that could be snapped to when a scroll happens in
// its scroll container.
// This data structure describes the data needed for SnapCoordinator if we want
// to snap to this snap area.
struct SnapAreaData {
// kInvalidScrollOffset is used to mark that the snap_position on a specific
// axis is not applicable, thus should not be considered when snapping on that
// axis. This is because the snap area has SnapAlignmentNone on that axis.
static const int kInvalidScrollPosition = -1;
SnapAreaData() {}
SnapAreaData(SnapAxis axis, gfx::ScrollOffset position, bool msnap)
: snap_axis(axis), snap_position(position), must_snap(msnap) {}
bool operator==(const SnapAreaData& other) const {
return (other.snap_axis == snap_axis) &&
(other.snap_position == snap_position) &&
(other.must_snap == must_snap);
}
bool operator!=(const SnapAreaData& other) const { return !(*this == other); }
// The axes along which the area has specified snap positions.
SnapAxis snap_axis;
// The scroll_position to snap the area at the specified alignment in that
// axis.
// This is in the same coordinate with blink's scroll position, which is the
// location of the top/left of the scroll viewport in the top/left of the
// overflow rect.
gfx::ScrollOffset snap_position;
// Whether this area has scroll-snap-stop: always.
// See https://www.w3.org/TR/css-scroll-snap-1/#scroll-snap-stop
bool must_snap;
// TODO(sunyunjia): Add fields for visibility requirement and large area
// snapping.
};
// Snap container is a scroll container that has non-'none' value for
// scroll-snap-type. It can be snapped to one of its snap areas when a scroll
// happens.
// This data structure describes the data needed for SnapCoordinator to perform
// snapping in the snap container.
class CC_EXPORT SnapContainerData {
public:
SnapContainerData();
explicit SnapContainerData(ScrollSnapType type);
SnapContainerData(ScrollSnapType type, gfx::ScrollOffset 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.max_position_ == max_position_) &&
(other.snap_area_list_ == snap_area_list_);
}
bool operator!=(const SnapContainerData& other) const {
return !(*this == other);
}
gfx::ScrollOffset FindSnapPosition(const gfx::ScrollOffset& current_position,
bool should_snap_on_x,
bool should_snap_on_y) const;
void AddSnapAreaData(SnapAreaData snap_area_data);
size_t size() const { return snap_area_list_.size(); }
const SnapAreaData& at(int 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_max_position(gfx::ScrollOffset position) {
max_position_ = position;
}
gfx::ScrollOffset max_position() const { return max_position_; }
private:
// Specifies whether a scroll container is a scroll snap container, how
// strictly it snaps, and which axes are considered.
// See https://www.w3.org/TR/css-scroll-snap-1/#scroll-snap-type for details.
ScrollSnapType scroll_snap_type_;
// The maximal scroll position of the SnapContainer, in the same coordinate
// with blink's scroll position.
gfx::ScrollOffset max_position_;
// The SnapAreaData for the snap areas in this snap container. When a scroll
// happens, we iterate through the snap_area_list to find the best snap
// position.
std::vector<SnapAreaData> snap_area_list_;
};
CC_EXPORT std::ostream& operator<<(std::ostream&, const SnapAreaData&);
CC_EXPORT std::ostream& operator<<(std::ostream&, const SnapContainerData&);
} // namespace cc
#endif // CC_INPUT_SCROLL_SNAP_DATA_H_