43#include <unordered_map>
59SkString preshapedFontName(
const std::string_view& fontName) {
70 std::vector<SkPoint> verts, in_tan, out_tan;
80 SkASSERT(verts.size() == in_tan.size());
81 SkASSERT(verts.size() == out_tan.size());
86 std::vector<Contour> contours(1);
91 if (!contours.back().verts.empty()) {
92 contours.emplace_back();
94 contours.back().add(pts[0], {0, 0}, {0, 0});
97 SkASSERT(contours.back().size() > 0);
98 contours.back().closed =
true;
101 SkASSERT(contours.back().size() > 0);
102 SkASSERT(pts[0] == contours.back().verts.back());
103 contours.back().add(pts[1], {0, 0}, {0, 0});
106 SkASSERT(contours.back().size() > 0);
107 SkASSERT(pts[0] == contours.back().verts.back());
110 contours.back().out_tan.back() = cubic[1] - cubic[0];
111 contours.back().add(cubic[3], cubic[2] - cubic[3], {0, 0});
114 SkASSERT(contours.back().size() > 0);
115 SkASSERT(pts[0] == contours.back().verts.back());
116 contours.back().out_tan.back() = pts[1] - pts[0];
117 contours.back().add(pts[3], pts[2] - pts[3], {0, 0});
120 SkDebugf(
"Unexpected conic verb!\n");
125 auto ptsToLottie = [](
const std::vector<SkPoint> v,
SkArenaAlloc& alloc) {
126 std::vector<Value> vec(v.size());
127 for (
size_t i = 0; i < v.size(); ++i) {
129 vec[i] =
ArrayValue(fields, std::size(fields), alloc);
132 return ArrayValue(vec.data(), vec.size(), alloc);
135 std::vector<Value> jcontours(contours.size());
136 for (
size_t i = 0; i < contours.size(); ++i) {
138 {
StringValue(
"v", alloc), ptsToLottie(contours[i].verts, alloc) },
139 {
StringValue(
"i", alloc), ptsToLottie(contours[i].in_tan, alloc) },
140 {
StringValue(
"o", alloc), ptsToLottie(contours[i].out_tan, alloc) },
158 jcontours[i] =
ObjectValue(fields, std::size(fields), alloc);
175 return ObjectValue(fields_data, std::size(fields_data), alloc);
186 void addGlyph(
const std::string_view& font_name,
SkUnichar id,
const SkFont& font,
188 std::vector<GlyphRec>& font_glyphs =
189 fFontGlyphs.emplace(font_name, std::vector<GlyphRec>()).first->second;
192 for (
const auto& rec : font_glyphs) {
199 if (!font.getPath(glyph, &path)) {
204 std::cerr <<
"Glyph ID %d could not be converted to a path, discarding.";
208 font.getWidths(&glyph, 1, &
width);
211 const float scale = 100 / font.getSize();
213 font_glyphs.push_back({
220 std::tuple<Value, Value> toLottie(
SkArenaAlloc& alloc,
const Value& orig_fonts)
const {
221 auto find_font_info = [&](
const std::string& font_name) ->
const ObjectValue* {
222 if (
const ArrayValue* jlist = orig_fonts[
"list"]) {
223 for (
const auto& jfont : *jlist) {
225 if (font_name == jname->begin()) {
240 std::vector<Value> fonts, chars;
242 for (
const auto& font : fFontGlyphs) {
243 const ObjectValue* orig_font = find_font_info(font.first);
247 const SkString font_name = preshapedFontName(font.first);
248 orig_font->
writable(
"fName", alloc) =
250 fonts.push_back(*orig_font);
252 for (
const auto& glyph : font.second) {
259 {
StringValue(
"fFamily", alloc), (*orig_font)[
"fFamily"] },
260 {
StringValue(
"style" , alloc), (*orig_font)[
"fStyle"] },
263 {
StringValue(
"data" , alloc), pathToLottie(glyph.fPath, alloc) },
266 chars.push_back(
ObjectValue(fields, std::size(fields), alloc));
273 return std::make_tuple(
ObjectValue(fonts_fields, std::size(fonts_fields), alloc),
274 ArrayValue(chars.data(), chars.size(), alloc));
278 std::unordered_map<std::string, std::vector<GlyphRec>> fFontGlyphs;
285 , fShapersFact(sfact)
286 , fBuilder(rp ? std::move(rp) : sk_make_sp<NullResourceProvider>(),
288 nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
290 &fStats, {0, 0}, 1, 1, 0)
294 void preshape(
const Value& jlottie) {
295 fBuilder.parseFonts(jlottie[
"fonts"], jlottie[
"chars"]);
297 this->preshapeComp(jlottie);
298 if (
const ArrayValue* jassets = jlottie[
"assets"]) {
299 for (
const auto& jasset : *jassets) {
300 this->preshapeComp(jasset);
304 const auto& [fonts, chars] = fGlyphCache.toLottie(fAlloc, jlottie[
"fonts"]);
312 sk_sp<SkData> load(
const char[],
const char[])
const override {
return nullptr; }
315 void preshapeComp(
const Value& jcomp) {
316 if (
const ArrayValue* jlayers = jcomp[
"layers"]) {
317 for (
const auto& jlayer : *jlayers) {
318 this->preshapeLayer(jlayer);
323 void preshapeLayer(
const Value& jlayer) {
324 static constexpr int kTextLayerType = 5;
325 if (skottie::ParseDefault<int>(jlayer[
"ty"], -1) != kTextLayerType) {
329 const ArrayValue* jtxts = jlayer[
"t"][
"d"][
"k"];
334 for (
const auto& jtxt : *jtxts) {
335 const Value& jtxt_val = jtxt[
"s"];
343 const std::string_view font_name(jfont_name->
begin(), jfont_name->
size());
345 static constexpr float kMinSize = 0.1f,
370 fFontMgr, fShapersFact);
373 size_t line,
size_t cluster) ->
Value {
386 return ObjectValue(fields, std::size(fields), fAlloc);
389 std::vector<Value> shaped_info;
390 for (
const auto& frag : shape_result.fFragments) {
391 SkASSERT(frag.fGlyphs.fGlyphIDs.size() == 1);
392 SkASSERT(frag.fGlyphs.fClusters.size() == frag.fGlyphs.fGlyphIDs.size());
394 for (
const auto& runrec : frag.fGlyphs.fRuns) {
396 const SkPoint* glyph_pos = frag.fGlyphs.fGlyphPos.data() +
offset;
397 const size_t* clusters = frag.fGlyphs.fClusters.data() +
offset;
399 for (
size_t i = 0; i < runrec.fSize; ++i) {
404 const char* ch_utf8 = txt_val.
fText.
c_str() + clusters[i];
407 fGlyphCache.addGlyph(font_name, ch, runrec.fFont,
glyphs[i]);
408 shaped_info.push_back(shaped_glyph_info(ch,
409 frag.fOrigin + glyph_pos[i],
420 ArrayValue(shaped_info.data(), shaped_info.size(), fAlloc);
426 StringValue(preshapedFontName(font_name).c_str(), fAlloc);
435 GlyphCache fGlyphCache;
442bool Preshape(
const char* json,
size_t size,
SkWStream* stream,
451 Preshaper preshaper(rp, fmgr, sfact);
453 preshaper.preshape(
dom.root());
455 stream->writeText(
dom.root().toString().c_str());
464 return Preshape(
static_cast<const char*
>(json->data()), json->size(), stream, fmgr, sfact, rp);
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4])
@ kClose
SkPath::RawIter returns 0 points.
@ kCubic
SkPath::RawIter returns 4 points.
@ kConic
SkPath::RawIter returns 3 points + 1 weight.
@ kQuad
SkPath::RawIter returns 3 points.
@ kMove
SkPath::RawIter returns 1 point.
@ kLine
SkPath::RawIter returns 2 points.
SK_API SkString static SkString SkStringPrintf()
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
constexpr int SkToInt(S x)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
const char * c_str() const
Value & writable(const char *key, SkArenaAlloc &) const
const char * begin() const
static Result Shape(const SkString &text, const TextDesc &desc, const SkPoint &point, const sk_sp< SkFontMgr > &, const sk_sp< SkShapers::Factory > &)
@ kTrackFragmentAdvanceAscent
SK_SPI size_t ToUTF8(SkUnichar uni, char utf8[kMaxBytesInUTF8Sequence]=nullptr)
constexpr unsigned kMaxBytesInUTF8Sequence
SK_SPI SkUnichar NextUTF8(const char **ptr, const char *end)
bool Parse(const skjson::Value &jv, const internal::AnimationBuilder &abuilder, TextValue *v)
sk_sp< SkTypeface > fTypeface
Shaper::Direction fDirection
Shaper::LinebreakPolicy fLineBreak
Shaper::Capitalization fCapitalization
Shaper::ResizePolicy fResize
SkTextUtils::Align fHAlign