blob: a245997d20ee7653b16400d24b5ff8250b64fb68 [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
reed@google.comac10a2d2010-12-22 21:39:39 +000061void GrFontCache::freeAll() {
62 fCache.deleteAll();
63 delete fAtlasMgr;
64 fAtlasMgr = NULL;
bsalomon@google.com8fe72472011-03-30 21:26:44 +000065 fHead = NULL;
66 fTail = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000067}
68
69void 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
84void 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
127GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
reed@google.com98539c62011-03-15 15:40:16 +0000128 GrMaskFormat format,
reed@google.comac10a2d2010-12-22 21:39:39 +0000129 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
reed@google.com98539c62011-03-15 15:40:16 +0000137 fMaskFormat = format;
138
reed@google.comac10a2d2010-12-22 21:39:39 +0000139#if GR_DEBUG
140 GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
141 gCounter += 1;
142#endif
143}
144
145static void FreeGlyph(GrGlyph*& glyph) { glyph->free(); }
146
147GrTextStrike::~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
158GrGlyph* 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
171bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
172 GrAssert(glyph);
173 GrAssert(scaler);
174 GrAssert(fCache.contains(glyph));
175 if (glyph->fAtlas) {
176 return true;
177 }
178
179 GrAutoRef ar(scaler);
reed@google.com98539c62011-03-15 15:40:16 +0000180
181 int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
182 size_t size = glyph->fBounds.area() * bytesPerPixel;
reed@google.comac10a2d2010-12-22 21:39:39 +0000183 GrAutoSMalloc<1024> storage(size);
184 if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
reed@google.com98539c62011-03-15 15:40:16 +0000185 glyph->height(),
186 glyph->width() * bytesPerPixel,
reed@google.comac10a2d2010-12-22 21:39:39 +0000187 storage.get())) {
188 return false;
189 }
190
191 GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(),
192 glyph->height(), storage.get(),
reed@google.com98539c62011-03-15 15:40:16 +0000193 fMaskFormat,
reed@google.comac10a2d2010-12-22 21:39:39 +0000194 &glyph->fAtlasLocation);
195 if (NULL == atlas) {
196 return false;
197 }
198
199 // update fAtlas as well, since they may be chained in a linklist
200 glyph->fAtlas = fAtlas = atlas;
201 return true;
202}
203
204