blob: 87167aafcd3786b99abeddd3955271d83dd40ba1 [file]
#include <rive/file.hpp>
#include <rive/artboard.hpp>
#include <rive/artboard_component_list.hpp>
#include <rive/animation/state_machine_instance.hpp>
#include <rive/viewmodel/viewmodel_instance.hpp>
#include "rive_file_reader.hpp"
#include <catch.hpp>
#include <utility>
#include <vector>
// An ArtboardComponentList skips the per-frame work of rows that would do
// nothing ("quiet" rows) until something wakes them. Under TESTING every
// skipped row pass is still run, after the pass, and aborts if it did
// anything, so the whole suite checks the skipping; these cases pin down that
// rows do go quiet and that what the host pushes into them wakes them.
using namespace rive;
namespace
{
struct RowLayout
{
float width;
float height;
float minX;
float minY;
};
std::vector<RowLayout> rowLayouts(ArtboardComponentList* list)
{
std::vector<RowLayout> rows;
for (size_t i = 0; i < list->artboardCount(); i++)
{
auto row = list->artboardInstance((int)i);
auto bounds = list->layoutBoundsForNode((int)i);
rows.push_back({row->layoutWidth(),
row->layoutHeight(),
bounds.minX,
bounds.minY});
}
return rows;
}
bool operator==(const RowLayout& a, const RowLayout& b)
{
return a.width == b.width && a.height == b.height && a.minX == b.minX &&
a.minY == b.minY;
}
// Plays "Main" in artboard_list_overrides.riv until its rows could go quiet,
// halves the artboard's width, lets the layout settle, and returns where the
// rows were before and after, with quiet rows on or off.
std::pair<std::vector<RowLayout>, std::vector<RowLayout>> resizeHost(
File* file,
bool quietRows)
{
ArtboardComponentList::sm_quietRowsEnabled = quietRows;
auto artboard = file->artboardNamed("Main");
REQUIRE(artboard != nullptr);
auto stateMachine = artboard->stateMachineAt(0);
auto viewModelId = artboard->viewModelId();
auto viewModelInstance =
viewModelId == -1 ? file->createViewModelInstance(artboard.get())
: file->createViewModelInstance(viewModelId, 0);
stateMachine->bindViewModelInstance(viewModelInstance);
stateMachine->advanceAndApply(0.1f);
auto lists = artboard->find<ArtboardComponentList>();
REQUIRE(lists.size() == 1);
auto list = lists[0];
REQUIRE(list->artboardCount() > 0);
// Longer than the one-second empty animation a state without one plays,
// which keeps its layer going until it ends.
auto skips = ArtboardComponentList::sm_quietRowSkips;
for (int i = 0; i < 90; i++)
{
stateMachine->advanceAndApply(1.0f / 60.0f);
}
CHECK((ArtboardComponentList::sm_quietRowSkips > skips) == quietRows);
for (size_t i = 0; i < list->artboardCount(); i++)
{
CHECK((list->artboardInstance((int)i)->quietHostRow() == (uint32_t)i) ==
quietRows);
}
auto before = rowLayouts(list);
artboard->width(artboard->width() * 0.5f);
for (int i = 0; i < 60; i++)
{
stateMachine->advanceAndApply(1.0f / 60.0f);
}
auto after = rowLayouts(list);
ArtboardComponentList::sm_quietRowsEnabled = true;
return {before, after};
}
} // namespace
TEST_CASE("Quiet list rows wake for layout the host pushes into them",
"[component_list]")
{
auto file = ReadRiveFile("assets/artboard_list_overrides.riv");
auto quiet = resizeHost(file.get(), true);
auto awake = resizeHost(file.get(), false);
// The resize must move the rows, or matching proves nothing.
CHECK_FALSE(quiet.first == quiet.second);
REQUIRE(quiet.second.size() == awake.second.size());
CHECK(quiet.second == awake.second);
}