• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2010 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 
11 #include "GrAtlas.h"
12 #include "GrGpu.h"
13 #include "GrRectanizer.h"
14 #include "GrTextStrike.h"
15 #include "GrTextStrike_impl.h"
16 #include "GrRect.h"
17 
GrFontCache(GrGpu * gpu)18 GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
19     gpu->ref();
20     fAtlasMgr = NULL;
21 
22     fHead = fTail = NULL;
23 }
24 
~GrFontCache()25 GrFontCache::~GrFontCache() {
26     fCache.deleteAll();
27     delete fAtlasMgr;
28     fGpu->unref();
29 }
30 
generateStrike(GrFontScaler * scaler,const Key & key)31 GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
32                                           const Key& key) {
33     if (NULL == fAtlasMgr) {
34         fAtlasMgr = new GrAtlasMgr(fGpu);
35     }
36     GrTextStrike* strike = new GrTextStrike(this, scaler->getKey(),
37                                             scaler->getMaskFormat(), fAtlasMgr);
38     fCache.insert(key, strike);
39 
40     if (fHead) {
41         fHead->fPrev = strike;
42     } else {
43         GrAssert(NULL == fTail);
44         fTail = strike;
45     }
46     strike->fPrev = NULL;
47     strike->fNext = fHead;
48     fHead = strike;
49 
50     return strike;
51 }
52 
freeAll()53 void GrFontCache::freeAll() {
54     fCache.deleteAll();
55     delete fAtlasMgr;
56     fAtlasMgr = NULL;
57     fHead = NULL;
58     fTail = NULL;
59 }
60 
purgeExceptFor(GrTextStrike * preserveStrike)61 void GrFontCache::purgeExceptFor(GrTextStrike* preserveStrike) {
62     GrTextStrike* strike = fTail;
63     while (strike) {
64         if (strike == preserveStrike) {
65             strike = strike->fPrev;
66             continue;
67         }
68         GrTextStrike* strikeToPurge = strike;
69         // keep going if we won't free up any atlases with this strike.
70         strike = (NULL == strikeToPurge->fAtlas) ? strikeToPurge->fPrev : NULL;
71         int index = fCache.slowFindIndex(strikeToPurge);
72         GrAssert(index >= 0);
73         fCache.removeAt(index, strikeToPurge->fFontScalerKey->getHash());
74         this->detachStrikeFromList(strikeToPurge);
75         delete strikeToPurge;
76     }
77 }
78 
79 #if GR_DEBUG
validate() const80 void GrFontCache::validate() const {
81     int count = fCache.count();
82     if (0 == count) {
83         GrAssert(!fHead);
84         GrAssert(!fTail);
85     } else if (1 == count) {
86         GrAssert(fHead == fTail);
87     } else {
88         GrAssert(fHead != fTail);
89     }
90 
91     int count2 = 0;
92     const GrTextStrike* strike = fHead;
93     while (strike) {
94         count2 += 1;
95         strike = strike->fNext;
96     }
97     GrAssert(count == count2);
98 
99     count2 = 0;
100     strike = fTail;
101     while (strike) {
102         count2 += 1;
103         strike = strike->fPrev;
104     }
105     GrAssert(count == count2);
106 }
107 #endif
108 
109 ///////////////////////////////////////////////////////////////////////////////
110 
111 #if GR_DEBUG
112     static int gCounter;
113 #endif
114 
115 /*
116     The text strike is specific to a given font/style/matrix setup, which is
117     represented by the GrHostFontScaler object we are given in getGlyph().
118 
119     We map a 32bit glyphID to a GrGlyph record, which in turn points to a
120     atlas and a position within that texture.
121  */
122 
GrTextStrike(GrFontCache * cache,const GrKey * key,GrMaskFormat format,GrAtlasMgr * atlasMgr)123 GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
124                            GrMaskFormat format,
125                            GrAtlasMgr* atlasMgr) : fPool(64) {
126     fFontScalerKey = key;
127     fFontScalerKey->ref();
128 
129     fFontCache = cache;     // no need to ref, it won't go away before we do
130     fAtlasMgr = atlasMgr;   // no need to ref, it won't go away before we do
131     fAtlas = NULL;
132 
133     fMaskFormat = format;
134 
135 #if GR_DEBUG
136 //    GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
137     gCounter += 1;
138 #endif
139 }
140 
FreeGlyph(GrGlyph * & glyph)141 static void FreeGlyph(GrGlyph*& glyph) { glyph->free(); }
142 
~GrTextStrike()143 GrTextStrike::~GrTextStrike() {
144     GrAtlas::FreeLList(fAtlas);
145     fFontScalerKey->unref();
146     fCache.getArray().visit(FreeGlyph);
147 
148 #if GR_DEBUG
149     gCounter -= 1;
150 //    GrPrintf("~GrTextStrike %p %d\n", this, gCounter);
151 #endif
152 }
153 
generateGlyph(GrGlyph::PackedID packed,GrFontScaler * scaler)154 GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
155                                      GrFontScaler* scaler) {
156     GrIRect bounds;
157     if (!scaler->getPackedGlyphBounds(packed, &bounds)) {
158         return NULL;
159     }
160 
161     GrGlyph* glyph = fPool.alloc();
162     glyph->init(packed, bounds);
163     fCache.insert(packed, glyph);
164     return glyph;
165 }
166 
getGlyphAtlas(GrGlyph * glyph,GrFontScaler * scaler)167 bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
168 #if 0   // testing hack to force us to flush our cache often
169     static int gCounter;
170     if ((++gCounter % 10) == 0) return false;
171 #endif
172 
173     GrAssert(glyph);
174     GrAssert(scaler);
175     GrAssert(fCache.contains(glyph));
176     if (glyph->fAtlas) {
177         return true;
178     }
179 
180     GrAutoRef ar(scaler);
181 
182     int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
183     size_t size = glyph->fBounds.area() * bytesPerPixel;
184     SkAutoSMalloc<1024> storage(size);
185     if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
186                                      glyph->height(),
187                                      glyph->width() * bytesPerPixel,
188                                      storage.get())) {
189         return false;
190     }
191 
192     GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(),
193                                            glyph->height(), storage.get(),
194                                            fMaskFormat,
195                                            &glyph->fAtlasLocation);
196     if (NULL == atlas) {
197         return false;
198     }
199 
200     // update fAtlas as well, since they may be chained in a linklist
201     glyph->fAtlas = fAtlas = atlas;
202     return true;
203 }
204 
205 
206