Как рисовать текст на нескольких языках в Skia? - PullRequest
0 голосов
/ 10 октября 2019

Я пытаюсь нарисовать текст на нескольких языках с помощью 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);
    }

Я предполагаю, что мне не хватает гораздо лучшего способа, и был бы благодаренесли бы кто-то мог просветить меня.

...