Index: skia/ports/SkFontHost_fontconfig.cpp |
=================================================================== |
--- skia/ports/SkFontHost_fontconfig.cpp (revision 16859) |
+++ skia/ports/SkFontHost_fontconfig.cpp (working copy) |
@@ -1,375 +0,0 @@ |
-/* libs/graphics/ports/SkFontHost_fontconfig.cpp |
-** |
-** Copyright 2008, Google Inc. |
-** |
-** Licensed under the Apache License, Version 2.0 (the "License"); |
-** you may not use this file except in compliance with the License. |
-** You may obtain a copy of the License at |
-** |
-** http://www.apache.org/licenses/LICENSE-2.0 |
-** |
-** Unless required by applicable law or agreed to in writing, software |
-** distributed under the License is distributed on an "AS IS" BASIS, |
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-** See the License for the specific language governing permissions and |
-** limitations under the License. |
-*/ |
- |
-// ----------------------------------------------------------------------------- |
-// This file provides implementations of the font resolution members of |
-// SkFontHost by using the fontconfig[1] library. Fontconfig is usually found |
-// on Linux systems and handles configuration, parsing and caching issues |
-// involved with enumerating and matching fonts. |
-// |
-// [1] http://fontconfig.org |
-// ----------------------------------------------------------------------------- |
- |
-#include <map> |
-#include <string> |
- |
-#include <fontconfig/fontconfig.h> |
- |
-#include "SkDescriptor.h" |
-#include "SkFontHost.h" |
-#include "SkMMapStream.h" |
-#include "SkPaint.h" |
-#include "SkStream.h" |
-#include "SkString.h" |
-#include "SkThread.h" |
-#include "SkTSearch.h" |
- |
-// This is an extern from SkFontHost_FreeType |
-SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name); |
- |
-// ----------------------------------------------------------------------------- |
-// The rest of Skia requires that fonts be identified by a unique unsigned id |
-// and that we be able to load them given the id. What we actually get from |
-// fontconfig is the filename of the font so we keep a locked map from |
-// filenames to fileid numbers and back. |
-// |
-// Note that there's also a unique id in the SkTypeface. This is unique over |
-// both filename and style. Thus we encode that id as (fileid << 8) | style. |
-// Although truetype fonts can support multiple faces in a single file, at the |
-// moment Skia doesn't. |
-// ----------------------------------------------------------------------------- |
-static SkMutex global_fc_map_lock; |
-static std::map<std::string, unsigned> global_fc_map; |
-static std::map<unsigned, std::string> global_fc_map_inverted; |
-static std::map<uint32_t, SkTypeface *> global_fc_typefaces; |
-static unsigned global_fc_map_next_id = 0; |
- |
-// This is the maximum size of the font cache. |
-static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB |
- |
-static unsigned UniqueIdToFileId(unsigned uniqueid) |
-{ |
- return uniqueid >> 8; |
-} |
- |
-static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid) |
-{ |
- return static_cast<SkTypeface::Style>(uniqueid & 0xff); |
-} |
- |
-static unsigned FileIdAndStyleToUniqueId(unsigned fileid, |
- SkTypeface::Style style) |
-{ |
- SkASSERT(style & 0xff == style); |
- return (fileid << 8) | static_cast<int>(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(bool is_fallback, |
- const char* type, FcType vtype, const void* value, |
- ...) |
-{ |
- va_list ap; |
- va_start(ap, value); |
- |
- FcPattern* pattern = FcPatternCreate(); |
- bool family_requested = false; |
- |
- for (;;) { |
- FcValue fcvalue; |
- fcvalue.type = vtype; |
- switch (vtype) { |
- case FcTypeString: |
- fcvalue.u.s = (FcChar8*) value; |
- break; |
- case FcTypeInteger: |
- fcvalue.u.i = (int) value; |
- break; |
- default: |
- SkASSERT(!"FontMatch unhandled type"); |
- } |
- FcPatternAdd(pattern, type, fcvalue, 0); |
- |
- if (vtype == FcTypeString && strcmp(type, FC_FAMILY) == 0) |
- family_requested = true; |
- |
- type = va_arg(ap, const char *); |
- if (!type) |
- break; |
- // FcType is promoted to int when passed through ... |
- vtype = static_cast<FcType>(va_arg(ap, int)); |
- value = va_arg(ap, const void *); |
- }; |
- va_end(ap); |
- |
- FcConfigSubstitute(0, pattern, FcMatchPattern); |
- FcDefaultSubstitute(pattern); |
- |
- // Font matching: |
- // CSS often specifies a fallback list of families: |
- // font-family: a, b, c, serif; |
- // However, fontconfig will always do its best to find *a* font when asked |
- // for something so we need a way to tell if the match which it has found is |
- // "good enough" for us. Otherwise, we can return NULL which gets piped up |
- // and lets WebKit know to try the next CSS family name. However, fontconfig |
- // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we |
- // wish to support that. |
- // |
- // Thus, if a specific family is requested we set @family_requested. Then we |
- // record two strings: the family name after config processing and the |
- // family name after resolving. If the two are equal, it's a good match. |
- // |
- // So consider the case where a user has mapped Arial to Helvetica in their |
- // config. |
- // requested family: "Arial" |
- // post_config_family: "Helvetica" |
- // post_match_family: "Helvetica" |
- // -> good match |
- // |
- // and for a missing font: |
- // requested family: "Monaco" |
- // post_config_family: "Monaco" |
- // post_match_family: "Times New Roman" |
- // -> BAD match |
- FcChar8* post_config_family; |
- FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family); |
- |
- FcResult result; |
- FcPattern* match = FcFontMatch(0, pattern, &result); |
- if (!match) { |
- FcPatternDestroy(pattern); |
- return NULL; |
- } |
- |
- FcChar8* post_match_family; |
- FcPatternGetString(match, FC_FAMILY, 0, &post_match_family); |
- const bool family_names_match = |
- !family_requested ? |
- true : |
- strcasecmp((char *) post_config_family, (char *) post_match_family) == 0; |
- |
- FcPatternDestroy(pattern); |
- |
- if (!family_names_match && !is_fallback) { |
- FcPatternDestroy(match); |
- return NULL; |
- } |
- |
- return match; |
-} |
- |
-// ----------------------------------------------------------------------------- |
-// 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<std::string, unsigned>::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; |
- } |
-} |
- |
-SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, |
- const char familyName[], |
- SkTypeface::Style style) |
-{ |
- const char* resolved_family_name = NULL; |
- FcPattern* face_match = NULL; |
- |
- 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 = UniqueIdToFileId(familyFace->uniqueID()); |
- std::map<unsigned, std::string>::const_iterator i = |
- global_fc_map_inverted.find(fileid); |
- if (i == global_fc_map_inverted.end()) |
- return NULL; |
- |
- FcInit(); |
- face_match = FontMatch(false, 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<char*>(family); |
- } else if (familyName) { |
- resolved_family_name = familyName; |
- } else { |
- return NULL; |
- } |
- |
- { |
- SkAutoMutexAcquire ac(global_fc_map_lock); |
- FcInit(); |
- } |
- |
- // At this point, we have a resolved_family_name from somewhere |
- SkASSERT(resolved_family_name); |
- |
- 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 = FontMatch(false, |
- FC_FAMILY, FcTypeString, resolved_family_name, |
- FC_WEIGHT, FcTypeInteger, 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<char*>(filename)); |
- const unsigned id = FileIdAndStyleToUniqueId(fileid, style); |
- SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id)); |
- FcPatternDestroy(match); |
- |
- { |
- SkAutoMutexAcquire ac(global_fc_map_lock); |
- global_fc_typefaces[id] = typeface; |
- } |
- |
- return typeface; |
-} |
- |
-SkTypeface* SkFontHost::ResolveTypeface(uint32_t id) |
-{ |
- SkAutoMutexAcquire ac(global_fc_map_lock); |
- const std::map<uint32_t, SkTypeface *>::iterator |
- i = global_fc_typefaces.find(id); |
- |
- if (i == global_fc_typefaces.end()) |
- return NULL; |
- return i->second; |
-} |
- |
-SkStream* SkFontHost::OpenStream(uint32_t id) |
-{ |
- SkAutoMutexAcquire ac(global_fc_map_lock); |
- const unsigned fileid = UniqueIdToFileId(id); |
- |
- std::map<unsigned, std::string>::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())); |
-} |
- |
-void SkFontHost::CloseStream(uint32_t fontID, SkStream* stream) |
-{ |
-} |
- |
-SkTypeface* SkFontHost::CreateTypeface(SkStream* stream) |
-{ |
- SkASSERT(!"SkFontHost::CreateTypeface unimplemented"); |
- return NULL; |
-} |
- |
-SkTypeface* SkFontHost::Deserialize(SkStream* stream) { |
- SkASSERT(!"SkFontHost::Deserialize unimplemented"); |
- return NULL; |
-} |
- |
-void SkFontHost::Serialize(const SkTypeface*, SkWStream*) { |
- SkASSERT(!"SkFontHost::Serialize unimplemented"); |
-} |
- |
-SkScalerContext* SkFontHost::CreateFallbackScalerContext |
- (const SkScalerContext::Rec& rec) { |
- FcPattern* match = FontMatch(true, FC_FAMILY, FcTypeString, "serif", |
- NULL); |
- |
- // This will fail when we have no fonts on the system. |
- SkASSERT(match); |
- |
- FcChar8* filename; |
- if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) { |
- FcPatternDestroy(match); |
- return NULL; |
- } |
- // Now @filename is pointing into @match |
- |
- const unsigned id = FileIdFromFilename(reinterpret_cast<char*>(filename)); |
- FcPatternDestroy(match); |
- |
- SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); |
- SkDescriptor* desc = ad.getDesc(); |
- |
- desc->init(); |
- SkScalerContext::Rec* newRec = |
- (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, |
- sizeof(rec), &rec); |
- newRec->fFontID = id; |
- desc->computeChecksum(); |
- |
- return SkFontHost::CreateScalerContext(desc); |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) |
-{ |
- if (sizeAllocatedSoFar > kFontCacheMemoryBudget) |
- return sizeAllocatedSoFar - kFontCacheMemoryBudget; |
- else |
- return 0; // nothing to do |
-} |