/* * Copyright 2008 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include #include #include #include "SkFontHost.h" #include "SkStream.h" /** An extern from SkFontHost_FreeType. */ SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name); /** This lock must be held while modifying global_fc_* globals. */ SK_DECLARE_STATIC_MUTEX(global_fc_map_lock); /** Map from file names to file ids. */ static std::map global_fc_map; /** Map from file ids to file names. */ static std::map global_fc_map_inverted; /** The next file id. */ static unsigned global_fc_map_next_id = 0; /** * Check to see if the filename has already been assigned a fileid and, if so, use it. * Otherwise, assign one. Return the resulting fileid. */ static unsigned FileIdFromFilename(const char* filename) { SkAutoMutexAcquire ac(global_fc_map_lock); std::map::const_iterator i = global_fc_map.find(filename); if (i == global_fc_map.end()) { const unsigned fileid = global_fc_map_next_id++; global_fc_map[filename] = fileid; global_fc_map_inverted[fileid] = filename; return fileid; } else { return i->second; } } static unsigned FileIdFromUniqueId(unsigned uniqueid) { return uniqueid >> 8; } static SkTypeface::Style StyleFromUniqueId(unsigned uniqueid) { return static_cast(uniqueid & 0xff); } static unsigned UniqueIdFromFileIdAndStyle(unsigned fileid, SkTypeface::Style style) { SkASSERT((style & 0xff) == style); return (fileid << 8) | static_cast(style); } class FontConfigTypeface : public SkTypeface { public: FontConfigTypeface(Style style, uint32_t id) : SkTypeface(style, id) { } }; /** * Find a matching font where @type (one of FC_*) is equal to @value. For a * list of types, see http://fontconfig.org/fontconfig-devel/x19.html#AEN27. * The variable arguments are a list of triples, just like the first three * arguments, and must be NULL terminated. * * For example, * FontMatchString(FC_FILE, FcTypeString, "/usr/share/fonts/myfont.ttf", NULL); */ static FcPattern* FontMatch(const char* type, FcType vtype, const void* value, ...) { va_list ap; va_start(ap, value); FcPattern* pattern = FcPatternCreate(); for (;;) { FcValue fcvalue; fcvalue.type = vtype; switch (vtype) { case FcTypeString: fcvalue.u.s = (FcChar8*) value; break; case FcTypeInteger: fcvalue.u.i = (int)(intptr_t)value; break; default: SkDEBUGFAIL("FontMatch unhandled type"); } FcPatternAdd(pattern, type, fcvalue, FcFalse); type = va_arg(ap, const char *); if (!type) break; // FcType is promoted to int when passed through ... vtype = static_cast(va_arg(ap, int)); value = va_arg(ap, const void *); }; va_end(ap); FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; FcPattern* match = FcFontMatch(NULL, pattern, &result); FcPatternDestroy(pattern); return match; } // static SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style) { const char* resolved_family_name = NULL; FcPattern* face_match = NULL; { SkAutoMutexAcquire ac(global_fc_map_lock); if (FcTrue != FcInit()) { SkASSERT(false && "Could not initialize fontconfig."); } } if (familyFace) { // Here we use the inverted global id map to find the filename from the // SkTypeface object. Given the filename we can ask fontconfig for the // familyname of the font. SkAutoMutexAcquire ac(global_fc_map_lock); const unsigned fileid = FileIdFromUniqueId(familyFace->uniqueID()); std::map::const_iterator i = global_fc_map_inverted.find(fileid); if (i == global_fc_map_inverted.end()) { return NULL; } face_match = FontMatch(FC_FILE, FcTypeString, i->second.c_str(), NULL); if (!face_match) { return NULL; } FcChar8* family; if (FcPatternGetString(face_match, FC_FAMILY, 0, &family)) { FcPatternDestroy(face_match); return NULL; } // At this point, @family is pointing into the @face_match object so we // cannot release it yet. resolved_family_name = reinterpret_cast(family); } else if (familyName) { resolved_family_name = familyName; } const int bold = (style & SkTypeface::kBold) ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL; const int italic = (style & SkTypeface::kItalic) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN; FcPattern* match; if (resolved_family_name) { match = FontMatch(FC_FAMILY, FcTypeString, resolved_family_name, FC_WEIGHT, FcTypeInteger, bold, FC_SLANT, FcTypeInteger, italic, NULL); } else { match = FontMatch(FC_WEIGHT, FcTypeInteger, reinterpret_cast(bold), FC_SLANT, FcTypeInteger, italic, NULL); } if (face_match) FcPatternDestroy(face_match); if (!match) return NULL; FcChar8* filename; if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) { FcPatternDestroy(match); return NULL; } // Now @filename is pointing into @match const unsigned fileid = FileIdFromFilename(reinterpret_cast(filename)); const unsigned id = UniqueIdFromFileIdAndStyle(fileid, style); SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id)); FcPatternDestroy(match); return typeface; } // static SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { SkDEBUGFAIL("SkFontHost::CreateTypefaceFromStream unimplemented"); return NULL; } // static SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented"); return NULL; } // static SkStream* SkFontHost::OpenStream(uint32_t id) { SkAutoMutexAcquire ac(global_fc_map_lock); const unsigned fileid = FileIdFromUniqueId(id); std::map::const_iterator i = global_fc_map_inverted.find(fileid); if (i == global_fc_map_inverted.end()) { return NULL; } return SkNEW_ARGS(SkFILEStream, (i->second.c_str())); } size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, int32_t* index) { SkAutoMutexAcquire ac(global_fc_map_lock); const unsigned fileid = FileIdFromUniqueId(fontID); std::map::const_iterator i = global_fc_map_inverted.find(fileid); if (i == global_fc_map_inverted.end()) { return 0; } const std::string& str = i->second; if (path) { memcpy(path, str.c_str(), SkMin32(str.size(), length)); } if (index) { // TODO: check if we're in a TTC *index = 0; } return str.size(); } void SkFontHost::Serialize(const SkTypeface*, SkWStream*) { SkDEBUGFAIL("SkFontHost::Serialize unimplemented"); } SkTypeface* SkFontHost::Deserialize(SkStream* stream) { SkDEBUGFAIL("SkFontHost::Deserialize unimplemented"); return NULL; } SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { // We don't handle font fallback, WebKit does. return 0; }