blob: 4298c3c09cf766306599dcc92dee78687098a439 [file] [log] [blame]
/*
* Copyright 2022 Rive
*/
#include "rive/factory.hpp"
#include "rive/render_text.hpp"
#include "skia_rive_fontmgr.hpp"
#include "include/core/SkTypeface.h"
#include "include/core/SkFont.h"
#include "include/core/SkPath.h"
class SkiaRenderFont : public rive::RenderFont {
public:
sk_sp<SkTypeface> m_Typeface;
SkiaRenderFont(sk_sp<SkTypeface> tf) : m_Typeface(std::move(tf)) {}
std::vector<Axis> getAxes() const override;
std::vector<Coord> getCoords() const override;
rive::rcp<rive::RenderFont> makeAtCoords(rive::Span<const Coord>) const override;
rive::RawPath getPath(rive::GlyphID) const override;
};
std::vector<rive::RenderFont::Axis> SkiaRenderFont::getAxes() const {
std::vector<rive::RenderFont::Axis> axes;
const int count = m_Typeface->getVariationDesignParameters(nullptr, 0);
if (count > 0) {
std::vector<SkFontParameters::Variation::Axis> src(count);
(void)m_Typeface->getVariationDesignParameters(src.data(), count);
axes.resize(count);
for (int i = 0; i < count; ++i) {
axes[i] = { src[i].tag, src[i].min, src[i].def, src[i].max };
}
}
return axes;
}
std::vector<rive::RenderFont::Coord> SkiaRenderFont::getCoords() const {
int count = m_Typeface->getVariationDesignPosition(nullptr, 0);
std::vector<SkFontArguments::VariationPosition::Coordinate> skcoord(count);
m_Typeface->getVariationDesignPosition(skcoord.data(), count);
std::vector<rive::RenderFont::Coord> coords(count);
for (int i = 0; i < count; ++i) {
coords[i] = { skcoord[i].axis, skcoord[i].value };
}
return coords;
}
rive::rcp<rive::RenderFont> SkiaRenderFont::makeAtCoords(rive::Span<const Coord> coords) const {
const int count = (int)coords.size();
SkAutoSTArray<16, SkFontArguments::VariationPosition::Coordinate> storage(count);
for (size_t i = 0; i < count; ++i) {
storage[i].axis = coords[i].axis;
storage[i].value = coords[i].value;
}
SkFontArguments args;
args.setVariationDesignPosition({storage.get(), count});
auto face = m_Typeface->makeClone(args);
if (face->uniqueID() == m_Typeface->uniqueID()) {
auto self = const_cast<SkiaRenderFont*>(this);
return rive::rcp<rive::RenderFont>(rive::safe_ref(self));
} else {
return rive::rcp<rive::RenderFont>(new SkiaRenderFont(std::move(face)));
}
}
static inline rive::Vec2D rv(SkPoint p) { return rive::Vec2D(p.fX, p.fY); }
static void setupFont(SkFont* font) {
font->setLinearMetrics(true);
font->setBaselineSnap(false);
font->setHinting(SkFontHinting::kNone);
}
rive::RawPath SkiaRenderFont::getPath(rive::GlyphID glyph) const {
SkFont font(m_Typeface, 1.0f);
setupFont(&font);
SkPath skpath;
font.getPath(glyph, &skpath);
rive::RawPath rpath;
SkPath::RawIter iter(skpath);
SkPoint pts[4];
bool done = false;
while (!done) {
switch (iter.next(pts)) {
case SkPath::kMove_Verb: rpath.move (rv(pts[0])); break;
case SkPath::kLine_Verb: rpath.line (rv(pts[1])); break;
case SkPath::kQuad_Verb: rpath.quad (rv(pts[1]), rv(pts[2])); break;
case SkPath::kConic_Verb: rpath.quad (rv(pts[1]), rv(pts[2])); break; // TODO: convert
case SkPath::kCubic_Verb: rpath.cubic(rv(pts[1]), rv(pts[2]), rv(pts[3])); break;
case SkPath::kClose_Verb: rpath.close(); break;
case SkPath::kDone_Verb: done = true; break;
}
}
return rpath;
}
///////////////////////////////////////////////////////////
rive::rcp<rive::RenderFont> SkiaRiveFontMgr::decodeFont(rive::Span<const uint8_t> data) {
auto tf = SkTypeface::MakeDefault(); // ignoring data for now
return rive::rcp<rive::RenderFont>(new SkiaRenderFont(std::move(tf)));
}
rive::rcp<rive::RenderFont> SkiaRiveFontMgr::findFont(const char name[]) {
auto tf = SkTypeface::MakeFromName(name, SkFontStyle());
if (!tf) {
tf = SkTypeface::MakeDefault();
}
return rive::rcp<rive::RenderFont>(new SkiaRenderFont(std::move(tf)));
}
static float shapeRun(rive::RenderGlyphRun* grun, const rive::RenderTextRun& trun,
const rive::Unichar text[], size_t textOffset, float origin) {
grun->font = trun.font;
grun->size = trun.size;
grun->startTextIndex = textOffset;
grun->glyphs.resize(trun.unicharCount);
grun->xpos.resize(trun.unicharCount + 1);
const int count = SkToInt(trun.unicharCount);
SkiaRenderFont* rfont = static_cast<SkiaRenderFont*>(trun.font.get());
rfont->m_Typeface->unicharsToGlyphs(text + textOffset, count, grun->glyphs.data());
SkFont font(rfont->m_Typeface, grun->size);
setupFont(&font);
// We get 'widths' from skia, but then turn them into xpos
// this will write count values, but xpos has count+1 slots
font.getWidths(grun->glyphs.data(), count, grun->xpos.data());
for (auto& xp : grun->xpos) {
auto width = xp;
xp = origin;
origin += width;
}
return grun->xpos.data()[count];
}
std::vector<rive::RenderGlyphRun>
SkiaRiveFontMgr::shapeText(rive::Span<const rive::Unichar> text,
rive::Span<const rive::RenderTextRun> truns) {
std::vector<rive::RenderGlyphRun> gruns;
// sanity check
size_t count = 0;
for (const auto& tr : truns) {
count += tr.unicharCount;
}
if (count > text.size()) {
return gruns; // not enough text, so abort
}
gruns.resize(truns.size());
int i = 0;
size_t offset = 0;
float origin = 0;
for (const auto& tr : truns) {
origin = shapeRun(&gruns[i], tr, text.data(), offset, origin);
offset += tr.unicharCount;
i += 1;
}
return gruns;
}