0c2bcce996
This is safe because count == 0 will produce an empty path. Bug: oss-fuzz:8213 Change-Id: Ie3b546c614ba22eef1ba16a182016c2edd0bd641 Reviewed-on: https://skia-review.googlesource.com/127323 Reviewed-by: Kevin Lubick <kjlubick@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
165 lines
4.9 KiB
C++
165 lines
4.9 KiB
C++
/*
|
|
* Copyright 2018 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "SkottieAdapter.h"
|
|
|
|
#include "SkMatrix.h"
|
|
#include "SkottieValue.h"
|
|
#include "SkPath.h"
|
|
#include "SkRRect.h"
|
|
#include "SkSGGradient.h"
|
|
#include "SkSGPath.h"
|
|
#include "SkSGRect.h"
|
|
#include "SkSGTransform.h"
|
|
#include "SkSGTrimEffect.h"
|
|
|
|
#include <cmath>
|
|
|
|
namespace skottie {
|
|
|
|
RRectAdapter::RRectAdapter(sk_sp<sksg::RRect> wrapped_node)
|
|
: fRRectNode(std::move(wrapped_node)) {}
|
|
|
|
void RRectAdapter::apply() {
|
|
// BM "position" == "center position"
|
|
auto rr = SkRRect::MakeRectXY(SkRect::MakeXYWH(fPosition.x() - fSize.width() / 2,
|
|
fPosition.y() - fSize.height() / 2,
|
|
fSize.width(), fSize.height()),
|
|
fRadius.width(),
|
|
fRadius.height());
|
|
fRRectNode->setRRect(rr);
|
|
}
|
|
|
|
TransformAdapter::TransformAdapter(sk_sp<sksg::Matrix> matrix)
|
|
: fMatrixNode(std::move(matrix)) {}
|
|
|
|
void TransformAdapter::apply() {
|
|
SkMatrix t = SkMatrix::MakeTrans(-fAnchorPoint.x(), -fAnchorPoint.y());
|
|
|
|
t.postScale(fScale.x() / 100, fScale.y() / 100); // 100% based
|
|
t.postRotate(fRotation);
|
|
t.postTranslate(fPosition.x(), fPosition.y());
|
|
// TODO: skew
|
|
|
|
fMatrixNode->setMatrix(t);
|
|
}
|
|
|
|
PolyStarAdapter::PolyStarAdapter(sk_sp<sksg::Path> wrapped_node, Type t)
|
|
: fPathNode(std::move(wrapped_node))
|
|
, fType(t) {}
|
|
|
|
void PolyStarAdapter::apply() {
|
|
const auto count = SkScalarTruncToInt(fPointCount);
|
|
const auto arc = sk_ieee_float_divide(SK_ScalarPI * 2, count);
|
|
|
|
const auto pt_on_circle = [](const SkPoint& c, SkScalar r, SkScalar a) {
|
|
return SkPoint::Make(c.x() + r * std::cos(a),
|
|
c.y() + r * std::sin(a));
|
|
};
|
|
|
|
// TODO: inner/outer "roundness"?
|
|
|
|
SkPath poly;
|
|
|
|
auto angle = SkDegreesToRadians(fRotation);
|
|
poly.moveTo(pt_on_circle(fPosition, fOuterRadius, angle));
|
|
|
|
for (int i = 0; i < count; ++i) {
|
|
if (fType == Type::kStar) {
|
|
poly.lineTo(pt_on_circle(fPosition, fInnerRadius, angle + arc * 0.5f));
|
|
}
|
|
angle += arc;
|
|
poly.lineTo(pt_on_circle(fPosition, fOuterRadius, angle));
|
|
}
|
|
|
|
poly.close();
|
|
fPathNode->setPath(poly);
|
|
}
|
|
|
|
GradientAdapter::GradientAdapter(sk_sp<sksg::Gradient> grad, size_t stopCount)
|
|
: fGradient(std::move(grad))
|
|
, fStopCount(stopCount) {}
|
|
|
|
void GradientAdapter::apply() {
|
|
this->onApply();
|
|
|
|
// |fColorStops| holds |fStopCount| x [ pos, r, g, g ] + ? x [ pos, alpha ]
|
|
|
|
if (fColorStops.size() < fStopCount * 4 || ((fColorStops.size() - fStopCount * 4) % 2)) {
|
|
SkDebugf("!! Invalid gradient stop array size: %zu", fColorStops.size());
|
|
return;
|
|
}
|
|
|
|
std::vector<sksg::Gradient::ColorStop> stops;
|
|
|
|
// TODO: merge/lerp opacity stops
|
|
const auto csEnd = fColorStops.cbegin() + fStopCount * 4;
|
|
for (auto cs = fColorStops.cbegin(); cs != csEnd; cs += 4) {
|
|
const auto pos = cs[0];
|
|
const VectorValue rgb({ cs[1], cs[2], cs[3] });
|
|
|
|
stops.push_back({ pos, ValueTraits<VectorValue>::As<SkColor>(rgb) });
|
|
}
|
|
|
|
fGradient->setColorStops(std::move(stops));
|
|
}
|
|
|
|
LinearGradientAdapter::LinearGradientAdapter(sk_sp<sksg::LinearGradient> grad, size_t stopCount)
|
|
: INHERITED(std::move(grad), stopCount) {}
|
|
|
|
void LinearGradientAdapter::onApply() {
|
|
auto* grad = static_cast<sksg::LinearGradient*>(fGradient.get());
|
|
grad->setStartPoint(this->startPoint());
|
|
grad->setEndPoint(this->endPoint());
|
|
}
|
|
|
|
RadialGradientAdapter::RadialGradientAdapter(sk_sp<sksg::RadialGradient> grad, size_t stopCount)
|
|
: INHERITED(std::move(grad), stopCount) {}
|
|
|
|
void RadialGradientAdapter::onApply() {
|
|
auto* grad = static_cast<sksg::RadialGradient*>(fGradient.get());
|
|
grad->setStartCenter(this->startPoint());
|
|
grad->setEndCenter(this->startPoint());
|
|
grad->setStartRadius(0);
|
|
grad->setEndRadius(SkPoint::Distance(this->startPoint(), this->endPoint()));
|
|
}
|
|
|
|
TrimEffectAdapter::TrimEffectAdapter(sk_sp<sksg::TrimEffect> trimEffect)
|
|
: fTrimEffect(std::move(trimEffect)) {
|
|
SkASSERT(fTrimEffect);
|
|
}
|
|
|
|
void TrimEffectAdapter::apply() {
|
|
// BM semantics: start/end are percentages, offset is "degrees" (?!).
|
|
const auto start = fStart / 100,
|
|
end = fEnd / 100,
|
|
offset = fOffset / 360;
|
|
|
|
auto startT = SkTMin(start, end) + offset,
|
|
stopT = SkTMax(start, end) + offset;
|
|
auto mode = SkTrimPathEffect::Mode::kNormal;
|
|
|
|
if (stopT - startT < 1) {
|
|
startT -= SkScalarFloorToScalar(startT);
|
|
stopT -= SkScalarFloorToScalar(stopT);
|
|
|
|
if (startT > stopT) {
|
|
SkTSwap(startT, stopT);
|
|
mode = SkTrimPathEffect::Mode::kInverted;
|
|
}
|
|
} else {
|
|
startT = 0;
|
|
stopT = 1;
|
|
}
|
|
|
|
fTrimEffect->setStart(startT);
|
|
fTrimEffect->setStop(stopT);
|
|
fTrimEffect->setMode(mode);
|
|
}
|
|
|
|
} // namespace skottie
|