Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrTextStrike.cpp
1 /*
2  * 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.
6  */
7
8 #include "GrAtlas.h"
9 #include "GrGpu.h"
10 #include "GrRectanizer.h"
11 #include "GrTextStrike.h"
12 #include "GrTextStrike_impl.h"
13 #include "SkString.h"
14
15 #include "SkDistanceFieldGen.h"
16
17 ///////////////////////////////////////////////////////////////////////////////
18
19 #define FONT_CACHE_STATS 0
20 #if FONT_CACHE_STATS
21 static int g_PurgeCount = 0;
22 #endif
23
24 GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
25     gpu->ref();
26     for (int i = 0; i < kAtlasCount; ++i) {
27         fAtlasMgr[i] = NULL;
28     }
29
30     fHead = fTail = NULL;
31 }
32
33 GrFontCache::~GrFontCache() {
34     fCache.deleteAll();
35     for (int i = 0; i < kAtlasCount; ++i) {
36         delete fAtlasMgr[i];
37     }
38     fGpu->unref();
39 #if FONT_CACHE_STATS
40       GrPrintf("Num purges: %d\n", g_PurgeCount);
41 #endif
42 }
43
44 static GrPixelConfig mask_format_to_pixel_config(GrMaskFormat format) {
45     static const GrPixelConfig sPixelConfigs[] = {
46         kAlpha_8_GrPixelConfig,
47         kRGB_565_GrPixelConfig,
48         kSkia8888_GrPixelConfig,
49         kSkia8888_GrPixelConfig
50     };
51     SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sPixelConfigs) == kMaskFormatCount, array_size_mismatch);
52
53     return sPixelConfigs[format];
54 }
55
56 static int mask_format_to_atlas_index(GrMaskFormat format) {
57     static const int sAtlasIndices[] = {
58         GrFontCache::kA8_AtlasType,
59         GrFontCache::k565_AtlasType,
60         GrFontCache::k8888_AtlasType,
61         GrFontCache::k8888_AtlasType
62     };
63     SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, array_size_mismatch);
64
65     SkASSERT(sAtlasIndices[format] < GrFontCache::kAtlasCount);
66     return sAtlasIndices[format];
67 }
68
69 GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
70                                           const Key& key) {
71     GrMaskFormat format = scaler->getMaskFormat();
72     GrPixelConfig config = mask_format_to_pixel_config(format);
73     int atlasIndex = mask_format_to_atlas_index(format);
74     if (NULL == fAtlasMgr[atlasIndex]) {
75         fAtlasMgr[atlasIndex] = SkNEW_ARGS(GrAtlasMgr, (fGpu, config));
76     }
77     GrTextStrike* strike = SkNEW_ARGS(GrTextStrike,
78                                       (this, scaler->getKey(), format, fAtlasMgr[atlasIndex]));
79     fCache.insert(key, strike);
80
81     if (fHead) {
82         fHead->fPrev = strike;
83     } else {
84         SkASSERT(NULL == fTail);
85         fTail = strike;
86     }
87     strike->fPrev = NULL;
88     strike->fNext = fHead;
89     fHead = strike;
90
91     return strike;
92 }
93
94 void GrFontCache::freeAll() {
95     fCache.deleteAll();
96     for (int i = 0; i < kAtlasCount; ++i) {
97         delete fAtlasMgr[i];
98         fAtlasMgr[i] = NULL;
99     }
100     fHead = NULL;
101     fTail = NULL;
102 }
103
104 void GrFontCache::purgeStrike(GrTextStrike* strike) {
105     const GrFontCache::Key key(strike->fFontScalerKey);
106     fCache.remove(key, strike);
107     this->detachStrikeFromList(strike);
108     delete strike;
109 }
110
111 bool GrFontCache::freeUnusedPlot(GrTextStrike* preserveStrike) {
112     SkASSERT(NULL != preserveStrike);
113
114     GrAtlasMgr* atlasMgr = preserveStrike->fAtlasMgr;
115     GrPlot* plot = atlasMgr->getUnusedPlot();
116     if (NULL == plot) {
117         return false;
118     }
119     plot->resetRects();
120
121     GrTextStrike* strike = fHead;
122     GrMaskFormat maskFormat = preserveStrike->fMaskFormat;
123     while (strike) {
124         if (maskFormat != strike->fMaskFormat) {
125             strike = strike->fNext;
126             continue;
127         }
128
129         GrTextStrike* strikeToPurge = strike;
130         strike = strikeToPurge->fNext;
131         strikeToPurge->removePlot(plot);
132
133         // clear out any empty strikes (except this one)
134         if (strikeToPurge != preserveStrike && strikeToPurge->fAtlas.isEmpty()) {
135             this->purgeStrike(strikeToPurge);
136         }
137     }
138
139 #if FONT_CACHE_STATS
140     ++g_PurgeCount;
141 #endif
142
143     return true;
144 }
145
146 #ifdef SK_DEBUG
147 void GrFontCache::validate() const {
148     int count = fCache.count();
149     if (0 == count) {
150         SkASSERT(!fHead);
151         SkASSERT(!fTail);
152     } else if (1 == count) {
153         SkASSERT(fHead == fTail);
154     } else {
155         SkASSERT(fHead != fTail);
156     }
157
158     int count2 = 0;
159     const GrTextStrike* strike = fHead;
160     while (strike) {
161         count2 += 1;
162         strike = strike->fNext;
163     }
164     SkASSERT(count == count2);
165
166     count2 = 0;
167     strike = fTail;
168     while (strike) {
169         count2 += 1;
170         strike = strike->fPrev;
171     }
172     SkASSERT(count == count2);
173 }
174 #endif
175
176 #ifdef SK_DEVELOPER
177 void GrFontCache::dump() const {
178     static int gDumpCount = 0;
179     for (int i = 0; i < kAtlasCount; ++i) {
180         if (NULL != fAtlasMgr[i]) {
181             GrTexture* texture = fAtlasMgr[i]->getTexture();
182             if (NULL != texture) {
183                 SkString filename;
184 #ifdef SK_BUILD_FOR_ANDROID
185                 filename.printf("/sdcard/fontcache_%d%d.png", gDumpCount, i);
186 #else
187                 filename.printf("fontcache_%d%d.png", gDumpCount, i);
188 #endif
189                 texture->savePixels(filename.c_str());
190             }
191         }
192     }
193     ++gDumpCount;
194 }
195 #endif
196
197 ///////////////////////////////////////////////////////////////////////////////
198
199 #ifdef SK_DEBUG
200     static int gCounter;
201 #endif
202
203 // this acts as the max magnitude for the distance field,
204 // as well as the pad we need around the glyph
205 #define DISTANCE_FIELD_RANGE   4
206
207 /*
208     The text strike is specific to a given font/style/matrix setup, which is
209     represented by the GrHostFontScaler object we are given in getGlyph().
210
211     We map a 32bit glyphID to a GrGlyph record, which in turn points to a
212     atlas and a position within that texture.
213  */
214
215 GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
216                            GrMaskFormat format,
217                            GrAtlasMgr* atlasMgr) : fPool(64) {
218     fFontScalerKey = key;
219     fFontScalerKey->ref();
220
221     fFontCache = cache;     // no need to ref, it won't go away before we do
222     fAtlasMgr = atlasMgr;   // no need to ref, it won't go away before we do
223
224     fMaskFormat = format;
225
226 #ifdef SK_DEBUG
227 //    GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
228     gCounter += 1;
229 #endif
230 }
231
232 // this signature is needed because it's used with
233 // SkTDArray::visitAll() (see destructor)
234 static void free_glyph(GrGlyph*& glyph) { glyph->free(); }
235
236 GrTextStrike::~GrTextStrike() {
237     fFontScalerKey->unref();
238     fCache.getArray().visitAll(free_glyph);
239
240 #ifdef SK_DEBUG
241     gCounter -= 1;
242 //    GrPrintf("~GrTextStrike %p %d\n", this, gCounter);
243 #endif
244 }
245
246 GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
247                                      GrFontScaler* scaler) {
248     SkIRect bounds;
249     if (!scaler->getPackedGlyphBounds(packed, &bounds)) {
250         return NULL;
251     }
252
253     GrGlyph* glyph = fPool.alloc();
254     // expand bounds to hold full distance field data
255     // + room for bilerp
256     int pad = DISTANCE_FIELD_RANGE+1;
257     if (fUseDistanceField) {
258         bounds.fLeft   -= pad;
259         bounds.fRight  += pad;
260         bounds.fTop    -= pad;
261         bounds.fBottom += pad;
262     }
263     glyph->init(packed, bounds);
264     fCache.insert(packed, glyph);
265     return glyph;
266 }
267
268 void GrTextStrike::removePlot(const GrPlot* plot) {
269     SkTDArray<GrGlyph*>& glyphArray = fCache.getArray();
270     for (int i = 0; i < glyphArray.count(); ++i) {
271         if (plot == glyphArray[i]->fPlot) {
272             glyphArray[i]->fPlot = NULL;
273         }
274     }
275
276     fAtlasMgr->removePlot(&fAtlas, plot);
277 }
278
279
280 bool GrTextStrike::addGlyphToAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
281 #if 0   // testing hack to force us to flush our cache often
282     static int gCounter;
283     if ((++gCounter % 10) == 0) return false;
284 #endif
285
286     SkASSERT(glyph);
287     SkASSERT(scaler);
288     SkASSERT(fCache.contains(glyph));
289     SkASSERT(NULL == glyph->fPlot);
290
291     SkAutoRef ar(scaler);
292
293     int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
294
295     GrPlot* plot;
296     if (fUseDistanceField) {
297         // we've already expanded the glyph dimensions to match the final size
298         // but must shrink back down to get the packed glyph data
299         int dfWidth = glyph->width();
300         int dfHeight = glyph->height();
301         int pad = DISTANCE_FIELD_RANGE+1;
302         int width = dfWidth - 2*pad;
303         int height = dfHeight - 2*pad;
304         int stride = width*bytesPerPixel;
305
306         size_t size = width * height * bytesPerPixel;
307         SkAutoSMalloc<1024> storage(size);
308         if (!scaler->getPackedGlyphImage(glyph->fPackedID, width, height, stride, storage.get())) {
309             return false;
310         }
311
312         // alloc storage for distance field glyph
313         size_t dfSize = dfWidth * dfHeight * bytesPerPixel;
314         SkAutoSMalloc<1024> dfStorage(dfSize);
315
316         if (1 == bytesPerPixel) {
317             (void) SkGenerateDistanceFieldFromImage((unsigned char*)dfStorage.get(),
318                                                     (unsigned char*)storage.get(),
319                                                     width, height, DISTANCE_FIELD_RANGE);
320         } else {
321             // TODO: Fix color emoji
322             // for now, copy glyph into distance field storage
323             // this is not correct, but it won't crash
324             sk_bzero(dfStorage.get(), dfSize);
325             unsigned char* ptr = (unsigned char*) storage.get();
326             unsigned char* dfPtr = (unsigned char*) dfStorage.get();
327             size_t dfStride = dfWidth*bytesPerPixel;
328             dfPtr += DISTANCE_FIELD_RANGE*dfStride;
329             dfPtr += DISTANCE_FIELD_RANGE*bytesPerPixel;
330
331             for (int i = 0; i < height; ++i) {
332                 memcpy(dfPtr, ptr, stride);
333
334                 dfPtr += dfStride;
335                 ptr += stride;
336             }
337         }
338
339         // copy to atlas
340         plot = fAtlasMgr->addToAtlas(&fAtlas, dfWidth, dfHeight, dfStorage.get(),
341                                      &glyph->fAtlasLocation);
342
343     } else {
344         size_t size = glyph->fBounds.area() * bytesPerPixel;
345         SkAutoSMalloc<1024> storage(size);
346         if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
347                                          glyph->height(),
348                                          glyph->width() * bytesPerPixel,
349                                          storage.get())) {
350             return false;
351         }
352
353         plot = fAtlasMgr->addToAtlas(&fAtlas, glyph->width(),
354                                      glyph->height(), storage.get(),
355                                      &glyph->fAtlasLocation);
356     }
357
358     if (NULL == plot) {
359         return false;
360     }
361
362     glyph->fPlot = plot;
363     return true;
364 }