blob: cb8fa8292439c26772dc5293b41931f1945a7b9c [file] [log] [blame]
#include <rive/file.hpp>
#include <rive/node.hpp>
#include <rive/shapes/rectangle.hpp>
#include <rive/shapes/shape.hpp>
#include <rive/shapes/paint/stroke.hpp>
#include <rive/shapes/paint/solid_color.hpp>
#include <rive/shapes/paint/stroke_effect.hpp>
#include <rive/shapes/paint/color.hpp>
#include <utils/no_op_renderer.hpp>
#include "rive_file_reader.hpp"
#include <catch.hpp>
#include <cstdio>
TEST_CASE("A 0 scale path will trim with no crash", "[file]")
{
auto file = ReadRiveFile("assets/trim.riv");
auto artboard = file->artboard();
auto node = artboard->find<rive::Node>("I");
REQUIRE(node != nullptr);
REQUIRE(node->scaleX() != 0);
REQUIRE(node->scaleY() != 0);
artboard->advance(0.0f);
rive::NoOpRenderer renderer;
artboard->draw(&renderer);
// Now set scale to 0 and make sure it doesn't crash.
node->scaleX(0.0f);
node->scaleY(0.0f);
artboard->advance(0.0f);
artboard->draw(&renderer);
}
static void testRawPath(rive::Artboard* artboard,
std::string shapeName,
std::vector<rive::PathVerb> verbs)
{
auto node = artboard->find<rive::Shape>(shapeName);
rive::Stroke* stroke;
for (auto& child : node->children())
{
if (child->is<rive::Stroke>())
{
stroke = child->as<rive::Stroke>();
break;
}
}
REQUIRE(stroke != nullptr);
REQUIRE(stroke->is<rive::Stroke>());
auto effect = stroke->effect();
REQUIRE(effect != nullptr);
auto effectPath = effect->effectPath();
REQUIRE(effectPath != nullptr);
auto rawPath = effectPath->rawPath();
REQUIRE(rawPath != nullptr);
size_t index = 0;
for (auto iter : *rawPath)
{
REQUIRE(verbs.size() > index);
rive::PathVerb verb = std::get<0>(iter);
REQUIRE(verb == verbs[index]);
index++;
}
REQUIRE(verbs.size() == index);
}
TEST_CASE("Different types of trim paths", "[trim]")
{
auto file = ReadRiveFile("assets/trim_path.riv");
auto artboard = file->artboard("artboard-2");
REQUIRE(artboard != nullptr);
artboard->updateComponents();
// Closed Path with start at 50%, end at 100% and offset at 75% doesn't add
// an extra move between end and start of path
std::vector<rive::PathVerb> verbs1 = {rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line};
testRawPath(artboard, "clipped-rect", verbs1);
// Open Path with start at 50%, end at 100% and offset at 75% does add
// an extra move between end and start of path
std::vector<rive::PathVerb> verbs2 = {rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::move,
rive::PathVerb::line};
testRawPath(artboard, "clipped-rect-open", verbs2);
// Multiple closed paths with start at 0%, end at 50% and offset at 90% do
// move between paths
std::vector<rive::PathVerb> verbs3 = {rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::close};
testRawPath(artboard, "clipped-rect-multi", verbs3);
// Multiple closed paths with trim path synced with start at 0%, end at 50%
// and offset at 90% do move between paths
std::vector<rive::PathVerb> verbs4 = {rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line};
testRawPath(artboard, "clipped-rect-multi-sync", verbs4);
// Open Shape with trim path at 0% 100% 0% does not close
std::vector<rive::PathVerb> verbs5 = {rive::PathVerb::move,
rive::PathVerb::cubic,
rive::PathVerb::cubic};
testRawPath(artboard, "pen-shape", verbs5);
// Closed Shape with trim path at 0% 100% 0% does close
std::vector<rive::PathVerb> verbs6 = {rive::PathVerb::move,
rive::PathVerb::cubic,
rive::PathVerb::cubic,
rive::PathVerb::cubic,
rive::PathVerb::close};
testRawPath(artboard, "pen-shape-close", verbs6);
// Mixed shapes with open and closed paths respect their close value
std::vector<rive::PathVerb> verbs7 = {rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::close,
rive::PathVerb::move,
rive::PathVerb::cubic,
rive::PathVerb::cubic,
rive::PathVerb::cubic};
testRawPath(artboard, "mixed-shapes", verbs7);
// Mixed shapes with synced trim path with open and closed paths respect
// their close value
std::vector<rive::PathVerb> verbs8 = {rive::PathVerb::move,
rive::PathVerb::cubic,
rive::PathVerb::cubic,
rive::PathVerb::move,
rive::PathVerb::cubic,
rive::PathVerb::cubic,
rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line};
testRawPath(artboard, "mixed-shapes-synced", verbs8);
// Mixed shapes with synced trim path with open and closed paths respect
// their close value at 100%
std::vector<rive::PathVerb> verbs9 = {
rive::PathVerb::move, rive::PathVerb::cubic, rive::PathVerb::cubic,
rive::PathVerb::move, rive::PathVerb::cubic, rive::PathVerb::cubic,
rive::PathVerb::move, rive::PathVerb::line, rive::PathVerb::line,
rive::PathVerb::line, rive::PathVerb::line, rive::PathVerb::line,
rive::PathVerb::line, rive::PathVerb::close, rive::PathVerb::move,
rive::PathVerb::line, rive::PathVerb::line, rive::PathVerb::line,
rive::PathVerb::line, rive::PathVerb::line, rive::PathVerb::close};
testRawPath(artboard, "mixed-shapes-synced-100", verbs9);
// Mixed shapes with open and closed paths respect their close value at 100%
std::vector<rive::PathVerb> verbs10 = {rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::move,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::line,
rive::PathVerb::close,
rive::PathVerb::move,
rive::PathVerb::cubic,
rive::PathVerb::cubic,
rive::PathVerb::cubic};
testRawPath(artboard, "mixed-shapes-100", verbs10);
}