如何在Skia中用多种语言绘制文本?

时间:2019-10-10 19:00:19

标签: skia

我正在尝试使用Skia(使用2019-10-07版本)以多种语言绘制文本。显然,它包括Harfbuzz库,因为我必须使用skia_use_system_harfbuzz=false进行构建,因此似乎所有内容都应包含在内。如果我用中文字体绘制中文文本,就没有问题。但是,如果我要求“ Helvetica”并画中文文本,那就不好了。 macOS和Windows都允许我执行此操作,它们会在引擎盖下查找最匹配的中文字体并使用它。 Skia确实有SkFontMgr,它将为给定的Unicode字符找到字体。因此,我将不得不遍历所有字符并找出字符串的哪些部分需要哪些字体,但是似乎没有暴露出任何可产生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);
    }

我认为我正在错过更好的方法,如果有人能启发我,我将不胜感激。

0 个答案:

没有答案