michael@0: /* michael@0: * Copyright 2008 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkFontConfigInterface.h" michael@0: #include "SkFontConfigTypeface.h" michael@0: #include "SkFontDescriptor.h" michael@0: #include "SkFontHost.h" michael@0: #include "SkFontHost_FreeType_common.h" michael@0: #include "SkFontStream.h" michael@0: #include "SkStream.h" michael@0: #include "SkTypeface.h" michael@0: #include "SkTypefaceCache.h" michael@0: michael@0: // Defined in SkFontHost_FreeType.cpp michael@0: bool find_name_and_attributes(SkStream* stream, SkString* name, michael@0: SkTypeface::Style* style, bool* isFixedWidth); michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SK_DECLARE_STATIC_MUTEX(gFontConfigInterfaceMutex); michael@0: static SkFontConfigInterface* gFontConfigInterface; michael@0: michael@0: SkFontConfigInterface* SkFontConfigInterface::RefGlobal() { michael@0: SkAutoMutexAcquire ac(gFontConfigInterfaceMutex); michael@0: michael@0: return SkSafeRef(gFontConfigInterface); michael@0: } michael@0: michael@0: SkFontConfigInterface* SkFontConfigInterface::SetGlobal(SkFontConfigInterface* fc) { michael@0: SkAutoMutexAcquire ac(gFontConfigInterfaceMutex); michael@0: michael@0: SkRefCnt_SafeAssign(gFontConfigInterface, fc); michael@0: return fc; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: // convenience function to create the direct interface if none is installed. michael@0: extern SkFontConfigInterface* SkCreateDirectFontConfigInterface(); michael@0: michael@0: static SkFontConfigInterface* RefFCI() { michael@0: for (;;) { michael@0: SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal(); michael@0: if (fci) { michael@0: return fci; michael@0: } michael@0: fci = SkFontConfigInterface::GetSingletonDirectInterface(); michael@0: SkFontConfigInterface::SetGlobal(fci); michael@0: } michael@0: } michael@0: michael@0: // export this to SkFontMgr_fontconfig.cpp until this file just goes away. michael@0: SkFontConfigInterface* SkFontHost_fontconfig_ref_global(); michael@0: SkFontConfigInterface* SkFontHost_fontconfig_ref_global() { michael@0: return RefFCI(); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: struct FindRec { michael@0: FindRec(const char* name, SkTypeface::Style style) michael@0: : fFamilyName(name) // don't need to make a deep copy michael@0: , fStyle(style) {} michael@0: michael@0: const char* fFamilyName; michael@0: SkTypeface::Style fStyle; michael@0: }; michael@0: michael@0: static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) { michael@0: FontConfigTypeface* fci = (FontConfigTypeface*)face; michael@0: const FindRec* rec = (const FindRec*)ctx; michael@0: michael@0: return rec->fStyle == style && fci->isFamilyName(rec->fFamilyName); michael@0: } michael@0: michael@0: SkTypeface* FontConfigTypeface::LegacyCreateTypeface( michael@0: const SkTypeface* familyFace, michael@0: const char familyName[], michael@0: SkTypeface::Style style) { michael@0: SkAutoTUnref fci(RefFCI()); michael@0: if (NULL == fci.get()) { michael@0: return NULL; michael@0: } michael@0: michael@0: if (familyFace) { michael@0: FontConfigTypeface* fct = (FontConfigTypeface*)familyFace; michael@0: familyName = fct->getFamilyName(); michael@0: } michael@0: michael@0: FindRec rec(familyName, style); michael@0: SkTypeface* face = SkTypefaceCache::FindByProcAndRef(find_proc, &rec); michael@0: if (face) { michael@0: // SkDebugf("found cached face <%s> <%s> %p [%d]\n", familyName, ((FontConfigTypeface*)face)->getFamilyName(), face, face->getRefCnt()); michael@0: return face; michael@0: } michael@0: michael@0: SkFontConfigInterface::FontIdentity indentity; michael@0: SkString outFamilyName; michael@0: SkTypeface::Style outStyle; michael@0: michael@0: if (!fci->matchFamilyName(familyName, style, michael@0: &indentity, &outFamilyName, &outStyle)) { michael@0: return NULL; michael@0: } michael@0: michael@0: // check if we, in fact, already have this. perhaps fontconfig aliased the michael@0: // requested name to some other name we actually have... michael@0: rec.fFamilyName = outFamilyName.c_str(); michael@0: rec.fStyle = outStyle; michael@0: face = SkTypefaceCache::FindByProcAndRef(find_proc, &rec); michael@0: if (face) { michael@0: return face; michael@0: } michael@0: michael@0: face = SkNEW_ARGS(FontConfigTypeface, (outStyle, indentity, outFamilyName)); michael@0: SkTypefaceCache::Add(face, style); michael@0: // SkDebugf("add face <%s> <%s> %p [%d]\n", familyName, outFamilyName.c_str(), face, face->getRefCnt()); michael@0: return face; michael@0: } michael@0: michael@0: #ifdef SK_FONTHOST_DOES_NOT_USE_FONTMGR michael@0: michael@0: SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, michael@0: const char familyName[], michael@0: SkTypeface::Style style) { michael@0: return FontConfigTypeface::LegacyCreateTypeface(familyFace, familyName, michael@0: style); michael@0: } michael@0: michael@0: SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { michael@0: if (!stream) { michael@0: return NULL; michael@0: } michael@0: const size_t length = stream->getLength(); michael@0: if (!length) { michael@0: return NULL; michael@0: } michael@0: if (length >= 1024 * 1024 * 1024) { michael@0: return NULL; // don't accept too large fonts (>= 1GB) for safety. michael@0: } michael@0: michael@0: // ask freetype for reported style and if it is a fixed width font michael@0: SkTypeface::Style style = SkTypeface::kNormal; michael@0: bool isFixedWidth = false; michael@0: if (!find_name_and_attributes(stream, NULL, &style, &isFixedWidth)) { michael@0: return NULL; michael@0: } michael@0: michael@0: SkTypeface* face = SkNEW_ARGS(FontConfigTypeface, (style, isFixedWidth, stream)); michael@0: return face; michael@0: } michael@0: michael@0: SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { michael@0: SkAutoTUnref stream(SkStream::NewFromFile(path)); michael@0: return stream.get() ? CreateTypefaceFromStream(stream) : NULL; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkStream* FontConfigTypeface::onOpenStream(int* ttcIndex) const { michael@0: SkStream* stream = this->getLocalStream(); michael@0: if (stream) { michael@0: // should have been provided by CreateFromStream() michael@0: *ttcIndex = 0; michael@0: michael@0: SkAutoTUnref dupStream(stream->duplicate()); michael@0: if (dupStream) { michael@0: return dupStream.detach(); michael@0: } michael@0: michael@0: // TODO: update interface use, remove the following code in this block. michael@0: size_t length = stream->getLength(); michael@0: michael@0: const void* memory = stream->getMemoryBase(); michael@0: if (NULL != memory) { michael@0: return new SkMemoryStream(memory, length, true); michael@0: } michael@0: michael@0: SkAutoTMalloc allocMemory(length); michael@0: stream->rewind(); michael@0: if (length == stream->read(allocMemory.get(), length)) { michael@0: SkAutoTUnref copyStream(new SkMemoryStream()); michael@0: copyStream->setMemoryOwned(allocMemory.detach(), length); michael@0: return copyStream.detach(); michael@0: } michael@0: michael@0: stream->rewind(); michael@0: stream->ref(); michael@0: } else { michael@0: SkAutoTUnref fci(RefFCI()); michael@0: if (NULL == fci.get()) { michael@0: return NULL; michael@0: } michael@0: stream = fci->openStream(this->getIdentity()); michael@0: *ttcIndex = this->getIdentity().fTTCIndex; michael@0: } michael@0: return stream; michael@0: } michael@0: michael@0: void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc, michael@0: bool* isLocalStream) const { michael@0: desc->setFamilyName(this->getFamilyName()); michael@0: *isLocalStream = SkToBool(this->getLocalStream()); michael@0: }