static void test_fontiter(skiatest::Reporter* reporter, bool verbose) { SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault()); int count = fm->countFamilies(); for (int i = 0; i < count; ++i) { SkString fname; fm->getFamilyName(i, &fname); SkAutoTUnref<SkFontStyleSet> fnset(fm->matchFamily(fname.c_str())); SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i)); REPORTER_ASSERT(reporter, fnset->count() == set->count()); if (verbose) { SkDebugf("[%2d] %s\n", i, fname.c_str()); } for (int j = 0; j < set->count(); ++j) { SkString sname; SkFontStyle fs; set->getStyle(j, &fs, &sname); // REPORTER_ASSERT(reporter, sname.size() > 0); SkAutoTUnref<SkTypeface> face(set->createTypeface(j)); // REPORTER_ASSERT(reporter, face.get()); if (verbose) { SkDebugf("\t[%d] %s [%3d %d %d]\n", j, sname.c_str(), fs.weight(), fs.width(), fs.isItalic()); } } } }
explicit SkFontStyleSet_Android(const FontFamily& family, const SkTypeface_FreeType::Scanner& scanner) { const SkString* cannonicalFamilyName = NULL; if (family.fNames.count() > 0) { cannonicalFamilyName = &family.fNames[0]; } // TODO? make this lazy for (int i = 0; i < family.fFonts.count(); ++i) { const FontFileInfo& fontFile = family.fFonts[i]; SkString pathName(family.fBasePath); pathName.append(fontFile.fFileName); SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(pathName.c_str())); if (!stream.get()) { SkDEBUGF(("Requested font file %s does not exist or cannot be opened.\n", pathName.c_str())); continue; } const int ttcIndex = fontFile.fIndex; SkString familyName; SkFontStyle style; bool isFixedWidth; if (!scanner.scanFont(stream.get(), ttcIndex, &familyName, &style, &isFixedWidth)) { SkDEBUGF(("Requested font file %s exists, but is not a valid font.\n", pathName.c_str())); continue; } int weight = fontFile.fWeight != 0 ? fontFile.fWeight : style.weight(); SkFontStyle::Slant slant = style.slant(); switch (fontFile.fStyle) { case FontFileInfo::Style::kAuto: slant = style.slant(); break; case FontFileInfo::Style::kNormal: slant = SkFontStyle::kUpright_Slant; break; case FontFileInfo::Style::kItalic: slant = SkFontStyle::kItalic_Slant; break; default: SkASSERT(false); break; } style = SkFontStyle(weight, style.width(), slant); const SkLanguage& lang = family.fLanguage; uint32_t variant = family.fVariant; if (kDefault_FontVariant == variant) { variant = kCompact_FontVariant | kElegant_FontVariant; } // The first specified family name overrides the family name found in the font. // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return // all of the specified family names in addition to the names found in the font. if (cannonicalFamilyName != NULL) { familyName = *cannonicalFamilyName; } fStyles.push_back().reset(SkNEW_ARGS(SkTypeface_AndroidSystem, (pathName, ttcIndex, style, isFixedWidth, familyName, lang, variant))); } }
explicit DWriteStyle(const SkFontStyle& pattern) { switch (pattern.slant()) { case SkFontStyle::kUpright_Slant: fSlant = DWRITE_FONT_STYLE_NORMAL; break; case SkFontStyle::kItalic_Slant: fSlant = DWRITE_FONT_STYLE_ITALIC; break; default: SkASSERT(false); } fWeight = (DWRITE_FONT_WEIGHT)pattern.weight(); fWidth = (DWRITE_FONT_STRETCH)pattern.width(); }
void SkGlyphCache::dump() const { const SkTypeface* face = fScalerContext->getTypeface(); const SkScalerContextRec& rec = fScalerContext->getRec(); SkMatrix matrix; rec.getSingleMatrix(&matrix); matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize)); SkString name; face->getFamilyName(&name); SkString msg; SkFontStyle style = face->fontStyle(); msg.printf("cache typeface:%x %25s:(%d,%d,%d)\n %s glyphs:%3d", face->uniqueID(), name.c_str(), style.weight(), style.width(), style.slant(), rec.dump().c_str(), fGlyphMap.count()); SkDebugf("%s\n", msg.c_str()); }
void iterateFamily(SkCanvas* canvas, const SkPaint& paint, SkFontStyleSet* fset) { SkPaint p(paint); SkScalar y = 0; for (int j = 0; j < fset->count(); ++j) { SkString sname; SkFontStyle fs; fset->getStyle(j, &fs, &sname); sname.appendf(" [%d %d]", fs.weight(), fs.width()); SkSafeUnref(p.setTypeface(fset->createTypeface(j))); (void)drawString(canvas, sname, 0, y, p); y += 24; } }
sk_sp<SkTypeface> SkTypeface::MakeFromName(const char name[], SkFontStyle fontStyle) { if (gCreateTypefaceDelegate) { sk_sp<SkTypeface> result = (*gCreateTypefaceDelegate)(name, fontStyle); if (result) { return result; } } if (nullptr == name && (fontStyle.slant() == SkFontStyle::kItalic_Slant || fontStyle.slant() == SkFontStyle::kUpright_Slant) && (fontStyle.weight() == SkFontStyle::kBold_Weight || fontStyle.weight() == SkFontStyle::kNormal_Weight)) { return MakeDefault(static_cast<SkTypeface::Style>( (fontStyle.slant() == SkFontStyle::kItalic_Slant ? SkTypeface::kItalic : SkTypeface::kNormal) | (fontStyle.weight() == SkFontStyle::kBold_Weight ? SkTypeface::kBold : SkTypeface::kNormal))); } SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault()); return sk_sp<SkTypeface>(fm->legacyCreateTypeface(name, fontStyle)); }
static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) { int score = 0; score += (pattern.width() - candidate.width()) * 100; score += (pattern.isItalic() == candidate.isItalic()) ? 0 : 1000; score += pattern.weight() - candidate.weight(); return score; }
static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) { int score = 0; score += SkTAbs((pattern.width() - candidate.width()) * 100); score += SkTAbs((pattern.slant() == candidate.slant()) ? 0 : 1000); score += SkTAbs(pattern.weight() - candidate.weight()); return score; }
void onDraw(SkCanvas* canvas) override { SkScalar y = 20; SkPaint paint; paint.setAntiAlias(true); paint.setLCDRenderText(true); paint.setSubpixelText(true); paint.setTextSize(17); SkFontMgr* fm = fFM; int count = SkMin32(fm->countFamilies(), MAX_FAMILIES); for (int i = 0; i < count; ++i) { SkString familyName; fm->getFamilyName(i, &familyName); paint.setTypeface(nullptr); (void)drawString(canvas, familyName, 20, y, paint); SkScalar x = 220; SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i)); for (int j = 0; j < set->count(); ++j) { SkString sname; SkFontStyle fs; set->getStyle(j, &fs, &sname); sname.appendf(" [%d %d %d]", fs.weight(), fs.width(), fs.slant()); SkSafeUnref(paint.setTypeface(set->createTypeface(j))); x = drawString(canvas, sname, x, y, paint) + 20; // check to see that we get different glyphs in japanese and chinese x = drawCharacter(canvas, 0x5203, x, y, paint, fm, familyName.c_str(), &zh, 1, fs); x = drawCharacter(canvas, 0x5203, x, y, paint, fm, familyName.c_str(), &ja, 1, fs); // check that emoji characters are found x = drawCharacter(canvas, 0x1f601, x, y, paint, fm, familyName.c_str(), nullptr,0, fs); } y += 24; } }
sk_sp<SkTypeface> create_font(const char* name, SkFontStyle style) { SkTestFontData* fontData = nullptr; const SubFont* sub; if (name) { for (int index = 0; index < gSubFontsCount; ++index) { sub = &gSubFonts[index]; if (!strcmp(name, sub->fName) && sub->fStyle == style) { fontData = &sub->fFont; break; } } if (!fontData) { // Once all legacy callers to portable fonts are converted, replace this with // SK_ABORT(); SkDebugf("missing %s weight %d, width %d, slant %d\n", name, style.weight(), style.width(), style.slant()); // If we called SkTypeface::CreateFromName() here we'd recurse infinitely, // so we reimplement its core logic here inline without the recursive aspect. sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault()); return fm->legacyMakeTypeface(name, style); } } else { sub = &gSubFonts[gDefaultFontIndex]; fontData = &sub->fFont; } sk_sp<SkTestFont> font; { SkAutoMutexAcquire ac(gTestFontMutex); if (fontData->fCachedFont) { font = fontData->fCachedFont; } else { font = sk_make_sp<SkTestFont>(*fontData); fontData->fCachedFont = font; } } return sk_make_sp<SkTestTypeface>(std::move(font), style); }
static void TypefaceStyle_test(skiatest::Reporter* reporter, uint16_t weight, uint16_t width, SkData* data) { sk_sp<SkData> dataCopy; SkData* dataToUse = data; if (!dataToUse->unique()) { dataCopy = SkData::MakeWithCopy(data->data(), data->size()); dataToUse = dataCopy.get(); } SkSFNTHeader* sfntHeader = static_cast<SkSFNTHeader*>(dataToUse->writable_data()); SkSFNTHeader::TableDirectoryEntry* tableEntry = SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader); SkSFNTHeader::TableDirectoryEntry* os2TableEntry = nullptr; int numTables = SkEndian_SwapBE16(sfntHeader->numTables); for (int tableEntryIndex = 0; tableEntryIndex < numTables; ++tableEntryIndex) { if (SkOTTableOS2::TAG == tableEntry[tableEntryIndex].tag) { os2TableEntry = tableEntry + tableEntryIndex; break; } } SkASSERT_RELEASE(os2TableEntry); size_t os2TableOffset = SkEndian_SwapBE32(os2TableEntry->offset); SkOTTableOS2_V0* os2Table = SkTAddOffset<SkOTTableOS2_V0>(sfntHeader, os2TableOffset); os2Table->usWeightClass.value = SkEndian_SwapBE16(weight); using WidthType = SkOTTableOS2_V0::WidthClass::Value; os2Table->usWidthClass.value = static_cast<WidthType>(SkEndian_SwapBE16(width)); sk_sp<SkTypeface> newTypeface(SkTypeface::MakeFromStream(new SkMemoryStream(dataToUse))); SkASSERT_RELEASE(newTypeface); SkFontStyle newStyle = newTypeface->fontStyle(); //printf("%d, %f\n", weight, (newStyle.weight() - (float)0x7FFF) / (float)0x7FFF); //printf("%d, %f\n", width , (newStyle.width() - (float)0x7F) / (float)0x7F); //printf("%d, %d\n", weight, newStyle.weight()); //printf("%d, %d\n", width , newStyle.width()); // Some back-ends (CG, GDI, DW) support OS/2 version A which uses 0 - 10 (but all differently). REPORTER_ASSERT(reporter, newStyle.weight() == weight || (weight <= 10 && newStyle.weight() == 100 * weight) || (weight == 4 && newStyle.weight() == 350) || // GDI weirdness (weight == 5 && newStyle.weight() == 400) || // GDI weirdness (weight == 0 && newStyle.weight() == 1) || // DW weirdness (weight == 1000 && newStyle.weight() == 999) // DW weirdness ); // Some back-ends (GDI) don't support width, ensure these always report 'medium'. REPORTER_ASSERT(reporter, newStyle.width() == width || newStyle.width() == 5); }