blob: 46fea411a90e0901f2fd76d70e74a2c64298a775 [file] [log] [blame]
#include "rive/shapes/metrics_path.hpp"
#include "rive/renderer.hpp"
#include "rive/math/raw_path.hpp"
#include "rive/math/contour_measure.hpp"
#include <iostream>
using namespace rive;
void MetricsPath::rewind()
{
for (auto ptr : m_Paths)
{
delete ptr;
}
m_Paths.clear();
m_Contour.reset(nullptr);
m_RawPath.rewind();
m_ComputedLengthTransform = Mat2D();
m_ComputedLength = 0;
}
MetricsPath::~MetricsPath() { rewind(); }
void MetricsPath::addPath(CommandPath* path, const Mat2D& transform)
{
MetricsPath* metricsPath = static_cast<MetricsPath*>(path);
m_ComputedLength += metricsPath->computeLength(transform);
// We need to copy the data to avoid contention between multiple uses of the same path
// for example when the same path is added as localPath and worldPath
auto metricsPathCopy = new OnlyMetricsPath();
metricsPathCopy->m_Contour = metricsPath->m_Contour;
metricsPathCopy->m_RawPath = metricsPath->m_RawPath;
metricsPathCopy->m_ComputedLength = metricsPath->m_ComputedLength;
m_Paths.emplace_back(metricsPathCopy);
}
RawPath::Iter MetricsPath::addToRawPath(RawPath& rawPath, const Mat2D& transform) const
{
return rawPath.addPath(m_RawPath, &transform);
}
void MetricsPath::moveTo(float x, float y)
{
assert(m_RawPath.points().size() == 0);
m_RawPath.move({x, y});
}
void MetricsPath::lineTo(float x, float y) { m_RawPath.line({x, y}); }
void MetricsPath::cubicTo(float ox, float oy, float ix, float iy, float x, float y)
{
m_RawPath.cubic({ox, oy}, {ix, iy}, {x, y});
}
void MetricsPath::close()
{
// Should we pass the close() to our m_RawPath ???
}
float MetricsPath::computeLength(const Mat2D& transform)
{
// Only compute if our pre-computed length is not valid
if (!m_Contour || transform != m_ComputedLengthTransform)
{
m_ComputedLengthTransform = transform;
m_Contour = ContourMeasureIter(m_RawPath * transform).next();
m_ComputedLength = m_Contour ? m_Contour->length() : 0;
}
return m_ComputedLength;
}
void MetricsPath::trim(float startLength, float endLength, bool moveTo, RawPath* result)
{
assert(endLength >= startLength);
if (!m_Paths.empty())
{
m_Paths.front()->trim(startLength, endLength, moveTo, result);
return;
}
if (!m_Contour)
{
// All the contours were 0 length, so there's nothing to segment.
return;
}
// TODO: if we can change the signature of MetricsPath and/or trim() to speak native
// rawpaths, we wouldn't need this temporary copy (since ContourMeasure speaks
// native rawpaths).
RawPath tmp;
m_Contour->getSegment(startLength, endLength, result, moveTo);
}
RenderMetricsPath::RenderMetricsPath(rcp<RenderPath> path) : m_RenderPath(std::move(path)) {}
void RenderMetricsPath::addPath(CommandPath* path, const Mat2D& transform)
{
MetricsPath::addPath(path, transform);
m_RenderPath->addPath(path->renderPath(), transform);
}
void RenderMetricsPath::rewind()
{
MetricsPath::rewind();
m_RenderPath->rewind();
}
void RenderMetricsPath::moveTo(float x, float y)
{
MetricsPath::moveTo(x, y);
m_RenderPath->moveTo(x, y);
}
void RenderMetricsPath::lineTo(float x, float y)
{
MetricsPath::lineTo(x, y);
m_RenderPath->lineTo(x, y);
}
void RenderMetricsPath::cubicTo(float ox, float oy, float ix, float iy, float x, float y)
{
MetricsPath::cubicTo(ox, oy, ix, iy, x, y);
m_RenderPath->cubicTo(ox, oy, ix, iy, x, y);
}
void RenderMetricsPath::close()
{
MetricsPath::close();
m_RenderPath->close();
}
void RenderMetricsPath::fillRule(FillRule value) { m_RenderPath->fillRule(value); }