static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length) { SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData); SkPaint paint; paint.setTypeface(font->getTypeface()); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); return paint.containsText(characters, length * sizeof(uint16_t)); }
DEF_TEST(Paint_cmap, reporter) { // need to implement charsToGlyphs on other backends (e.g. linux, win) // before we can run this tests everywhere return; static const int NGLYPHS = 64; SkUnichar src[NGLYPHS]; SkUnichar dst[NGLYPHS]; // used for utf8, utf16, utf32 storage static const struct { size_t (*fSeedTextProc)(const SkUnichar[], void* dst, int count); SkPaint::TextEncoding fEncoding; } gRec[] = { { uni_to_utf8, SkPaint::kUTF8_TextEncoding }, { uni_to_utf16, SkPaint::kUTF16_TextEncoding }, { uni_to_utf32, SkPaint::kUTF32_TextEncoding }, }; SkRandom rand; SkPaint paint; paint.setTypeface(SkTypeface::RefDefault())->unref(); SkTypeface* face = paint.getTypeface(); for (int i = 0; i < 1000; ++i) { // generate some random text for (int j = 0; j < NGLYPHS; ++j) { src[j] = ' ' + j; } // inject some random chars, to sometimes abort early src[rand.nextU() & 63] = rand.nextU() & 0xFFF; for (size_t k = 0; k < SK_ARRAY_COUNT(gRec); ++k) { paint.setTextEncoding(gRec[k].fEncoding); size_t len = gRec[k].fSeedTextProc(src, dst, NGLYPHS); uint16_t glyphs0[NGLYPHS], glyphs1[NGLYPHS]; bool contains = paint.containsText(dst, len); int nglyphs = paint.textToGlyphs(dst, len, glyphs0); int first = face->charsToGlyphs(dst, paint2encoding(paint), glyphs1, NGLYPHS); int index = find_first_zero(glyphs1, NGLYPHS); REPORTER_ASSERT(reporter, NGLYPHS == nglyphs); REPORTER_ASSERT(reporter, index == first); REPORTER_ASSERT(reporter, 0 == memcmp(glyphs0, glyphs1, NGLYPHS * sizeof(uint16_t))); if (contains) { REPORTER_ASSERT(reporter, NGLYPHS == first); } else { REPORTER_ASSERT(reporter, NGLYPHS > first); } } } }
SkTypeface* OsmAnd::EmbeddedFontFinder::findFontForCharacterUCS4( const uint32_t character, const SkFontStyle style /*= SkFontStyle()*/) const { SkPaint paint; paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); SkTypeface* bestMatch = nullptr; auto bestMatchDifference = std::numeric_limits<float>::quiet_NaN(); for (const auto font : constOf(_fonts)) { paint.setTypeface(font); // If font doesn't contain requested character, it should be completely ignored if (!paint.containsText(&character, sizeof(uint32_t))) continue; // Calculate difference between this font style and requested style auto difference = 0.0f; const auto fontStyle = font->fontStyle(); if (fontStyle.slant() != style.slant()) difference += 1.0f; if (fontStyle.width() != style.width()) difference += static_cast<float>(qAbs(fontStyle.width() - style.width())) / SkFontStyle::kUltaExpanded_Width; if (fontStyle.weight() != style.weight()) difference += static_cast<float>(qAbs(fontStyle.weight() - style.weight())) / SkFontStyle::kBlack_Weight; // If there was previous best match, check if this match is better if (bestMatch && bestMatchDifference < difference) continue; bestMatch = font; bestMatchDifference = difference; // In case difference is 0, there won't be better match if (qFuzzyIsNull(bestMatchDifference)) break; } return bestMatch; }
QVector<OsmAnd::TextRasterizer_P::LinePaint> OsmAnd::TextRasterizer_P::evaluatePaints( const QVector<QStringRef>& lineRefs, const Style& style) const { // Prepare default paint SkPaint paint = _defaultPaint; paint.setTextSize(style.size); paint.setColor(style.color.toSkColor()); // Transform text style to font style const SkFontStyle fontStyle( style.bold ? SkFontStyle::kBold_Weight : SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width, style.italic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant); const auto pText = lineRefs.first().string()->constData(); QVector<LinePaint> linePaints; linePaints.reserve(lineRefs.count()); for (const auto& lineRef : constOf(lineRefs)) { LinePaint linePaint; linePaint.line = lineRef; TextPaint* pTextPaint = nullptr; const auto pLine = lineRef.constData(); const auto pEnd = pLine + lineRef.size(); auto pNextCharacter = pLine; while (pNextCharacter != pEnd) { const auto pCharacter = pNextCharacter; const auto position = pNextCharacter - pText; const auto characterUCS4 = SkUTF16_NextUnichar(reinterpret_cast<const uint16_t**>(&pNextCharacter)); // First of all check previous font if it contains this character auto font = pTextPaint ? pTextPaint->paint.getTypeface() : nullptr; if (font) { SkPaint paint; paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); paint.setTypeface(font); if (!paint.containsText(&characterUCS4, sizeof(uint32_t))) font = nullptr; #if OSMAND_LOG_CHARACTERS_FONT else { SkString fontName; font->getFamilyName(&fontName); LogPrintf(LogSeverityLevel::Warning, "UCS4 character 0x%08x (%u) has been found in '%s' font (reused)", characterUCS4, characterUCS4, fontName.c_str()); } #endif // OSMAND_LOG_CHARACTERS_FONT } if (!font) { font = owner->fontFinder->findFontForCharacterUCS4(characterUCS4, fontStyle); #if OSMAND_LOG_CHARACTERS_WITHOUT_FONT if (!font) { LogPrintf(LogSeverityLevel::Warning, "UCS4 character 0x%08x (%u) has not been found in any font", characterUCS4, characterUCS4); } #endif // OSMAND_LOG_CHARACTERS_WITHOUT_FONT #if OSMAND_LOG_CHARACTERS_FONT if (font) { SkString fontName; font->getFamilyName(&fontName); LogPrintf(LogSeverityLevel::Warning, "UCS4 character 0x%08x (%u) has been found in '%s' font", characterUCS4, characterUCS4, fontName.c_str()); } #endif // OSMAND_LOG_CHARACTERS_FONT } if (pTextPaint == nullptr || pTextPaint->paint.getTypeface() != font) { linePaint.textPaints.push_back(qMove(TextPaint())); pTextPaint = &linePaint.textPaints.last(); pTextPaint->text = QStringRef(lineRef.string(), position, 1); pTextPaint->paint = paint; pTextPaint->paint.setTypeface(font); SkPaint::FontMetrics metrics; pTextPaint->height = paint.getFontMetrics(&metrics); linePaint.maxFontHeight = qMax(linePaint.maxFontHeight, pTextPaint->height); linePaint.minFontHeight = qMin(linePaint.minFontHeight, pTextPaint->height); linePaint.maxFontLineSpacing = qMax(linePaint.maxFontLineSpacing, metrics.fLeading); linePaint.minFontLineSpacing = qMin(linePaint.minFontLineSpacing, metrics.fLeading); linePaint.maxFontTop = qMax(linePaint.maxFontTop, -metrics.fTop); linePaint.minFontTop = qMin(linePaint.minFontTop, -metrics.fTop); linePaint.maxFontBottom = qMax(linePaint.maxFontBottom, metrics.fBottom); linePaint.minFontBottom = qMin(linePaint.minFontBottom, metrics.fBottom); if (style.bold && (!font || (font && font->fontStyle().weight() <= SkFontStyle::kNormal_Weight))) pTextPaint->paint.setFakeBoldText(true); } else { pTextPaint->text = QStringRef(lineRef.string(), pTextPaint->text.position(), pTextPaint->text.size() + 1); } } linePaints.push_back(qMove(linePaint)); } return linePaints; }
static void containsText_proc(int loops, const SkPaint& paint, const void* text, size_t len, int glyphCount) { for (int i = 0; i < loops; ++i) { paint.containsText(text, len); } }