*/
#include "SkAdvancedTypefaceMetrics.h"
+#include "SkEndian.h"
#include "SkFontDescriptor.h"
-#include "SkFontHost.h"
-#include "SkOnce.h"
+#include "SkFontMgr.h"
+#include "SkLazyPtr.h"
+#include "SkOTTable_OS_2.h"
#include "SkStream.h"
#include "SkTypeface.h"
-//#define TRACE_LIFECYCLE
+SkTypeface::SkTypeface(const SkFontStyle& style, SkFontID fontID, bool isFixedPitch)
+ : fUniqueID(fontID), fStyle(style), fIsFixedPitch(isFixedPitch) { }
-#ifdef TRACE_LIFECYCLE
- static int32_t gTypefaceCounter;
-#endif
-
-SkTypeface::SkTypeface(Style style, SkFontID fontID, bool isFixedPitch)
- : fUniqueID(fontID), fStyle(style), fIsFixedPitch(isFixedPitch) {
-#ifdef TRACE_LIFECYCLE
- SkDebugf("SkTypeface: create %p fontID %d total %d\n",
- this, fontID, ++gTypefaceCounter);
-#endif
-}
-
-SkTypeface::~SkTypeface() {
-#ifdef TRACE_LIFECYCLE
- SkDebugf("SkTypeface: destroy %p fontID %d total %d\n",
- this, fUniqueID, --gTypefaceCounter);
-#endif
-}
+SkTypeface::~SkTypeface() { }
///////////////////////////////////////////////////////////////////////////////
return SkNEW(SkEmptyTypeface);
}
protected:
- SkEmptyTypeface() : SkTypeface(SkTypeface::kNormal, 0, true) { }
+ SkEmptyTypeface() : SkTypeface(SkFontStyle(), 0, true) { }
virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE { return NULL; }
virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE {
public:
virtual bool next(SkTypeface::LocalizedString*) SK_OVERRIDE { return false; }
};
+ virtual void onGetFamilyName(SkString* familyName) const SK_OVERRIDE {
+ familyName->reset();
+ }
virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE {
return SkNEW(EmptyLocalizedStrings);
};
}
};
-static SkTypeface* gDefaultTypefaces[] = { NULL, NULL, NULL, NULL };
-static const size_t FONT_STYLE_COUNT = SK_ARRAY_COUNT(gDefaultTypefaces);
-static SkOnceFlag gDefaultTypefaceOnce[FONT_STYLE_COUNT] = {
- SK_ONCE_INIT, SK_ONCE_INIT, SK_ONCE_INIT, SK_ONCE_INIT
-};
-template <uintmax_t N> struct SkTIsPow2 {
- static const bool value = (N & (N - 1)) == 0;
-};
-SK_COMPILE_ASSERT(SkTIsPow2<FONT_STYLE_COUNT>::value, FONT_STYLE_COUNT_not_power_of_2);
+namespace {
-void SkTypeface::create_default_typeface(Style style) {
- if (NULL == gDefaultTypefaces[style]) {
- gDefaultTypefaces[style] = SkFontHost::CreateTypeface(NULL, NULL, style);
- }
- if (NULL == gDefaultTypefaces[style]) {
- // FIXME: Use a singleton for SkEmptyTypeface.
- gDefaultTypefaces[style] = SkEmptyTypeface::Create();
- }
+SK_DECLARE_STATIC_MUTEX(gCreateDefaultMutex);
+
+// As a template arguments, these must have external linkage.
+SkTypeface* sk_create_default_typeface(int style) {
+ // If backed by fontconfig, it's not safe to call SkFontHost::CreateTypeface concurrently.
+ // To be safe, we serialize here with a mutex so only one call to
+ // CreateTypeface is happening at any given time.
+ // TODO(bungeman, mtklein): This is sad. Make our fontconfig code safe?
+ SkAutoMutexAcquire lock(&gCreateDefaultMutex);
+
+ SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
+ SkTypeface* t = fm->legacyCreateTypeface(NULL, style);;
+ return t ? t : SkEmptyTypeface::Create();
}
-SkTypeface* SkTypeface::GetDefaultTypeface(Style style) {
- SkASSERT((size_t)style < FONT_STYLE_COUNT);
+void sk_unref_typeface(SkTypeface* ptr) { SkSafeUnref(ptr); }
- // mask off any other bits to avoid a crash in SK_RELEASE
- style = (Style)(style & (FONT_STYLE_COUNT - 1));
+} // namespace
- SkOnce(&gDefaultTypefaceOnce[style], SkTypeface::create_default_typeface, style);
- return gDefaultTypefaces[style];
+SK_DECLARE_STATIC_LAZY_PTR_ARRAY(SkTypeface, defaults, 4,
+ sk_create_default_typeface, sk_unref_typeface);
+
+SkTypeface* SkTypeface::GetDefaultTypeface(Style style) {
+ SkASSERT((int)style < 4);
+ return defaults[style];
}
SkTypeface* SkTypeface::RefDefault(Style style) {
if (NULL == name) {
return RefDefault(style);
}
- return SkFontHost::CreateTypeface(NULL, name, style);
+ SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
+ return fm->legacyCreateTypeface(name, style);
}
SkTypeface* SkTypeface::CreateFromTypeface(const SkTypeface* family, Style s) {
- if (family && family->style() == s) {
+ if (!family) {
+ return SkTypeface::RefDefault(s);
+ }
+
+ if (family->style() == s) {
family->ref();
return const_cast<SkTypeface*>(family);
}
- return SkFontHost::CreateTypeface(family, NULL, s);
+
+ SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
+ bool bold = s & SkTypeface::kBold;
+ bool italic = s & SkTypeface::kItalic;
+ SkFontStyle newStyle = SkFontStyle(bold ? SkFontStyle::kBold_Weight
+ : SkFontStyle::kNormal_Weight,
+ SkFontStyle::kNormal_Width,
+ italic ? SkFontStyle::kItalic_Slant
+ : SkFontStyle::kUpright_Slant);
+ return fm->matchFaceStyle(family, newStyle);
}
-SkTypeface* SkTypeface::CreateFromStream(SkStream* stream) {
- return SkFontHost::CreateTypefaceFromStream(stream);
+SkTypeface* SkTypeface::CreateFromStream(SkStream* stream, int index) {
+ SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
+ return fm->createFromStream(stream, index);
}
-SkTypeface* SkTypeface::CreateFromFile(const char path[]) {
- return SkFontHost::CreateTypefaceFromFile(path);
+SkTypeface* SkTypeface::CreateFromFile(const char path[], int index) {
+ SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
+ return fm->createFromFile(path, index);
}
///////////////////////////////////////////////////////////////////////////////
SkFontDescriptor desc(this->style());
this->onGetFontDescriptor(&desc, &isLocal);
- desc.serialize(wstream);
- if (isLocal) {
- int ttcIndex; // TODO: write this to the stream?
- SkAutoTUnref<SkStream> rstream(this->openStream(&ttcIndex));
- if (rstream.get()) {
- size_t length = rstream->getLength();
- wstream->writePackedUInt(length);
- wstream->writeStream(rstream, length);
- } else {
- wstream->writePackedUInt(0);
- }
- } else {
- wstream->writePackedUInt(0);
+ if (isLocal && NULL == desc.getFontData()) {
+ int ttcIndex;
+ desc.setFontData(this->onOpenStream(&ttcIndex));
+ desc.setFontIndex(ttcIndex);
}
+
+ desc.serialize(wstream);
}
SkTypeface* SkTypeface::Deserialize(SkStream* stream) {
SkFontDescriptor desc(stream);
- size_t length = stream->readPackedUInt();
- if (length > 0) {
- void* addr = sk_malloc_flags(length, 0);
- if (addr) {
- SkAutoTUnref<SkMemoryStream> localStream(SkNEW(SkMemoryStream));
- localStream->setMemoryOwned(addr, length);
-
- if (stream->read(addr, length) == length) {
- return SkTypeface::CreateFromStream(localStream.get());
- } else {
- // Failed to read the full font data, so fall through and try to create from name.
- // If this is because of EOF, all subsequent reads from the stream will be EOF.
- // If this is because of a stream error, the stream is in an error state,
- // do not attempt to skip any remaining bytes.
- }
- } else {
- // failed to allocate, so just skip and create-from-name
- stream->skip(length);
+ SkStream* data = desc.getFontData();
+ if (data) {
+ SkTypeface* typeface = SkTypeface::CreateFromStream(data, desc.getFontIndex());
+ if (typeface) {
+ return typeface;
}
}
-
return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle());
}
}
void SkTypeface::getFamilyName(SkString* name) const {
- bool isLocal = false;
- SkFontDescriptor desc(this->style());
- this->onGetFontDescriptor(&desc, &isLocal);
- name->set(desc.getFamilyName());
+ SkASSERT(name);
+ this->onGetFamilyName(name);
}
SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics(
SkAdvancedTypefaceMetrics::PerGlyphInfo info,
const uint32_t* glyphIDs,
uint32_t glyphIDsCount) const {
- return this->onGetAdvancedTypefaceMetrics(info, glyphIDs, glyphIDsCount);
+ SkAdvancedTypefaceMetrics* result =
+ this->onGetAdvancedTypefaceMetrics(info, glyphIDs, glyphIDsCount);
+ if (result && result->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
+ struct SkOTTableOS2 os2table;
+ if (this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG), 0,
+ sizeof(os2table), &os2table) > 0) {
+ if (os2table.version.v2.fsType.field.Bitmap ||
+ (os2table.version.v2.fsType.field.Restricted &&
+ !(os2table.version.v2.fsType.field.PreviewPrint ||
+ os2table.version.v2.fsType.field.Editable))) {
+ result->fFlags = SkTBitOr<SkAdvancedTypefaceMetrics::FontFlags>(
+ result->fFlags,
+ SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
+ }
+ if (os2table.version.v2.fsType.field.NoSubsetting) {
+ result->fFlags = SkTBitOr<SkAdvancedTypefaceMetrics::FontFlags>(
+ result->fFlags,
+ SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag);
+ }
+ }
+ }
+ return result;
}
-///////////////////////////////////////////////////////////////////////////////
-
bool SkTypeface::onGetKerningPairAdjustments(const uint16_t glyphs[], int count,
int32_t adjustments[]) const {
return false;
}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkDescriptor.h"
+#include "SkPaint.h"
+
+struct SkTypeface::BoundsComputer {
+ const SkTypeface& fTypeface;
+
+ BoundsComputer(const SkTypeface& tf) : fTypeface(tf) {}
+
+ SkRect* operator()() const {
+ SkRect* rect = SkNEW(SkRect);
+ if (!fTypeface.onComputeBounds(rect)) {
+ rect->setEmpty();
+ }
+ return rect;
+ }
+};
+
+SkRect SkTypeface::getBounds() const {
+ return *fLazyBounds.get(BoundsComputer(*this));
+}
+
+bool SkTypeface::onComputeBounds(SkRect* bounds) const {
+ // we use a big size to ensure lots of significant bits from the scalercontext.
+ // then we scale back down to return our final answer (at 1-pt)
+ const SkScalar textSize = 2048;
+ const SkScalar invTextSize = 1 / textSize;
+
+ SkPaint paint;
+ paint.setTypeface(const_cast<SkTypeface*>(this));
+ paint.setTextSize(textSize);
+ paint.setLinearText(true);
+
+ SkScalerContext::Rec rec;
+ SkScalerContext::MakeRec(paint, NULL, NULL, &rec);
+
+ SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
+ SkDescriptor* desc = ad.getDesc();
+ desc->init();
+ desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
+
+ SkAutoTDelete<SkScalerContext> ctx(this->createScalerContext(desc, true));
+ if (ctx.get()) {
+ SkPaint::FontMetrics fm;
+ ctx->getFontMetrics(&fm);
+ bounds->set(fm.fXMin * invTextSize, fm.fTop * invTextSize,
+ fm.fXMax * invTextSize, fm.fBottom * invTextSize);
+ return true;
+ }
+ return false;
+}
+