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