aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrTextStrike.cpp
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-12 19:53:16 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-12 19:53:16 +0000
commitd38f137e9b813f8193675ebd3dfbfe8bc42639e9 (patch)
tree1e670c378d7b31a4538fde3c2b3e4e29b72c05b5 /src/gpu/GrTextStrike.cpp
parent4d5cb45f3e3e62633304b4911d131cdd02dfd541 (diff)
Move gpu/include/* to include/gpu and gpu/src/* to src/gpu
Review URL: http://codereview.appspot.com/5250070/ git-svn-id: http://skia.googlecode.com/svn/trunk@2471 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu/GrTextStrike.cpp')
-rw-r--r--src/gpu/GrTextStrike.cpp205
1 files changed, 205 insertions, 0 deletions
diff --git a/src/gpu/GrTextStrike.cpp b/src/gpu/GrTextStrike.cpp
new file mode 100644
index 0000000000..b8762adc11
--- /dev/null
+++ b/src/gpu/GrTextStrike.cpp
@@ -0,0 +1,205 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#include "GrAtlas.h"
+#include "GrGpu.h"
+#include "GrRectanizer.h"
+#include "GrTextStrike.h"
+#include "GrTextStrike_impl.h"
+#include "GrRect.h"
+
+GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
+ gpu->ref();
+ fAtlasMgr = NULL;
+
+ fHead = fTail = NULL;
+}
+
+GrFontCache::~GrFontCache() {
+ fCache.deleteAll();
+ delete fAtlasMgr;
+ fGpu->unref();
+}
+
+GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
+ const Key& key) {
+ if (NULL == fAtlasMgr) {
+ fAtlasMgr = new GrAtlasMgr(fGpu);
+ }
+ GrTextStrike* strike = new GrTextStrike(this, scaler->getKey(),
+ scaler->getMaskFormat(), fAtlasMgr);
+ fCache.insert(key, strike);
+
+ if (fHead) {
+ fHead->fPrev = strike;
+ } else {
+ GrAssert(NULL == fTail);
+ fTail = strike;
+ }
+ strike->fPrev = NULL;
+ strike->fNext = fHead;
+ fHead = strike;
+
+ return strike;
+}
+
+void GrFontCache::freeAll() {
+ fCache.deleteAll();
+ delete fAtlasMgr;
+ fAtlasMgr = NULL;
+ fHead = NULL;
+ fTail = NULL;
+}
+
+void GrFontCache::purgeExceptFor(GrTextStrike* preserveStrike) {
+ GrTextStrike* strike = fTail;
+ while (strike) {
+ if (strike == preserveStrike) {
+ strike = strike->fPrev;
+ continue;
+ }
+ GrTextStrike* strikeToPurge = strike;
+ // keep going if we won't free up any atlases with this strike.
+ strike = (NULL == strikeToPurge->fAtlas) ? strikeToPurge->fPrev : NULL;
+ int index = fCache.slowFindIndex(strikeToPurge);
+ GrAssert(index >= 0);
+ fCache.removeAt(index, strikeToPurge->fFontScalerKey->getHash());
+ this->detachStrikeFromList(strikeToPurge);
+ delete strikeToPurge;
+ }
+}
+
+#if GR_DEBUG
+void GrFontCache::validate() const {
+ int count = fCache.count();
+ if (0 == count) {
+ GrAssert(!fHead);
+ GrAssert(!fTail);
+ } else if (1 == count) {
+ GrAssert(fHead == fTail);
+ } else {
+ GrAssert(fHead != fTail);
+ }
+
+ int count2 = 0;
+ const GrTextStrike* strike = fHead;
+ while (strike) {
+ count2 += 1;
+ strike = strike->fNext;
+ }
+ GrAssert(count == count2);
+
+ count2 = 0;
+ strike = fTail;
+ while (strike) {
+ count2 += 1;
+ strike = strike->fPrev;
+ }
+ GrAssert(count == count2);
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if GR_DEBUG
+ static int gCounter;
+#endif
+
+/*
+ The text strike is specific to a given font/style/matrix setup, which is
+ represented by the GrHostFontScaler object we are given in getGlyph().
+
+ We map a 32bit glyphID to a GrGlyph record, which in turn points to a
+ atlas and a position within that texture.
+ */
+
+GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
+ GrMaskFormat format,
+ GrAtlasMgr* atlasMgr) : fPool(64) {
+ fFontScalerKey = key;
+ fFontScalerKey->ref();
+
+ fFontCache = cache; // no need to ref, it won't go away before we do
+ fAtlasMgr = atlasMgr; // no need to ref, it won't go away before we do
+ fAtlas = NULL;
+
+ fMaskFormat = format;
+
+#if GR_DEBUG
+// GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
+ gCounter += 1;
+#endif
+}
+
+static void FreeGlyph(GrGlyph*& glyph) { glyph->free(); }
+
+GrTextStrike::~GrTextStrike() {
+ GrAtlas::FreeLList(fAtlas);
+ fFontScalerKey->unref();
+ fCache.getArray().visit(FreeGlyph);
+
+#if GR_DEBUG
+ gCounter -= 1;
+// GrPrintf("~GrTextStrike %p %d\n", this, gCounter);
+#endif
+}
+
+GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
+ GrFontScaler* scaler) {
+ GrIRect bounds;
+ if (!scaler->getPackedGlyphBounds(packed, &bounds)) {
+ return NULL;
+ }
+
+ GrGlyph* glyph = fPool.alloc();
+ glyph->init(packed, bounds);
+ fCache.insert(packed, glyph);
+ return glyph;
+}
+
+bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
+#if 0 // testing hack to force us to flush our cache often
+ static int gCounter;
+ if ((++gCounter % 10) == 0) return false;
+#endif
+
+ GrAssert(glyph);
+ GrAssert(scaler);
+ GrAssert(fCache.contains(glyph));
+ if (glyph->fAtlas) {
+ return true;
+ }
+
+ GrAutoRef ar(scaler);
+
+ int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
+ size_t size = glyph->fBounds.area() * bytesPerPixel;
+ SkAutoSMalloc<1024> storage(size);
+ if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
+ glyph->height(),
+ glyph->width() * bytesPerPixel,
+ storage.get())) {
+ return false;
+ }
+
+ GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(),
+ glyph->height(), storage.get(),
+ fMaskFormat,
+ &glyph->fAtlasLocation);
+ if (NULL == atlas) {
+ return false;
+ }
+
+ // update fAtlas as well, since they may be chained in a linklist
+ glyph->fAtlas = fAtlas = atlas;
+ return true;
+}
+
+