GrTextStrike.cpp revision fd03d4a829efe2d77a712fd991927c55f59a2ffe
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2010 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com */
7ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
8ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#include "GrAtlas.h"
9ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#include "GrGpu.h"
10ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#include "GrRectanizer.h"
11ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#include "GrTextStrike.h"
12ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#include "GrTextStrike_impl.h"
13ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
14fa35e3ddcc9d130ce87c927218bdf27879c38711reed@google.comSK_DEFINE_INST_COUNT(GrFontScaler)
15fa35e3ddcc9d130ce87c927218bdf27879c38711reed@google.comSK_DEFINE_INST_COUNT(GrKey)
16fa35e3ddcc9d130ce87c927218bdf27879c38711reed@google.com
17fa35e3ddcc9d130ce87c927218bdf27879c38711reed@google.com///////////////////////////////////////////////////////////////////////////////
18fa35e3ddcc9d130ce87c927218bdf27879c38711reed@google.com
19ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comGrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
20ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    gpu->ref();
21ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fAtlasMgr = NULL;
22ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
23ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fHead = fTail = NULL;
24ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
25ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
26ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comGrFontCache::~GrFontCache() {
27ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fCache.deleteAll();
28ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    delete fAtlasMgr;
29ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fGpu->unref();
30ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
31ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
32ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comGrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
33ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com                                          const Key& key) {
34ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    if (NULL == fAtlasMgr) {
35c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com        fAtlasMgr = SkNEW_ARGS(GrAtlasMgr, (fGpu));
36ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
37c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com    GrTextStrike* strike = SkNEW_ARGS(GrTextStrike,
38c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com                                      (this, scaler->getKey(),
39c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com                                       scaler->getMaskFormat(), fAtlasMgr));
40ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fCache.insert(key, strike);
41ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
42ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    if (fHead) {
43ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        fHead->fPrev = strike;
44ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    } else {
45ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        GrAssert(NULL == fTail);
46ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        fTail = strike;
47ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
48ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    strike->fPrev = NULL;
49ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    strike->fNext = fHead;
50ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fHead = strike;
51ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
52ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    return strike;
53ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
54ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
55ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comvoid GrFontCache::freeAll() {
56ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fCache.deleteAll();
57ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    delete fAtlasMgr;
58ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fAtlasMgr = NULL;
598fe72477f204b1a45393e6a64caa84fd287b805bbsalomon@google.com    fHead = NULL;
608fe72477f204b1a45393e6a64caa84fd287b805bbsalomon@google.com    fTail = NULL;
61ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
62ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
63ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comvoid GrFontCache::purgeExceptFor(GrTextStrike* preserveStrike) {
64ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    GrTextStrike* strike = fTail;
657359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com    while (strike) {
667359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com        if (strike == preserveStrike) {
677359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com            strike = strike->fPrev;
687359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com            continue;
697359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com        }
707359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com        GrTextStrike* strikeToPurge = strike;
717359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com        // keep going if we won't free up any atlases with this strike.
727359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com        strike = (NULL == strikeToPurge->fAtlas) ? strikeToPurge->fPrev : NULL;
737359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com        int index = fCache.slowFindIndex(strikeToPurge);
74ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        GrAssert(index >= 0);
757359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com        fCache.removeAt(index, strikeToPurge->fFontScalerKey->getHash());
767359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com        this->detachStrikeFromList(strikeToPurge);
777359eae7c6fce8cb88ae28ca7048283b77535db4bsalomon@google.com        delete strikeToPurge;
78ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
79ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
80ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
81ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#if GR_DEBUG
82ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comvoid GrFontCache::validate() const {
83ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    int count = fCache.count();
84ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    if (0 == count) {
85ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        GrAssert(!fHead);
86ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        GrAssert(!fTail);
87ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    } else if (1 == count) {
88ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        GrAssert(fHead == fTail);
89ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    } else {
90ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        GrAssert(fHead != fTail);
91ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
92ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
93ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    int count2 = 0;
94ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    const GrTextStrike* strike = fHead;
95ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    while (strike) {
96ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        count2 += 1;
97ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        strike = strike->fNext;
98ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
99ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    GrAssert(count == count2);
100ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
101ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    count2 = 0;
102ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    strike = fTail;
103ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    while (strike) {
104ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        count2 += 1;
105ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        strike = strike->fPrev;
106ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
107ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    GrAssert(count == count2);
108ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
109ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
110ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
111ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com///////////////////////////////////////////////////////////////////////////////
112ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
113ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#if GR_DEBUG
114ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    static int gCounter;
115ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
116ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
117ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com/*
118ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    The text strike is specific to a given font/style/matrix setup, which is
119ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    represented by the GrHostFontScaler object we are given in getGlyph().
120ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
121ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    We map a 32bit glyphID to a GrGlyph record, which in turn points to a
122ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    atlas and a position within that texture.
123ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com */
124ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
125ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comGrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
12698539c607b05f7e25406ae873bf1b24154a36a6freed@google.com                           GrMaskFormat format,
127ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com                           GrAtlasMgr* atlasMgr) : fPool(64) {
128ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fFontScalerKey = key;
129ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fFontScalerKey->ref();
130ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
131ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fFontCache = cache;     // no need to ref, it won't go away before we do
132ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fAtlasMgr = atlasMgr;   // no need to ref, it won't go away before we do
133ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fAtlas = NULL;
134ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
13598539c607b05f7e25406ae873bf1b24154a36a6freed@google.com    fMaskFormat = format;
13698539c607b05f7e25406ae873bf1b24154a36a6freed@google.com
137ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#if GR_DEBUG
1383ef80cf14c3222f705c291123106991e52061678reed@google.com//    GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
139ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    gCounter += 1;
140ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
141ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
142ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
143ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comstatic void FreeGlyph(GrGlyph*& glyph) { glyph->free(); }
144ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
145ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comGrTextStrike::~GrTextStrike() {
146ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    GrAtlas::FreeLList(fAtlas);
147ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fFontScalerKey->unref();
14821cbec4870660f776f470e3a5e327599b6433dd2bsalomon@google.com    fCache.getArray().visitAll(FreeGlyph);
149ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
150ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#if GR_DEBUG
151ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    gCounter -= 1;
1523ef80cf14c3222f705c291123106991e52061678reed@google.com//    GrPrintf("~GrTextStrike %p %d\n", this, gCounter);
153ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
154ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
155ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
156ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comGrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
157ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com                                     GrFontScaler* scaler) {
158fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    SkIRect bounds;
159ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    if (!scaler->getPackedGlyphBounds(packed, &bounds)) {
160ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return NULL;
161ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
162ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
163ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    GrGlyph* glyph = fPool.alloc();
164ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    glyph->init(packed, bounds);
165ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fCache.insert(packed, glyph);
166ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    return glyph;
167ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
168ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
169ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.combool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
1700ebe81a2b7a2dfd3b978520c2594e448bdbadca0reed@google.com#if 0   // testing hack to force us to flush our cache often
1710ebe81a2b7a2dfd3b978520c2594e448bdbadca0reed@google.com    static int gCounter;
1720ebe81a2b7a2dfd3b978520c2594e448bdbadca0reed@google.com    if ((++gCounter % 10) == 0) return false;
1730ebe81a2b7a2dfd3b978520c2594e448bdbadca0reed@google.com#endif
1740ebe81a2b7a2dfd3b978520c2594e448bdbadca0reed@google.com
175ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    GrAssert(glyph);
176ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    GrAssert(scaler);
177ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    GrAssert(fCache.contains(glyph));
178ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    if (glyph->fAtlas) {
179ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return true;
180ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
181ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
182ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    GrAutoRef ar(scaler);
18398539c607b05f7e25406ae873bf1b24154a36a6freed@google.com
18498539c607b05f7e25406ae873bf1b24154a36a6freed@google.com    int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
18598539c607b05f7e25406ae873bf1b24154a36a6freed@google.com    size_t size = glyph->fBounds.area() * bytesPerPixel;
1863582bf9e3d94feac5d4cc64fdb646dd68a3e4b18bsalomon@google.com    SkAutoSMalloc<1024> storage(size);
187ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
18898539c607b05f7e25406ae873bf1b24154a36a6freed@google.com                                     glyph->height(),
18998539c607b05f7e25406ae873bf1b24154a36a6freed@google.com                                     glyph->width() * bytesPerPixel,
190ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com                                     storage.get())) {
191ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return false;
192ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
193ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
194ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(),
195ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com                                           glyph->height(), storage.get(),
19698539c607b05f7e25406ae873bf1b24154a36a6freed@google.com                                           fMaskFormat,
197ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com                                           &glyph->fAtlasLocation);
198ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    if (NULL == atlas) {
199ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        return false;
200ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
201ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
202ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    // update fAtlas as well, since they may be chained in a linklist
203ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    glyph->fAtlas = fAtlas = atlas;
204ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    return true;
205ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
206