#include "SkStream.h"
#include "SkTypeface.h"
-//#define TRACE_LIFECYCLE
-
-#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(const SkFontStyle& style, SkFontID fontID, bool isFixedPitch)
+ : fUniqueID(fontID), fStyle(style), fIsFixedPitch(isFixedPitch) { }
-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 {
}
};
+namespace {
+
SK_DECLARE_STATIC_MUTEX(gCreateDefaultMutex);
-SkTypeface* SkTypeface::CreateDefault(int style) {
+
+// 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.
return t ? t : SkEmptyTypeface::Create();
}
-void SkTypeface::DeleteDefault(SkTypeface* t) {
- // The SkTypeface returned by SkFontHost::CreateTypeface may _itself_ be a
- // cleverly-shared singleton. This is less than ideal. This means we
- // cannot just assert our ownership and SkDELETE(t) like we'd want to.
- SkSafeUnref(t);
-}
+void sk_unref_typeface(SkTypeface* ptr) { SkSafeUnref(ptr); }
-SkTypeface* SkTypeface::GetDefaultTypeface(Style style) {
- SK_DECLARE_STATIC_LAZY_PTR_ARRAY(SkTypeface, defaults, 4, CreateDefault, DeleteDefault);
+} // namespace
+
+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];
}
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;
+}
+