static void load_embedded_font(const SkTypeface_FreeType::Scanner& scanner, const uint8_t* data, size_t size, int index, SkFontMgr_Custom::Families* families) { auto stream = skstd::make_unique<SkMemoryStream>(data, size, false); int numFaces; if (!scanner.recognizedFont(stream.get(), &numFaces)) { SkDebugf("---- failed to open <%d> as a font\n", index); return; } for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { bool isFixedPitch; SkString realname; SkFontStyle style = SkFontStyle(); // avoid uninitialized warning if (!scanner.scanFont(stream.get(), faceIndex, &realname, &style, &isFixedPitch, nullptr)) { SkDebugf("---- failed to open <%d> <%d> as a font\n", index, faceIndex); return; } SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str()); if (nullptr == addTo) { addTo = new SkFontStyleSet_Custom(realname); families->push_back().reset(addTo); } auto data = skstd::make_unique<SkFontData>(std::move(stream), faceIndex, nullptr, 0); addTo->appendTypeface(sk_make_sp<SkTypeface_Stream>(std::move(data), style, isFixedPitch, true, realname)); } }
static void load_embedded_font(const SkTypeface_FreeType::Scanner& scanner, const uint8_t* data, size_t size, int index, SkFontMgr_Custom::Families* families) { SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(data, size, false)); int numFaces; if (!scanner.recognizedFont(stream, &numFaces)) { SkDebugf("---- failed to open <%d> as a font\n", index); return; } for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { bool isFixedPitch; SkString realname; SkFontStyle style = SkFontStyle(); // avoid uninitialized warning if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch, nullptr)) { SkDebugf("---- failed to open <%d> <%d> as a font\n", index, faceIndex); return; } SkTypeface_Custom* tf = new SkTypeface_Stream(style, isFixedPitch, true, // system-font (cannot delete) realname, stream.release(), faceIndex); SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str()); if (nullptr == addTo) { addTo = new SkFontStyleSet_Custom(realname); families->push_back().reset(addTo); } addTo->appendTypeface(tf); } }
static void load_directory_fonts(const SkTypeface_FreeType::Scanner& scanner, const SkString& directory, const char* suffix, SkFontMgr_Custom::Families* families) { SkOSFile::Iter iter(directory.c_str(), suffix); SkString name; while (iter.next(&name, false)) { SkString filename(SkOSPath::Join(directory.c_str(), name.c_str())); SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(filename.c_str())); if (!stream.get()) { SkDebugf("---- failed to open <%s>\n", filename.c_str()); continue; } int numFaces; if (!scanner.recognizedFont(stream, &numFaces)) { SkDebugf("---- failed to open <%s> as a font\n", filename.c_str()); continue; } for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { bool isFixedPitch; SkString realname; SkFontStyle style = SkFontStyle(); // avoid uninitialized warning if (!scanner.scanFont(stream, faceIndex, &realname, &style, &isFixedPitch, NULL)) { SkDebugf("---- failed to open <%s> <%d> as a font\n", filename.c_str(), faceIndex); continue; } SkTypeface_Custom* tf = SkNEW_ARGS(SkTypeface_File, ( style, isFixedPitch, true, // system-font (cannot delete) realname, filename.c_str(), faceIndex)); SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str()); if (NULL == addTo) { addTo = new SkFontStyleSet_Custom(realname); families->push_back().reset(addTo); } addTo->appendTypeface(tf); } } SkOSFile::Iter dirIter(directory.c_str()); while (dirIter.next(&name, true)) { if (name.startsWith(".")) { continue; } SkString dirname(SkOSPath::Join(directory.c_str(), name.c_str())); load_directory_fonts(scanner, dirname, suffix, families); } }
static const char* find_family_name(const SkTypeface* familyMember) { const FamilyRec* familyRec = find_family(familyMember); for (int i = 0; i < gNameList.count(); i++) { if (gNameList[i].fFamily == familyRec) { return gNameList[i].fName; } } return NULL; }
/* Remove reference to this face from its family. If the resulting family is empty (has no faces), return that family, otherwise return NULL */ static FamilyRec* remove_from_family(const SkTypeface* face) { FamilyRec* family = find_family(face); SkASSERT(family->fFaces[face->style()] == face); family->fFaces[face->style()] = NULL; for (int i = 0; i < 4; i++) { if (family->fFaces[i] != NULL) { // family is non-empty return NULL; } } return family; // return the empty family }
FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember, bool isFixedPitch) : INHERITED(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedPitch) { fIsSysFont = sysFont; // our caller has acquired the gFamilyHeadAndNameListMutex so this is safe FamilyRec* rec = NULL; if (familyMember) { rec = find_family(familyMember); SkASSERT(rec); } else { rec = SkNEW(FamilyRec); } rec->fFaces[style] = this; }
FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember) : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) { fIsSysFont = sysFont; SkAutoMutexAcquire ac(gFamilyMutex); FamilyRec* rec = NULL; if (familyMember) { rec = find_family(familyMember); SkASSERT(rec); } else { rec = SkNEW(FamilyRec); } rec->fFaces[style] = this; }
/* Remove reference to this face from its family. If the resulting family is empty (has no faces), return that family, otherwise return NULL */ static FamilyRec* remove_from_family(const SkTypeface* face) { FamilyRec* family = find_family(face); if (family) { SkASSERT(family->fFaces[face->style()] == face); family->fFaces[face->style()] = NULL; for (int i = 0; i < 4; i++) { if (family->fFaces[i] != NULL) { // family is non-empty return NULL; } } } else { // SkDebugf("remove_from_family(%p) face not found", face); } return family; // return the empty family }
static void load_system_fonts() { // check if we've already be called if (NULL != gDefaultNormal) { return; } SkString baseDirectory(SK_FONT_FILE_PREFIX); unsigned int count = 0; load_directory_fonts(baseDirectory, &count); if (0 == count) { SkNEW(EmptyTypeface); } // do this after all fonts are loaded. This is our default font, and it // acts as a sentinel so we only execute load_system_fonts() once static const char* gDefaultNames[] = { #if defined(__LB_SHELL__) "Droid Sans", // our preferred default #endif "Arial", "Verdana", "Times New Roman", NULL }; const char** names = gDefaultNames; while (*names) { SkTypeface* tf = find_typeface(*names++, SkTypeface::kNormal); if (tf) { gDefaultNormal = tf; break; } } // check if we found *something* if (NULL == gDefaultNormal) { if (NULL == gFamilyHead) { sk_throw(); } for (int i = 0; i < 4; i++) { if ((gDefaultNormal = gFamilyHead->fFaces[i]) != NULL) { break; } } } if (NULL == gDefaultNormal) { sk_throw(); } gFallBackTypeface = gDefaultNormal; gDefaultFamily = find_family(gDefaultNormal); }
// gFamilyHeadAndNameListMutex must already be acquired static const char* find_family_name(const SkTypeface* member) { FamilyRec* family = find_family(member); if (NULL == family) { return NULL; } NameFamilyPairList& namelist = GetNameList(); NameFamilyPair* list = namelist.begin(); int count = namelist.count(); for (int i = 0; i < count; i++) { NameFamilyPair* pair = &list[i]; if (pair->fFamily == family) { return pair->fName; } } return NULL; }
static SkTypeface* find_typeface(const SkTypeface* familyMember, SkTypeface::Style style) { const FamilyRec* family = find_family(familyMember); return family ? find_best_face(family, style) : NULL; }
/* Called once (ensured by the sentinel check at the beginning of our body). Initializes all the globals, and register the system fonts. */ static void load_system_fonts() { // check if we've already be called if (NULL != gDefaultNormal) { return; } const FontInitRec* rec = gSystemFonts; SkTypeface* firstInFamily = NULL; int fallbackCount = 0; for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) { // if we're the first in a new family, clear firstInFamily if (rec[i].fNames != NULL) { firstInFamily = NULL; } SkString name; SkTypeface::Style style; // we expect all the fonts, except the "fallback" fonts bool isExpected = (rec[i].fNames != gFBNames); if (!get_name_and_style(rec[i].fFileName, &name, &style, isExpected)) { continue; } SkTypeface* tf = SkNEW_ARGS(FileTypeface, (style, true, // system-font (cannot delete) firstInFamily, // what family to join rec[i].fFileName) // filename ); if (rec[i].fNames != NULL) { // see if this is one of our fallback fonts if (rec[i].fNames == gFBNames) { // SkDebugf("---- adding %s as fallback[%d] fontID %d\n", // rec[i].fFileName, fallbackCount, tf->uniqueID()); gFallbackFonts[fallbackCount++] = tf->uniqueID(); } firstInFamily = tf; FamilyRec* family = find_family(tf); const char* const* names = rec[i].fNames; // record the default family if this is it if (names == DEFAULT_NAMES) { gDefaultFamily = family; } // add the names to map to this family while (*names) { add_name(*names, family); names += 1; } } } // do this after all fonts are loaded. This is our default font, and it // acts as a sentinel so we only execute load_system_fonts() once gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal); // now terminate our fallback list with the sentinel value gFallbackFonts[fallbackCount] = 0; }
static void load_system_fonts() { // check if we've already be called if (NULL != gDefaultNormal) { // printf("---- default font %p\n", gDefaultNormal); return; } SkOSFile::Iter iter(SK_FONT_FILE_PREFIX, ".ttf"); SkString name; int count = 0; while (iter.next(&name, false)) { SkString filename; GetFullPathForSysFonts(&filename, name.c_str()); bool isFixedWidth; SkString realname; SkTypeface::Style style = SkTypeface::kNormal; // avoid uninitialized warning if (!get_name_and_style(filename.c_str(), &realname, &style, &isFixedWidth)) { SkDebugf("------ can't load <%s> as a font\n", filename.c_str()); continue; } // SkDebugf("font: <%s> %d <%s>\n", realname.c_str(), style, filename.c_str()); FamilyRec* family = find_familyrec(realname.c_str()); if (family && family->fFaces[style]) { // SkDebugf("---- skipping duplicate typeface %s style %d\n", // realname.c_str(), style); continue; } // this constructor puts us into the global gFamilyHead llist FamilyTypeface* tf = SkNEW_ARGS(FileTypeface, (style, true, // system-font (cannot delete) family, // what family to join filename.c_str(), isFixedWidth) // filename ); if (NULL == family) { add_name(realname.c_str(), tf->getFamily()); } count += 1; } if (0 == count) { SkNEW(EmptyTypeface); } // do this after all fonts are loaded. This is our default font, and it // acts as a sentinel so we only execute load_system_fonts() once static const char* gDefaultNames[] = { "Arial", "Verdana", "Times New Roman", NULL }; const char** names = gDefaultNames; while (*names) { SkTypeface* tf = find_typeface(*names++, SkTypeface::kNormal); if (tf) { gDefaultNormal = tf; break; } } // check if we found *something* if (NULL == gDefaultNormal) { if (NULL == gFamilyHead) { sk_throw(); } for (int i = 0; i < 4; i++) { if ((gDefaultNormal = gFamilyHead->fFaces[i]) != NULL) { break; } } } if (NULL == gDefaultNormal) { sk_throw(); } gFallBackTypeface = gDefaultNormal; gDefaultFamily = find_family(gDefaultNormal); // SkDebugf("---- default %p head %p family %p\n", gDefaultNormal, gFamilyHead, gDefaultFamily); }
/* * Called once (ensured by the sentinel check at the beginning of our body). * Initializes all the globals, and register the system fonts. * * gFamilyHeadAndNameListMutex must already be acquired. */ static void init_system_fonts() { // check if we've already been called if (gDefaultNormal) { return; } SkASSERT(gUniqueFontID == 0); load_font_info(); FontInitRec* rec = gSystemFonts; SkTypeface* firstInFamily = NULL; int fallbackCount = 0; for (size_t i = 0; i < gNumSystemFonts; i++) { // if we're the first in a new family, clear firstInFamily if (rec[i].fNames != NULL) { firstInFamily = NULL; } bool isFixedWidth; SkString name; SkTypeface::Style style; // we expect all the fonts, except the "fallback" fonts bool isExpected = (rec[i].fNames != gFBNames); if (!get_name_and_style(rec[i].fFileName, &name, &style, &isFixedWidth, isExpected)) { // We need to increase gUniqueFontID here so that the unique id of // each font matches its index in gSystemFonts array, as expected // by find_uniqueID. sk_atomic_inc(&gUniqueFontID); continue; } SkTypeface* tf = SkNEW_ARGS(FileTypeface, (style, true, // system-font (cannot delete) firstInFamily, // what family to join rec[i].fFileName, isFixedWidth) // filename ); #if SK_DEBUG_FONTS SkDebugf("---- SkTypeface[%d] %s fontID %d", i, rec[i].fFileName, tf->uniqueID()); #endif if (rec[i].fNames != NULL) { // see if this is one of our fallback fonts if (rec[i].fNames == gFBNames) { #if SK_DEBUG_FONTS SkDebugf("---- adding %s as fallback[%d] fontID %d", rec[i].fFileName, fallbackCount, tf->uniqueID()); #endif gFallbackFonts[fallbackCount++] = tf->uniqueID(); // Use the font file name as the name of the typeface. const char **nameList = (const char**)malloc(2 * sizeof(char*)); if (nameList == NULL) { // shouldn't get here SkDEBUGFAIL("Failed to allocate nameList"); break; } nameList[0] = rec[i].fFileName; nameList[1] = NULL; rec[i].fNames = nameList; } firstInFamily = tf; FamilyRec* family = find_family(tf); const char* const* names = rec[i].fNames; // record the default family if this is it if (names == gDefaultNames) { gDefaultFamily = family; } // add the names to map to this family while (*names) { add_name(*names, family); names += 1; } } } // do this after all fonts are loaded. This is our default font, and it // acts as a sentinel so we only execute load_system_fonts() once gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal); // now terminate our fallback list with the sentinel value gFallbackFonts[fallbackCount] = 0; // SkDEBUGCODE(dump_globals()); }