blob: 5c1c9c96c95289f1a396dd79aa271462c20b326a [file] [log] [blame]
// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_GEOMETRY_SIZE_H_
#define FLUTTER_IMPELLER_GEOMETRY_SIZE_H_
#include <algorithm>
#include <cmath>
#include <limits>
#include <ostream>
#include <string>
#include "impeller/geometry/scalar.h"
namespace impeller {
template <class T>
struct TSize {
using Type = T;
Type width = {};
Type height = {};
constexpr TSize() {}
constexpr TSize(Type width, Type height) : width(width), height(height) {}
template <class U>
explicit constexpr TSize(const TSize<U>& other)
: TSize(static_cast<Type>(other.width), static_cast<Type>(other.height)) {
}
static constexpr TSize MakeWH(Type width, Type height) {
return TSize{width, height};
}
static constexpr TSize Infinite() {
return TSize{std::numeric_limits<Type>::max(),
std::numeric_limits<Type>::max()};
}
constexpr TSize operator*(Scalar scale) const {
return {width * scale, height * scale};
}
constexpr TSize operator/(Scalar scale) const {
return {static_cast<Scalar>(width) / scale,
static_cast<Scalar>(height) / scale};
}
constexpr TSize operator/(const TSize& s) const {
return {width / s.width, height / s.height};
}
constexpr bool operator==(const TSize& s) const {
return s.width == width && s.height == height;
}
constexpr bool operator!=(const TSize& s) const {
return s.width != width || s.height != height;
}
constexpr TSize operator+(const TSize& s) const {
return {width + s.width, height + s.height};
}
constexpr TSize operator-(const TSize& s) const {
return {width - s.width, height - s.height};
}
constexpr TSize operator-() const { return {-width, -height}; }
constexpr TSize Min(const TSize& o) const {
return {
std::min(width, o.width),
std::min(height, o.height),
};
}
constexpr TSize Max(const TSize& o) const {
return {
std::max(width, o.width),
std::max(height, o.height),
};
}
constexpr Type MaxDimension() const { return std::max(width, height); }
constexpr TSize Abs() const { return {std::fabs(width), std::fabs(height)}; }
constexpr TSize Floor() const {
return {std::floor(width), std::floor(height)};
}
constexpr TSize Ceil() const { return {std::ceil(width), std::ceil(height)}; }
constexpr TSize Round() const {
return {std::round(width), std::round(height)};
}
constexpr Type Area() const { return width * height; }
/// Returns true if either of the width or height are 0, negative, or NaN.
constexpr bool IsEmpty() const { return !(width > 0 && height > 0); }
constexpr bool IsSquare() const { return width == height; }
template <class U>
static constexpr TSize Ceil(const TSize<U>& other) {
return TSize{static_cast<Type>(std::ceil(other.width)),
static_cast<Type>(std::ceil(other.height))};
}
constexpr size_t MipCount() const {
constexpr size_t minimum_mip = 1u;
if (IsEmpty()) {
return minimum_mip;
}
size_t result = std::max(ceil(log2(width)), ceil(log2(height)));
return std::max(result, minimum_mip);
}
};
// RHS algebraic operations with arithmetic types.
template <class T, class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr TSize<T> operator*(U s, const TSize<T>& p) {
return p * s;
}
template <class T, class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr TSize<T> operator/(U s, const TSize<T>& p) {
return {static_cast<T>(s) / p.x, static_cast<T>(s) / p.y};
}
using Size = TSize<Scalar>;
using ISize = TSize<int64_t>;
static_assert(sizeof(Size) == 2 * sizeof(Scalar));
} // namespace impeller
namespace std {
template <class T>
inline std::ostream& operator<<(std::ostream& out,
const impeller::TSize<T>& s) {
out << "(" << s.width << ", " << s.height << ")";
return out;
}
} // namespace std
#endif // FLUTTER_IMPELLER_GEOMETRY_SIZE_H_