#include "ThorVGCanvasImpl.h" namespace lottie { namespace { void tvgPath(CanvasPathEnumerator const &enumeratePath, tvg::Shape *shape) { enumeratePath([&](PathCommand const &command) { switch (command.type) { case PathCommandType::MoveTo: { shape->moveTo(command.points[0].x, command.points[0].y); break; } case PathCommandType::LineTo: { shape->lineTo(command.points[0].x, command.points[0].y); break; } case PathCommandType::CurveTo: { shape->cubicTo(command.points[0].x, command.points[0].y, command.points[1].x, command.points[1].y, command.points[2].x, command.points[2].y); break; } case PathCommandType::Close: { shape->close(); break; } } }); } tvg::Matrix tvgTransform(lottie::Transform2D const &transform) { tvg::Matrix result; result.e11 = transform.rows().columns[0][0]; result.e21 = transform.rows().columns[0][1]; result.e31 = transform.rows().columns[0][2]; result.e12 = transform.rows().columns[1][0]; result.e22 = transform.rows().columns[1][1]; result.e32 = transform.rows().columns[1][2]; result.e13 = transform.rows().columns[2][0]; result.e23 = transform.rows().columns[2][1]; result.e33 = transform.rows().columns[2][2]; return result; } } void ThorVGCanvasImpl::initializeOnce() { tvg::Initializer::init(0); } ThorVGCanvasImpl::ThorVGCanvasImpl(int width, int height, int bytesPerRow) : _transform(lottie::Transform2D::identity()) { _canvas = tvg::SwCanvas::gen(); _bytesPerRow = bytesPerRow; _backingData = (uint32_t *)malloc(_bytesPerRow * height); memset(_backingData, 0, _bytesPerRow * height); _canvas->target(_backingData, _bytesPerRow / 4, width, height, tvg::SwCanvas::ARGB8888); } ThorVGCanvasImpl::~ThorVGCanvasImpl() { } void ThorVGCanvasImpl::saveState() { _stateStack.push_back(_transform); } void ThorVGCanvasImpl::restoreState() { if (_stateStack.empty()) { assert(false); return; } _transform = _stateStack[_stateStack.size() - 1]; _stateStack.pop_back(); } void ThorVGCanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) { auto shape = tvg::Shape::gen(); tvgPath(enumeratePath, shape.get()); shape->transform(tvgTransform(_transform)); shape->fill((int)(color.r * 255.0), (int)(color.g * 255.0), (int)(color.b * 255.0), (int)(color.a * 255.0)); shape->fill(fillRule == lottie::FillRule::EvenOdd ? tvg::FillRule::EvenOdd : tvg::FillRule::Winding); _canvas->push(std::move(shape)); } void ThorVGCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { auto shape = tvg::Shape::gen(); tvgPath(enumeratePath, shape.get()); shape->transform(tvgTransform(_transform)); auto fill = tvg::LinearGradient::gen(); fill->linear(start.x, start.y, end.x, end.y); std::vector colors; for (size_t i = 0; i < gradient.colors().size(); i++) { const auto &color = gradient.colors()[i]; tvg::Fill::ColorStop colorStop; colorStop.offset = gradient.locations()[i]; colorStop.r = (int)(color.r * 255.0); colorStop.g = (int)(color.g * 255.0); colorStop.b = (int)(color.b * 255.0); colorStop.a = (int)(color.a * 255.0); colors.push_back(colorStop); } fill->colorStops(colors.data(), (uint32_t)colors.size()); shape->fill(std::move(fill)); shape->fill(fillRule == lottie::FillRule::EvenOdd ? tvg::FillRule::EvenOdd : tvg::FillRule::Winding); _canvas->push(std::move(shape)); } void ThorVGCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, Vector2D const ¢er, float radius) { auto shape = tvg::Shape::gen(); tvgPath(enumeratePath, shape.get()); shape->transform(tvgTransform(_transform)); auto fill = tvg::RadialGradient::gen(); fill->radial(center.x, center.y, radius); std::vector colors; for (size_t i = 0; i < gradient.colors().size(); i++) { const auto &color = gradient.colors()[i]; tvg::Fill::ColorStop colorStop; colorStop.offset = gradient.locations()[i]; colorStop.r = (int)(color.r * 255.0); colorStop.g = (int)(color.g * 255.0); colorStop.b = (int)(color.b * 255.0); colorStop.a = (int)(color.a * 255.0); colors.push_back(colorStop); } fill->colorStops(colors.data(), (uint32_t)colors.size()); shape->fill(std::move(fill)); shape->fill(fillRule == lottie::FillRule::EvenOdd ? tvg::FillRule::EvenOdd : tvg::FillRule::Winding); _canvas->push(std::move(shape)); } void ThorVGCanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) { auto shape = tvg::Shape::gen(); tvgPath(enumeratePath, shape.get()); shape->transform(tvgTransform(_transform)); shape->strokeFill((int)(color.r * 255.0), (int)(color.g * 255.0), (int)(color.b * 255.0), (int)(color.a * 255.0)); shape->strokeWidth(lineWidth); switch (lineJoin) { case lottie::LineJoin::Miter: { shape->strokeJoin(tvg::StrokeJoin::Miter); break; } case lottie::LineJoin::Round: { shape->strokeJoin(tvg::StrokeJoin::Round); break; } case lottie::LineJoin::Bevel: { shape->strokeJoin(tvg::StrokeJoin::Bevel); break; } default: { shape->strokeJoin(tvg::StrokeJoin::Bevel); break; } } switch (lineCap) { case lottie::LineCap::Butt: { shape->strokeCap(tvg::StrokeCap::Butt); break; } case lottie::LineCap::Round: { shape->strokeCap(tvg::StrokeCap::Round); break; } case lottie::LineCap::Square: { shape->strokeCap(tvg::StrokeCap::Square); break; } default: { shape->strokeCap(tvg::StrokeCap::Square); break; } } if (!dashPattern.empty()) { std::vector intervals; intervals.reserve(dashPattern.size()); for (auto value : dashPattern) { intervals.push_back(value); } shape->strokeDash(intervals.data(), (uint32_t)intervals.size()); //TODO:phase } _canvas->push(std::move(shape)); } void ThorVGCanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { } void ThorVGCanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { } void ThorVGCanvasImpl::concatenate(lottie::Transform2D const &transform) { _transform = transform * _transform; } void ThorVGCanvasImpl::flush() { _canvas->draw(); _canvas->sync(); _statsNumStrokes = 0; } }