blob: 071c5d272486eadc77a36200e337e6bc15e19088 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2010 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00006 */
7
reed@google.comac10a2d2010-12-22 21:39:39 +00008#include "GrAtlas.h"
9#include "GrGpu.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000010#include "GrRectanizer.h"
11#include "GrTextStrike.h"
12#include "GrTextStrike_impl.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000013
reed@google.comfa35e3d2012-06-26 20:16:17 +000014SK_DEFINE_INST_COUNT(GrFontScaler)
15SK_DEFINE_INST_COUNT(GrKey)
16
17///////////////////////////////////////////////////////////////////////////////
18
reed@google.comac10a2d2010-12-22 21:39:39 +000019GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
20 gpu->ref();
21 fAtlasMgr = NULL;
22
23 fHead = fTail = NULL;
24}
25
26GrFontCache::~GrFontCache() {
27 fCache.deleteAll();
28 delete fAtlasMgr;
29 fGpu->unref();
30}
31
32GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
33 const Key& key) {
34 if (NULL == fAtlasMgr) {
tomhudson@google.comc377baf2012-07-09 20:17:56 +000035 fAtlasMgr = SkNEW_ARGS(GrAtlasMgr, (fGpu));
reed@google.comac10a2d2010-12-22 21:39:39 +000036 }
tomhudson@google.comc377baf2012-07-09 20:17:56 +000037 GrTextStrike* strike = SkNEW_ARGS(GrTextStrike,
38 (this, scaler->getKey(),
39 scaler->getMaskFormat(), fAtlasMgr));
reed@google.comac10a2d2010-12-22 21:39:39 +000040 fCache.insert(key, strike);
41
42 if (fHead) {
43 fHead->fPrev = strike;
44 } else {
45 GrAssert(NULL == fTail);
46 fTail = strike;
47 }
48 strike->fPrev = NULL;
49 strike->fNext = fHead;
50 fHead = strike;
51
52 return strike;
53}
54
reed@google.comac10a2d2010-12-22 21:39:39 +000055void GrFontCache::freeAll() {
56 fCache.deleteAll();
57 delete fAtlasMgr;
58 fAtlasMgr = NULL;
bsalomon@google.com8fe72472011-03-30 21:26:44 +000059 fHead = NULL;
60 fTail = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000061}
62
63void GrFontCache::purgeExceptFor(GrTextStrike* preserveStrike) {
64 GrTextStrike* strike = fTail;
bsalomon@google.com7359eae2011-06-21 21:18:25 +000065 while (strike) {
66 if (strike == preserveStrike) {
67 strike = strike->fPrev;
68 continue;
69 }
70 GrTextStrike* strikeToPurge = strike;
71 // keep going if we won't free up any atlases with this strike.
72 strike = (NULL == strikeToPurge->fAtlas) ? strikeToPurge->fPrev : NULL;
73 int index = fCache.slowFindIndex(strikeToPurge);
reed@google.comac10a2d2010-12-22 21:39:39 +000074 GrAssert(index >= 0);
bsalomon@google.com7359eae2011-06-21 21:18:25 +000075 fCache.removeAt(index, strikeToPurge->fFontScalerKey->getHash());
76 this->detachStrikeFromList(strikeToPurge);
77 delete strikeToPurge;
reed@google.comac10a2d2010-12-22 21:39:39 +000078 }
79}
80
81#if GR_DEBUG
82void GrFontCache::validate() const {
83 int count = fCache.count();
84 if (0 == count) {
85 GrAssert(!fHead);
86 GrAssert(!fTail);
87 } else if (1 == count) {
88 GrAssert(fHead == fTail);
89 } else {
90 GrAssert(fHead != fTail);
91 }
92
93 int count2 = 0;
94 const GrTextStrike* strike = fHead;
95 while (strike) {
96 count2 += 1;
97 strike = strike->fNext;
98 }
99 GrAssert(count == count2);
100
101 count2 = 0;
102 strike = fTail;
103 while (strike) {
104 count2 += 1;
105 strike = strike->fPrev;
106 }
107 GrAssert(count == count2);
108}
109#endif
110
111///////////////////////////////////////////////////////////////////////////////
112
113#if GR_DEBUG
114 static int gCounter;
115#endif
116
117/*
118 The text strike is specific to a given font/style/matrix setup, which is
119 represented by the GrHostFontScaler object we are given in getGlyph().
120
121 We map a 32bit glyphID to a GrGlyph record, which in turn points to a
122 atlas and a position within that texture.
123 */
124
125GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
reed@google.com98539c62011-03-15 15:40:16 +0000126 GrMaskFormat format,
reed@google.comac10a2d2010-12-22 21:39:39 +0000127 GrAtlasMgr* atlasMgr) : fPool(64) {
128 fFontScalerKey = key;
129 fFontScalerKey->ref();
130
131 fFontCache = cache; // no need to ref, it won't go away before we do
132 fAtlasMgr = atlasMgr; // no need to ref, it won't go away before we do
133 fAtlas = NULL;
134
reed@google.com98539c62011-03-15 15:40:16 +0000135 fMaskFormat = format;
136
reed@google.comac10a2d2010-12-22 21:39:39 +0000137#if GR_DEBUG
reed@google.com3ef80cf2011-07-05 19:09:47 +0000138// GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000139 gCounter += 1;
140#endif
141}
142
143static void FreeGlyph(GrGlyph*& glyph) { glyph->free(); }
144
145GrTextStrike::~GrTextStrike() {
146 GrAtlas::FreeLList(fAtlas);
147 fFontScalerKey->unref();
bsalomon@google.com21cbec42013-01-07 17:23:00 +0000148 fCache.getArray().visitAll(FreeGlyph);
reed@google.comac10a2d2010-12-22 21:39:39 +0000149
150#if GR_DEBUG
151 gCounter -= 1;
reed@google.com3ef80cf2011-07-05 19:09:47 +0000152// GrPrintf("~GrTextStrike %p %d\n", this, gCounter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000153#endif
154}
155
156GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
157 GrFontScaler* scaler) {
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000158 SkIRect bounds;
reed@google.comac10a2d2010-12-22 21:39:39 +0000159 if (!scaler->getPackedGlyphBounds(packed, &bounds)) {
160 return NULL;
161 }
162
163 GrGlyph* glyph = fPool.alloc();
164 glyph->init(packed, bounds);
165 fCache.insert(packed, glyph);
166 return glyph;
167}
168
169bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
reed@google.com0ebe81a2011-04-04 20:06:59 +0000170#if 0 // testing hack to force us to flush our cache often
171 static int gCounter;
172 if ((++gCounter % 10) == 0) return false;
173#endif
174
reed@google.comac10a2d2010-12-22 21:39:39 +0000175 GrAssert(glyph);
176 GrAssert(scaler);
177 GrAssert(fCache.contains(glyph));
178 if (glyph->fAtlas) {
179 return true;
180 }
181
182 GrAutoRef ar(scaler);
reed@google.com98539c62011-03-15 15:40:16 +0000183
184 int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
185 size_t size = glyph->fBounds.area() * bytesPerPixel;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000186 SkAutoSMalloc<1024> storage(size);
reed@google.comac10a2d2010-12-22 21:39:39 +0000187 if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
reed@google.com98539c62011-03-15 15:40:16 +0000188 glyph->height(),
189 glyph->width() * bytesPerPixel,
reed@google.comac10a2d2010-12-22 21:39:39 +0000190 storage.get())) {
191 return false;
192 }
193
194 GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(),
195 glyph->height(), storage.get(),
reed@google.com98539c62011-03-15 15:40:16 +0000196 fMaskFormat,
reed@google.comac10a2d2010-12-22 21:39:39 +0000197 &glyph->fAtlasLocation);
198 if (NULL == atlas) {
199 return false;
200 }
201
202 // update fAtlas as well, since they may be chained in a linklist
203 glyph->fAtlas = fAtlas = atlas;
204 return true;
205}