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