Я пытаюсь нарисовать текст на нескольких языках с помощью Skia (используя версию 2019-10-07). По-видимому, он включает библиотеку Harfbuzz, поскольку мне приходилось собирать с использованием skia_use_system_harfbuzz=false
, поэтому, похоже, все должно быть под капотом. Если я нарисую, скажем, китайский текст с китайским шрифтом, никаких проблем. Но если я попрошу «Helvetica» и нарисую китайский текст, ничего хорошего. И macOS, и Windows позволяют мне это делать, и они ищут наиболее подходящий китайский шрифт под капотом и используют его. У Skia есть SkFontMgr, который найдет шрифт для данного символа юникода. Поэтому мне пришлось бы пройтись по всем символам и выяснить, какие фрагменты строки нужны, какие шрифты, но, похоже, нет никаких функций, которые бы генерировали SkUnichar. Кроме того, SkFontMgr возвращает SkTypeface *, но все функции рисования требуют SkFont, который создается из sk_sp. Я предполагаю, что создание общего указателя из этого указателя - плохая идея, тем более что в документации сказано, что мне нужно сделать typeface-> unref () (но не сказано, когда и если я это сделаю, память будет повреждена). Вот код, который у меня есть (обратите внимание, что он не скомпилируется, потому что SkUTF.h отсутствует в skia/include
):
struct Run
{
SkTypeface *typeface; // PROBLEM: do I need to unref() this somewhere?
const char *utf8start;
size_t size;
float xPx = 0.0;
sk_sp<SkTextBlob> blob;
};
const char *text = "Hello world; 你好世界";
auto textLen = strlen(text);
const char **languages = nullptr;
const int nLanguages = 0;
const char *familyName = nullptr; // system font
auto style = SkFontStyle();
auto fontMgr = SkFontMgr::RefDefault();
auto *p = text;
auto *end = p + textLen;
std::vector<Run> runs;
SkTypeface *lastTypeface = nullptr;
while (p != end) {
const char *origP = p;
auto unichar = SkUTF::NextUtf8(&p, end); // PROBLEM: not exported
SkTypeface *typeface = fontMgr->matchFamilyStyleCharacter(familyName, style,
languages, nLanguages, unichar);
if (!typeface) {
typeface = fontMgr->matchFamilyStyle(nullptr, style); // default typeface
}
if (typeface != lastTypeface) {
runs.append(Run());
runs.back().typeface = typeface;
runs.back().utf8start = origP;
lastTypeface = typeface;
}
runs.back().size = p - runs.back().utf8start;
}
float fontSizePx = viewport.toPixelHeight(font.pointSize());
float xPx = 0.0, yPx = 0.0;
for (auto& r : runs) {
auto skfont = SkFont(sk_sp<SkTypeface>(r.typeface), fontSizePx); // PROBLEM: this can't be good?
r.blob = SkTextBlob::MakeFromText(r.utf8start, r.size, skfont);
SkRect bounds;
auto width = skfont.measureText(r.utf8start, r.size, SkTextEncoding::kUTF8, &bounds, nullptr);
r.xPx = xPx;
xPx += width;
}
xPx = 0.0;
for (auto& r : runs) {
canvas.drawTextBlob(r.blob, xPx + r.xPx, yPx, paint);
}
Я предполагаю, что мне не хватает гораздо лучшего способа, и был бы благодаренесли бы кто-то мог просветить меня.