blob: 6cdb61cdb5a99c20dba1418e797671730d2437e2 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
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
26GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
27 gpu->ref();
28 fAtlasMgr = NULL;
29
30 fHead = fTail = NULL;
31}
32
33GrFontCache::~GrFontCache() {
34 fCache.deleteAll();
35 delete fAtlasMgr;
36 fGpu->unref();
37}
38
39GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
40 const Key& key) {
41 if (NULL == fAtlasMgr) {
42 fAtlasMgr = new GrAtlasMgr(fGpu);
43 }
reed@google.com98539c62011-03-15 15:40:16 +000044 GrTextStrike* strike = new GrTextStrike(this, scaler->getKey(),
45 scaler->getMaskFormat(), fAtlasMgr);
reed@google.comac10a2d2010-12-22 21:39:39 +000046 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
61void GrFontCache::abandonAll() {
62 fCache.deleteAll();
63 if (fAtlasMgr) {
64 fAtlasMgr->abandonAll();
65 delete fAtlasMgr;
66 fAtlasMgr = NULL;
67 }
68}
69
70void GrFontCache::freeAll() {
71 fCache.deleteAll();
72 delete fAtlasMgr;
73 fAtlasMgr = NULL;
74}
75
76void GrFontCache::purgeExceptFor(GrTextStrike* preserveStrike) {
77 GrTextStrike* strike = fTail;
78 if (strike == preserveStrike) {
79 strike = strike->fPrev;
80 }
81 if (strike) {
82 int index = fCache.slowFindIndex(strike);
83 GrAssert(index >= 0);
84 fCache.removeAt(index, strike->fFontScalerKey->getHash());
85 this->detachStrikeFromList(strike);
86 delete strike;
87 }
88}
89
90#if GR_DEBUG
91void GrFontCache::validate() const {
92 int count = fCache.count();
93 if (0 == count) {
94 GrAssert(!fHead);
95 GrAssert(!fTail);
96 } else if (1 == count) {
97 GrAssert(fHead == fTail);
98 } else {
99 GrAssert(fHead != fTail);
100 }
101
102 int count2 = 0;
103 const GrTextStrike* strike = fHead;
104 while (strike) {
105 count2 += 1;
106 strike = strike->fNext;
107 }
108 GrAssert(count == count2);
109
110 count2 = 0;
111 strike = fTail;
112 while (strike) {
113 count2 += 1;
114 strike = strike->fPrev;
115 }
116 GrAssert(count == count2);
117}
118#endif
119
120///////////////////////////////////////////////////////////////////////////////
121
122#if GR_DEBUG
123 static int gCounter;
124#endif
125
126/*
127 The text strike is specific to a given font/style/matrix setup, which is
128 represented by the GrHostFontScaler object we are given in getGlyph().
129
130 We map a 32bit glyphID to a GrGlyph record, which in turn points to a
131 atlas and a position within that texture.
132 */
133
134GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
reed@google.com98539c62011-03-15 15:40:16 +0000135 GrMaskFormat format,
reed@google.comac10a2d2010-12-22 21:39:39 +0000136 GrAtlasMgr* atlasMgr) : fPool(64) {
137 fFontScalerKey = key;
138 fFontScalerKey->ref();
139
140 fFontCache = cache; // no need to ref, it won't go away before we do
141 fAtlasMgr = atlasMgr; // no need to ref, it won't go away before we do
142 fAtlas = NULL;
143
reed@google.com98539c62011-03-15 15:40:16 +0000144 fMaskFormat = format;
145
reed@google.comac10a2d2010-12-22 21:39:39 +0000146#if GR_DEBUG
147 GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
148 gCounter += 1;
149#endif
150}
151
152static void FreeGlyph(GrGlyph*& glyph) { glyph->free(); }
153
154GrTextStrike::~GrTextStrike() {
155 GrAtlas::FreeLList(fAtlas);
156 fFontScalerKey->unref();
157 fCache.getArray().visit(FreeGlyph);
158
159#if GR_DEBUG
160 gCounter -= 1;
161 GrPrintf("~GrTextStrike %p %d\n", this, gCounter);
162#endif
163}
164
165GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
166 GrFontScaler* scaler) {
167 GrIRect bounds;
168 if (!scaler->getPackedGlyphBounds(packed, &bounds)) {
169 return NULL;
170 }
171
172 GrGlyph* glyph = fPool.alloc();
173 glyph->init(packed, bounds);
174 fCache.insert(packed, glyph);
175 return glyph;
176}
177
178bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
179 GrAssert(glyph);
180 GrAssert(scaler);
181 GrAssert(fCache.contains(glyph));
182 if (glyph->fAtlas) {
183 return true;
184 }
185
186 GrAutoRef ar(scaler);
reed@google.com98539c62011-03-15 15:40:16 +0000187
188 int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
189 size_t size = glyph->fBounds.area() * bytesPerPixel;
reed@google.comac10a2d2010-12-22 21:39:39 +0000190 GrAutoSMalloc<1024> storage(size);
191 if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
reed@google.com98539c62011-03-15 15:40:16 +0000192 glyph->height(),
193 glyph->width() * bytesPerPixel,
reed@google.comac10a2d2010-12-22 21:39:39 +0000194 storage.get())) {
195 return false;
196 }
197
198 GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(),
199 glyph->height(), storage.get(),
reed@google.com98539c62011-03-15 15:40:16 +0000200 fMaskFormat,
reed@google.comac10a2d2010-12-22 21:39:39 +0000201 &glyph->fAtlasLocation);
202 if (NULL == atlas) {
203 return false;
204 }
205
206 // update fAtlas as well, since they may be chained in a linklist
207 glyph->fAtlas = fAtlas = atlas;
208 return true;
209}
210
211