mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
195 lines
5.4 KiB
C++
195 lines
5.4 KiB
C++
#include <LottieCpp/CGPath.h>
|
|
|
|
#include <cassert>
|
|
|
|
namespace lottie {
|
|
|
|
namespace {
|
|
|
|
void addPointToBoundingRect(bool *isFirst, CGRect *rect, Vector2D const *point) {
|
|
if (*isFirst) {
|
|
*isFirst = false;
|
|
|
|
rect->x = point->x;
|
|
rect->y = point->y;
|
|
rect->width = 0.0;
|
|
rect->height = 0.0;
|
|
|
|
return;
|
|
}
|
|
if (point->x > rect->x + rect->width) {
|
|
rect->width = point->x - rect->x;
|
|
}
|
|
if (point->y > rect->y + rect->height) {
|
|
rect->height = point->y - rect->y;
|
|
}
|
|
if (point->x < rect->x) {
|
|
rect->width += rect->x - point->x;
|
|
rect->x = point->x;
|
|
}
|
|
if (point->y < rect->y) {
|
|
rect->height += rect->y - point->y;
|
|
rect->y = point->y;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Vector2D transformVector(Vector2D const &v, CATransform3D const &m) {
|
|
return Vector2D(
|
|
m.m11 * v.x + m.m21 * v.y + m.m41 * 1.0,
|
|
m.m12 * v.x + m.m22 * v.y + m.m42 * 1.0
|
|
);
|
|
}
|
|
|
|
class CGPathImpl: public CGPath {
|
|
public:
|
|
CGPathImpl();
|
|
virtual ~CGPathImpl();
|
|
|
|
virtual CGRect boundingBox() const override;
|
|
|
|
virtual bool empty() const override;
|
|
|
|
virtual std::shared_ptr<CGPath> copyUsingTransform(CATransform3D const &transform) const override;
|
|
|
|
virtual void addLineTo(Vector2D const &point) override;
|
|
virtual void addCurveTo(Vector2D const &point, Vector2D const &control1, Vector2D const &control2) override;
|
|
virtual void moveTo(Vector2D const &point) override;
|
|
virtual void closeSubpath() override;
|
|
virtual void addRect(CGRect const &rect) override;
|
|
virtual void addPath(std::shared_ptr<CGPath> const &path) override;
|
|
virtual bool isEqual(CGPath *other) const override;
|
|
virtual void enumerate(std::function<void(CGPathItem const &)>) override;
|
|
|
|
private:
|
|
std::vector<CGPathItem> _items;
|
|
};
|
|
|
|
CGPathImpl::CGPathImpl() {
|
|
}
|
|
|
|
CGPathImpl::~CGPathImpl() {
|
|
}
|
|
|
|
CGRect CGPathImpl::boundingBox() const {
|
|
bool isFirst = true;
|
|
CGRect result(0.0, 0.0, 0.0, 0.0);
|
|
|
|
for (const auto &item : _items) {
|
|
switch (item.type) {
|
|
case CGPathItem::Type::MoveTo: {
|
|
addPointToBoundingRect(&isFirst, &result, &item.points[0]);
|
|
break;
|
|
}
|
|
case CGPathItem::Type::LineTo: {
|
|
addPointToBoundingRect(&isFirst, &result, &item.points[0]);
|
|
break;
|
|
}
|
|
case CGPathItem::Type::CurveTo: {
|
|
addPointToBoundingRect(&isFirst, &result, &item.points[0]);
|
|
addPointToBoundingRect(&isFirst, &result, &item.points[1]);
|
|
addPointToBoundingRect(&isFirst, &result, &item.points[2]);
|
|
break;
|
|
}
|
|
case CGPathItem::Type::Close: {
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool CGPathImpl::empty() const {
|
|
return _items.empty();
|
|
}
|
|
|
|
std::shared_ptr<CGPath> CGPathImpl::copyUsingTransform(CATransform3D const &transform) const {
|
|
auto result = std::make_shared<CGPathImpl>();
|
|
|
|
if (transform == CATransform3D::identity()) {
|
|
result->_items = _items;
|
|
return result;
|
|
}
|
|
|
|
result->_items.reserve(_items.capacity());
|
|
for (auto &sourceItem : _items) {
|
|
CGPathItem &item = result->_items.emplace_back(sourceItem.type);
|
|
item.points[0] = transformVector(sourceItem.points[0], transform);
|
|
item.points[1] = transformVector(sourceItem.points[1], transform);
|
|
item.points[2] = transformVector(sourceItem.points[2], transform);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void CGPathImpl::addLineTo(Vector2D const &point) {
|
|
CGPathItem &item = _items.emplace_back(CGPathItem::Type::LineTo);
|
|
item.points[0] = point;
|
|
}
|
|
|
|
void CGPathImpl::addCurveTo(Vector2D const &point, Vector2D const &control1, Vector2D const &control2) {
|
|
CGPathItem &item = _items.emplace_back(CGPathItem::Type::CurveTo);
|
|
item.points[0] = control1;
|
|
item.points[1] = control2;
|
|
item.points[2] = point;
|
|
}
|
|
|
|
void CGPathImpl::moveTo(Vector2D const &point) {
|
|
CGPathItem &item = _items.emplace_back(CGPathItem::Type::MoveTo);
|
|
item.points[0] = point;
|
|
}
|
|
|
|
void CGPathImpl::closeSubpath() {
|
|
_items.emplace_back(CGPathItem::Type::Close);
|
|
}
|
|
|
|
void CGPathImpl::addRect(CGRect const &rect) {
|
|
assert(false);
|
|
//CGPathAddRect(_path, nil, ::CGRectMake(rect.x, rect.y, rect.width, rect.height));
|
|
}
|
|
|
|
void CGPathImpl::addPath(std::shared_ptr<CGPath> const &path) {
|
|
if (_items.size() == 0) {
|
|
_items = std::static_pointer_cast<CGPathImpl>(path)->_items;
|
|
} else {
|
|
size_t totalItemCount = _items.size() + std::static_pointer_cast<CGPathImpl>(path)->_items.size();
|
|
if (_items.capacity() < totalItemCount) {
|
|
_items.reserve(totalItemCount);
|
|
}
|
|
for (const auto &item : std::static_pointer_cast<CGPathImpl>(path)->_items) {
|
|
_items.push_back(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CGPathImpl::isEqual(CGPath *other) const {
|
|
if (_items.size() != ((CGPathImpl *)other)->_items.size()) {
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < _items.size(); i++) {
|
|
if (_items[i] != ((CGPathImpl *)other)->_items[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CGPathImpl::enumerate(std::function<void(CGPathItem const &)> f) {
|
|
for (const auto &item : _items) {
|
|
f(item);
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<CGPath> CGPath::makePath() {
|
|
return std::static_pointer_cast<CGPath>(std::make_shared<CGPathImpl>());
|
|
}
|
|
|
|
}
|