1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/*
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2006 The Android Open Source Project
4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com *
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */
8685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkGlyphCache.h"
119defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com#include "SkGlyphCache_Globals.h"
12caaf85441ce8a2231c9543088ee7a523328a2419reed@google.com#include "SkGraphics.h"
13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkPaint.h"
149ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com#include "SkPath.h"
15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkTemplates.h"
16baaaeb0f86173a4ffb29cf75f90b9473ea7d2125reed@google.com#include "SkTLS.h"
1778341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com#include "SkTypeface.h"
18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
196a2b39f2e7680b1300aa16c71e2a9cb31c5277cfreed@google.com//#define SPEW_PURGE_STATUS
20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com//#define RECORD_HASH_EFFICIENCY
21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
22a12ddbbf5a9791687b41c608448353ebc6cfa9cfreed@google.combool gSkSuppressFontCachePurgeSpew;
23a12ddbbf5a9791687b41c608448353ebc6cfa9cfreed@google.com
249defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com// Returns the shared globals
259defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comstatic SkGlyphCache_Globals& getSharedGlobals() {
269defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    // we leak this, so we don't incur any shutdown cost of the destructor
279defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    static SkGlyphCache_Globals* gGlobals = SkNEW_ARGS(SkGlyphCache_Globals,
289defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com                                                       (SkGlyphCache_Globals::kYes_UseMutex));
299defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    return *gGlobals;
309defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com}
319defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
329defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com// Returns the TLS globals (if set), or the shared globals
339defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comstatic SkGlyphCache_Globals& getGlobals() {
349defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS();
359defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    return tls ? *tls : getSharedGlobals();
369defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com}
379defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
38bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
39bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef RECORD_HASH_EFFICIENCY
41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static uint32_t gHashSuccess;
42bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static uint32_t gHashCollision;
43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static void RecordHashSuccess() {
45bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        gHashSuccess += 1;
46bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
47bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static void RecordHashCollisionIf(bool pred) {
49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (pred) {
50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            gHashCollision += 1;
51ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
52bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            uint32_t total = gHashSuccess + gHashCollision;
53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkDebugf("Font Cache Hash success rate: %d%%\n",
54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                     100 * gHashSuccess / total);
55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#else
58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    #define RecordHashSuccess() (void)0
59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    #define RecordHashCollisionIf(pred) (void)0
60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define RecordHashCollision() RecordHashCollisionIf(true)
62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
64bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
65c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com// so we don't grow our arrays a lot
66c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com#define kMinGlyphCount      16
67c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com#define kMinGlyphImageSize  (16*2)
68c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com#define kMinAllocAmount     ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphCount)
69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
7042eacd7f693510758d71fdb07805a240d6176372reed@google.comSkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkScalerContext* ctx)
7142eacd7f693510758d71fdb07805a240d6176372reed@google.com        : fScalerContext(ctx), fGlyphAlloc(kMinAllocAmount) {
7278341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com    SkASSERT(typeface);
7342eacd7f693510758d71fdb07805a240d6176372reed@google.com    SkASSERT(desc);
7442eacd7f693510758d71fdb07805a240d6176372reed@google.com    SkASSERT(ctx);
7578341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com
76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fPrev = fNext = NULL;
77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fDesc = desc->copy();
792f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com    fScalerContext->getFontMetrics(&fFontMetrics);
80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // init to 0 so that all of the pointers will be null
82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    memset(fGlyphHash, 0, sizeof(fGlyphHash));
83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // init with 0xFF so that the charCode field will be -1, which is invalid
84bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    memset(fCharToGlyphHash, 0xFF, sizeof(fCharToGlyphHash));
85ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
86c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com    fMemoryUsed = sizeof(*this);
87ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
88c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com    fGlyphArray.setReserve(kMinGlyphCount);
89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
90bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fAuxProcList = NULL;
91bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
92bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkGlyphCache::~SkGlyphCache() {
94c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com#if 0
95c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com    {
96c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        size_t ptrMem = fGlyphArray.count() * sizeof(SkGlyph*);
97c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        size_t glyphAlloc = fGlyphAlloc.totalCapacity();
98c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        size_t glyphHashUsed = 0;
99c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        size_t uniHashUsed = 0;
100c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        for (int i = 0; i < kHashCount; ++i) {
101c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com            glyphHashUsed += fGlyphHash[i] ? sizeof(fGlyphHash[0]) : 0;
102c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com            uniHashUsed += fCharToGlyphHash[i].fID != 0xFFFFFFFF ? sizeof(fCharToGlyphHash[0]) : 0;
103c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        }
104c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        size_t glyphUsed = fGlyphArray.count() * sizeof(SkGlyph);
105c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        size_t imageUsed = 0;
106c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        for (int i = 0; i < fGlyphArray.count(); ++i) {
107c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com            const SkGlyph& g = *fGlyphArray[i];
108c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com            if (g.fImage) {
109c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com                imageUsed += g.fHeight * g.rowBytes();
110c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com            }
111c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        }
112c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com
113c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com        printf("glyphPtrArray,%zu, Alloc,%zu, imageUsed,%zu, glyphUsed,%zu, glyphHashAlloc,%zu, glyphHashUsed,%zu, unicharHashAlloc,%zu, unicharHashUsed,%zu\n",
114c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com                 ptrMem, glyphAlloc, imageUsed, glyphUsed, sizeof(fGlyphHash), glyphHashUsed, sizeof(fCharToGlyphHash), uniHashUsed);
1151bda0434d06e2cff123683fcf0b01bf30f33ab7dskia.committer@gmail.com
116c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com    }
117c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com#endif
118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyph**   gptr = fGlyphArray.begin();
119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyph**   stop = fGlyphArray.end();
120bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    while (gptr < stop) {
121bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkPath* path = (*gptr)->fPath;
122bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (path) {
123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkDELETE(path);
124bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
125bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        gptr += 1;
126bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
127bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkDescriptor::Free(fDesc);
128bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkDELETE(fScalerContext);
129bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    this->invokeAndRemoveAuxProcs();
130bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
131bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
132bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
133bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
134bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUG
135e216b62841acd5db9d91b63960805568259a2e0ereed@android.com#define VALIDATE()  AutoValidate av(this)
136bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#else
137bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define VALIDATE()
138bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
139bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
140bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comuint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) {
141bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    VALIDATE();
142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t id = SkGlyph::MakeID(charCode);
143bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const CharGlyphRec& rec = fCharToGlyphHash[ID2HashIndex(id)];
144ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
145bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (rec.fID == id) {
146bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return rec.fGlyph->getGlyphID();
147bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
148bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return fScalerContext->charToGlyphID(charCode);
149bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
150bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
151bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
152739245e986d7a78b96129f559363b7ab6fb0a21creed@android.comSkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) {
153739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com    return fScalerContext->glyphIDToChar(glyphID);
154739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com}
155739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com
156019978975b2cb2b2cfe270c72b53db0326002401ctguil@chromium.orgunsigned SkGlyphCache::getGlyphCount() {
157019978975b2cb2b2cfe270c72b53db0326002401ctguil@chromium.org    return fScalerContext->getGlyphCount();
158019978975b2cb2b2cfe270c72b53db0326002401ctguil@chromium.org}
159019978975b2cb2b2cfe270c72b53db0326002401ctguil@chromium.org
160bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
161bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
162bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comconst SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) {
163bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    VALIDATE();
164bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t id = SkGlyph::MakeID(charCode);
165bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
166ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
167bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (rec->fID != id) {
168bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // this ID is based on the UniChar
169bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fID = id;
170bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // this ID is based on the glyph index
171bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode));
172bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fGlyph = this->lookupMetrics(id, kJustAdvance_MetricsType);
173bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
174bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return *rec->fGlyph;
175bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
176bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
177bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comconst SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) {
178bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    VALIDATE();
179bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t id = SkGlyph::MakeID(glyphID);
180bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned index = ID2HashIndex(id);
181bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyph* glyph = fGlyphHash[index];
182bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
183bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (NULL == glyph || glyph->fID != id) {
184bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph = this->lookupMetrics(glyphID, kJustAdvance_MetricsType);
185bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fGlyphHash[index] = glyph;
186bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
187bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return *glyph;
188bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
189bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
190bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
191bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
192bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comconst SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) {
193bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    VALIDATE();
194bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t id = SkGlyph::MakeID(charCode);
195bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
196ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
197bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (rec->fID != id) {
198bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        RecordHashCollisionIf(rec->fGlyph != NULL);
199bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // this ID is based on the UniChar
200bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fID = id;
201bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // this ID is based on the glyph index
202bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode));
203bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType);
204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
205bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        RecordHashSuccess();
206bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (rec->fGlyph->isJustAdvance()) {
207bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fScalerContext->getMetrics(rec->fGlyph);
208bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
209bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
210bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(rec->fGlyph->isFullMetrics());
211bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return *rec->fGlyph;
212bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
213bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
214bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comconst SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode,
215bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                               SkFixed x, SkFixed y) {
216bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    VALIDATE();
217bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t id = SkGlyph::MakeID(charCode, x, y);
218bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)];
219ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
220bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (rec->fID != id) {
221bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        RecordHashCollisionIf(rec->fGlyph != NULL);
222bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // this ID is based on the UniChar
223bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fID = id;
224bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // this ID is based on the glyph index
225bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode), x, y);
226bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType);
227bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
228bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        RecordHashSuccess();
229bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (rec->fGlyph->isJustAdvance()) {
230bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fScalerContext->getMetrics(rec->fGlyph);
231bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
232bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
233bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(rec->fGlyph->isFullMetrics());
234bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return *rec->fGlyph;
235bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
236bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
237bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comconst SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) {
238bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    VALIDATE();
239bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t id = SkGlyph::MakeID(glyphID);
240bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned index = ID2HashIndex(id);
241bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyph* glyph = fGlyphHash[index];
242ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
243bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (NULL == glyph || glyph->fID != id) {
244bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        RecordHashCollisionIf(glyph != NULL);
245bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph = this->lookupMetrics(glyphID, kFull_MetricsType);
246bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fGlyphHash[index] = glyph;
247bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
248bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        RecordHashSuccess();
249bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (glyph->isJustAdvance()) {
250bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fScalerContext->getMetrics(glyph);
251bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
252bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
253bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(glyph->isFullMetrics());
254bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return *glyph;
255bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
256bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
257bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comconst SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID,
258bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                               SkFixed x, SkFixed y) {
259bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    VALIDATE();
260bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t id = SkGlyph::MakeID(glyphID, x, y);
261bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned index = ID2HashIndex(id);
262bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyph* glyph = fGlyphHash[index];
263bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
264bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (NULL == glyph || glyph->fID != id) {
265bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        RecordHashCollisionIf(glyph != NULL);
266bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph = this->lookupMetrics(id, kFull_MetricsType);
267bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fGlyphHash[index] = glyph;
268bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
269bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        RecordHashSuccess();
270bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (glyph->isJustAdvance()) {
271bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fScalerContext->getMetrics(glyph);
272bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
273bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
274bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(glyph->isFullMetrics());
275bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return *glyph;
276bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
277bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
278bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) {
279bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyph* glyph;
280bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
281bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int     hi = 0;
282bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int     count = fGlyphArray.count();
283bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
284bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (count) {
285bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkGlyph**   gptr = fGlyphArray.begin();
286bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int     lo = 0;
287bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
288bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        hi = count - 1;
289bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        while (lo < hi) {
290bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            int mid = (hi + lo) >> 1;
291bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (gptr[mid]->fID < id) {
292bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                lo = mid + 1;
293bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            } else {
294bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                hi = mid;
295bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
296bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
297bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph = gptr[hi];
298bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (glyph->fID == id) {
299bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (kFull_MetricsType == mtype && glyph->isJustAdvance()) {
300bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                fScalerContext->getMetrics(glyph);
301bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
302bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            return glyph;
303bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
304bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
305bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // check if we need to bump hi before falling though to the allocator
306bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (glyph->fID < id) {
307bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            hi += 1;
308bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
309bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
310bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
311bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // not found, but hi tells us where to inser the new glyph
312bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fMemoryUsed += sizeof(SkGlyph);
313bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
314bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    glyph = (SkGlyph*)fGlyphAlloc.alloc(sizeof(SkGlyph),
315bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                        SkChunkAlloc::kThrow_AllocFailType);
316e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    glyph->init(id);
317bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    *fGlyphArray.insert(hi) = glyph;
318ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
319bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (kJustAdvance_MetricsType == mtype) {
320bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fScalerContext->getAdvance(glyph);
321bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
322bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(kFull_MetricsType == mtype);
323bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fScalerContext->getMetrics(glyph);
324bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
325bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
326bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return glyph;
327bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
328bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
329bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comconst void* SkGlyphCache::findImage(const SkGlyph& glyph) {
330029b014370d8a89edd3ee71f653b6ebb2bd47a9escarybeasts@gmail.com    if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) {
331bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (glyph.fImage == NULL) {
332bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            size_t  size = glyph.computeImageSize();
333c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com            const_cast<SkGlyph&>(glyph).fImage = fGlyphAlloc.alloc(size,
334bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                        SkChunkAlloc::kReturnNil_AllocFailType);
335ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com            // check that alloc() actually succeeded
336ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com            if (glyph.fImage) {
337ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com                fScalerContext->getImage(glyph);
338ea9bd4b8a675f3f92e815f79c2f5c456661235bareed@google.com                // TODO: the scaler may have changed the maskformat during
339ea9bd4b8a675f3f92e815f79c2f5c456661235bareed@google.com                // getImage (e.g. from AA or LCD to BW) which means we may have
340ea9bd4b8a675f3f92e815f79c2f5c456661235bareed@google.com                // overallocated the buffer. Check if the new computedImageSize
341ea9bd4b8a675f3f92e815f79c2f5c456661235bareed@google.com                // is smaller, and if so, strink the alloc size in fImageAlloc.
342ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com                fMemoryUsed += size;
343ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com            }
344bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
345bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
346bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return glyph.fImage;
347bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
348bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
349bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comconst SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) {
350bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (glyph.fWidth) {
351bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (glyph.fPath == NULL) {
352bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            const_cast<SkGlyph&>(glyph).fPath = SkNEW(SkPath);
353bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fScalerContext->getPath(glyph, glyph.fPath);
354bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fMemoryUsed += sizeof(SkPath) +
35546597516083edf81db0ed946d5ef7ba04057c008bsalomon@google.com                    glyph.fPath->countPoints() * sizeof(SkPoint);
356bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
357bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
358bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return glyph.fPath;
359bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
360bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
361bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
362bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
363bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const {
364bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const AuxProcRec* rec = fAuxProcList;
365bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    while (rec) {
366bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (rec->fProc == proc) {
367bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (dataPtr) {
368bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                *dataPtr = rec->fData;
369bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
370bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            return true;
371bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
372bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec = rec->fNext;
373bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
374bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return false;
375bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
376bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
377bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) {
378bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (proc == NULL) {
379bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
380bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
381bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
382bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    AuxProcRec* rec = fAuxProcList;
383bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    while (rec) {
384bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (rec->fProc == proc) {
385bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            rec->fData = data;
386bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            return;
387bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
388bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec = rec->fNext;
389bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
390bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // not found, create a new rec
391bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rec = SkNEW(AuxProcRec);
392bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rec->fProc = proc;
393bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rec->fData = data;
394bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rec->fNext = fAuxProcList;
395bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fAuxProcList = rec;
396bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
397bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
398bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkGlyphCache::invokeAndRemoveAuxProcs() {
399bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    AuxProcRec* rec = fAuxProcList;
400bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    while (rec) {
401bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fProc(rec->fData);
402bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        AuxProcRec* next = rec->fNext;
403bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkDELETE(rec);
404bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec = next;
405bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
406bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
407bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
408bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
409bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
410bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
411b64e323a250ba2e19645ee17965bcd89d09d597freed@google.com#include "SkThread.h"
412b64e323a250ba2e19645ee17965bcd89d09d597freed@google.com
4139defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comsize_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) {
414490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com    static const size_t minLimit = 256 * 1024;
415490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com    if (newLimit < minLimit) {
416490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com        newLimit = minLimit;
417490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com    }
4188db5ae540517d2c31d40e2de5722d8dbb7ff3c68skia.committer@gmail.com
4199defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    SkAutoMutexAcquire    ac(fMutex);
4208db5ae540517d2c31d40e2de5722d8dbb7ff3c68skia.committer@gmail.com
4219defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    size_t prevLimit = fCacheSizeLimit;
4229defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    fCacheSizeLimit = newLimit;
4239defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    this->internalPurge();
424490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com    return prevLimit;
425490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com}
426490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com
4279defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comint SkGlyphCache_Globals::setCacheCountLimit(int newCount) {
4289defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    if (newCount < 0) {
4299defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        newCount = 0;
4309defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    }
4318db5ae540517d2c31d40e2de5722d8dbb7ff3c68skia.committer@gmail.com
43212b8acf22365abbd361f5f5796184340a5472b08reed@google.com    SkAutoMutexAcquire    ac(fMutex);
4338db5ae540517d2c31d40e2de5722d8dbb7ff3c68skia.committer@gmail.com
4349defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    int prevCount = fCacheCountLimit;
4359defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    fCacheCountLimit = newCount;
4369defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    this->internalPurge();
4379defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    return prevCount;
43812b8acf22365abbd361f5f5796184340a5472b08reed@google.com}
43912b8acf22365abbd361f5f5796184340a5472b08reed@google.com
4409defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comvoid SkGlyphCache_Globals::purgeAll() {
4419defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    SkAutoMutexAcquire    ac(fMutex);
4429defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    this->internalPurge(fTotalMemoryUsed);
443490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com}
444490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com
445bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*),
446bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                  void* context) {
447b64e323a250ba2e19645ee17965bcd89d09d597freed@google.com    SkGlyphCache_Globals& globals = getGlobals();
448bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkAutoMutexAcquire    ac(globals.fMutex);
449bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyphCache*         cache;
450ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
451bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    globals.validate();
452ae30cc1b4d11395a4e845ad003d8263f8395213breed@google.com
4539defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) {
454bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (proc(cache, context)) {
455bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
456bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
457bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
458bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
459bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    globals.validate();
460bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
461bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
462bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/*  This guy calls the visitor from within the mutext lock, so the visitor
463bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    cannot:
464bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    - take too much time
465bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    - try to acquire the mutext again
466bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    - call a fontscaler (which might call into the cache)
467bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com*/
46878341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.comSkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface,
46978341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com                              const SkDescriptor* desc,
470bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                              bool (*proc)(const SkGlyphCache*, void*),
471bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                              void* context) {
47278341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com    if (!typeface) {
47378341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com        typeface = SkTypeface::GetDefaultTypeface();
47478341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com    }
475bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(desc);
476bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
477b64e323a250ba2e19645ee17965bcd89d09d597freed@google.com    SkGlyphCache_Globals& globals = getGlobals();
478bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkAutoMutexAcquire    ac(globals.fMutex);
479bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyphCache*         cache;
480bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    bool                  insideMutex = true;
481bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
482bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    globals.validate();
483bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
4849defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) {
485bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (cache->fDesc->equals(*desc)) {
4869defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com            globals.internalDetachCache(cache);
487bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            goto FOUND_IT;
488bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
489bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
490bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
491bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /* Release the mutex now, before we create a new entry (which might have
492bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        side-effects like trying to access the cache/mutex (yikes!)
493bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
494bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    ac.release();           // release the mutex now
495bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    insideMutex = false;    // can't use globals anymore
496bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
49742eacd7f693510758d71fdb07805a240d6176372reed@google.com    // Check if we can create a scaler-context before creating the glyphcache.
49842eacd7f693510758d71fdb07805a240d6176372reed@google.com    // If not, we may have exhausted OS/font resources, so try purging the
49942eacd7f693510758d71fdb07805a240d6176372reed@google.com    // cache once and try again.
50042eacd7f693510758d71fdb07805a240d6176372reed@google.com    {
501bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com        // pass true the first time, to notice if the scalercontext failed,
502bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com        // so we can try the purge.
503bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com        SkScalerContext* ctx = typeface->createScalerContext(desc, true);
50442eacd7f693510758d71fdb07805a240d6176372reed@google.com        if (!ctx) {
50542eacd7f693510758d71fdb07805a240d6176372reed@google.com            getSharedGlobals().purgeAll();
506bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com            ctx = typeface->createScalerContext(desc, false);
507bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com            SkASSERT(ctx);
50842eacd7f693510758d71fdb07805a240d6176372reed@google.com        }
50942eacd7f693510758d71fdb07805a240d6176372reed@google.com        cache = SkNEW_ARGS(SkGlyphCache, (typeface, desc, ctx));
51042eacd7f693510758d71fdb07805a240d6176372reed@google.com    }
511bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
512bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comFOUND_IT:
513e216b62841acd5db9d91b63960805568259a2e0ereed@android.com
514e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    AutoValidate av(cache);
515e216b62841acd5db9d91b63960805568259a2e0ereed@android.com
5169defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    if (!proc(cache, context)) {   // need to reattach
517bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (insideMutex) {
5189defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com            globals.internalAttachCacheToHead(cache);
519bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else {
5209defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com            globals.attachCacheToHead(cache);
521bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
522bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        cache = NULL;
523bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
524bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return cache;
525bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
526bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
527bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkGlyphCache::AttachCache(SkGlyphCache* cache) {
528bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(cache);
529bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(cache->fNext == NULL);
530bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5319defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    getGlobals().attachCacheToHead(cache);
5329defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com}
533bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5349defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com///////////////////////////////////////////////////////////////////////////////
535bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5369defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comvoid SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) {
5379defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    SkAutoMutexAcquire    ac(fMutex);
538bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5399defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    this->validate();
5409defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    cache->validate();
541bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5429defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    this->internalAttachCacheToHead(cache);
5439defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    this->internalPurge();
544bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
545bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5469defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comSkGlyphCache* SkGlyphCache_Globals::internalGetTail() const {
5479defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    SkGlyphCache* cache = fHead;
548bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (cache) {
549bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        while (cache->fNext) {
550bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            cache = cache->fNext;
551bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
552bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
553bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return cache;
554bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
555bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5569defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comsize_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) {
5579defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    this->validate();
558935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
5599defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    size_t bytesNeeded = 0;
5609defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    if (fTotalMemoryUsed > fCacheSizeLimit) {
5619defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit;
5629defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    }
5639defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    bytesNeeded = SkMax32(bytesNeeded, minBytesNeeded);
5649defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    if (bytesNeeded) {
5659defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        // no small purges!
5669defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        bytesNeeded = SkMax32(bytesNeeded, fTotalMemoryUsed >> 2);
567bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
568bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5699defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    int countNeeded = 0;
5709defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    if (fCacheCount > fCacheCountLimit) {
5719defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        countNeeded = fCacheCount - fCacheCountLimit;
5729defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        // no small purges!
5739defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        countNeeded = SkMax32(countNeeded, fCacheCount >> 2);
574bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
575bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5769defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    // early exit
5779defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    if (!countNeeded && !bytesNeeded) {
5789defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        return 0;
5799defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    }
580bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
581bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    size_t  bytesFreed = 0;
5829defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    int     countFreed = 0;
583bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5849defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    // we start at the tail and proceed backwards, as the linklist is in LRU
5859defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    // order, with unimportant entries at the tail.
5869defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    SkGlyphCache* cache = this->internalGetTail();
5879defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    while (cache != NULL &&
5889defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com           (bytesFreed < bytesNeeded || countFreed < countNeeded)) {
589bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkGlyphCache* prev = cache->fPrev;
590bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        bytesFreed += cache->fMemoryUsed;
5919defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        countFreed += 1;
592bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5939defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        this->internalDetachCache(cache);
594bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkDELETE(cache);
595bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        cache = prev;
596bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
597bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5989defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    this->validate();
599bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
600bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SPEW_PURGE_STATUS
6019defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    if (countFreed && !gSkSuppressFontCachePurgeSpew) {
602bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkDebugf("purging %dK from font cache [%d entries]\n",
6039defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com                 (int)(bytesFreed >> 10), countFreed);
604bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
605bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
606bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
607bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return bytesFreed;
608bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
609bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
6109defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comvoid SkGlyphCache_Globals::internalAttachCacheToHead(SkGlyphCache* cache) {
6119defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    SkASSERT(NULL == cache->fPrev && NULL == cache->fNext);
6129defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    if (fHead) {
6139defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        fHead->fPrev = cache;
6149defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        cache->fNext = fHead;
6159defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    }
6169defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    fHead = cache;
6178db5ae540517d2c31d40e2de5722d8dbb7ff3c68skia.committer@gmail.com
6189defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    fCacheCount += 1;
6199defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    fTotalMemoryUsed += cache->fMemoryUsed;
6209defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com}
6219defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
6229defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comvoid SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) {
6239defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    SkASSERT(fCacheCount > 0);
6249defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    fCacheCount -= 1;
6259defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    fTotalMemoryUsed -= cache->fMemoryUsed;
6269defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
6279defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    if (cache->fPrev) {
6289defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        cache->fPrev->fNext = cache->fNext;
6299defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    } else {
6309defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        fHead = cache->fNext;
6319defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    }
6329defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    if (cache->fNext) {
6339defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        cache->fNext->fPrev = cache->fPrev;
6349defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    }
6359defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    cache->fPrev = cache->fNext = NULL;
6369defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com}
6379defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
638e216b62841acd5db9d91b63960805568259a2e0ereed@android.com///////////////////////////////////////////////////////////////////////////////
639e216b62841acd5db9d91b63960805568259a2e0ereed@android.com
640490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com#ifdef SK_DEBUG
6419defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
642e216b62841acd5db9d91b63960805568259a2e0ereed@android.comvoid SkGlyphCache::validate() const {
6434a0d8c8c1a6281cf2440b54606e894cc32354abfdjsollen@google.com#ifdef SK_DEBUG_GLYPH_CACHE
644e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    int count = fGlyphArray.count();
645e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    for (int i = 0; i < count; i++) {
646e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        const SkGlyph* glyph = fGlyphArray[i];
647e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        SkASSERT(glyph);
648e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        SkASSERT(fGlyphAlloc.contains(glyph));
649e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        if (glyph->fImage) {
650c67a3e573cd4660bc57622fd4550effcacc046c8reed@google.com            SkASSERT(fGlyphAlloc.contains(glyph->fImage));
651e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        }
652e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    }
6534a0d8c8c1a6281cf2440b54606e894cc32354abfdjsollen@google.com#endif
654e216b62841acd5db9d91b63960805568259a2e0ereed@android.com}
6559defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
6569defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comvoid SkGlyphCache_Globals::validate() const {
6579defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    size_t computedBytes = 0;
6589defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    int computedCount = 0;
6598db5ae540517d2c31d40e2de5722d8dbb7ff3c68skia.committer@gmail.com
6609defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    const SkGlyphCache* head = fHead;
6619defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    while (head != NULL) {
6629defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        computedBytes += head->fMemoryUsed;
6639defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        computedCount += 1;
6649defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        head = head->fNext;
6659defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    }
6668db5ae540517d2c31d40e2de5722d8dbb7ff3c68skia.committer@gmail.com
6679defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    SkASSERT(fTotalMemoryUsed == computedBytes);
6689defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    SkASSERT(fCacheCount == computedCount);
6699defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com}
6709defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
671e216b62841acd5db9d91b63960805568259a2e0ereed@android.com#endif
672490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com
673490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com///////////////////////////////////////////////////////////////////////////////
674490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com///////////////////////////////////////////////////////////////////////////////
675490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com
676490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com#include "SkTypefaceCache.h"
677490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com
678490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.comsize_t SkGraphics::GetFontCacheLimit() {
6799defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    return getSharedGlobals().getCacheSizeLimit();
680490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com}
681490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com
682490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.comsize_t SkGraphics::SetFontCacheLimit(size_t bytes) {
6839defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    return getSharedGlobals().setCacheSizeLimit(bytes);
684490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com}
685490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com
6863094b00052a6652f3c11894b21aed2acb5381987reed@google.comsize_t SkGraphics::GetFontCacheUsed() {
6879defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    return getSharedGlobals().getTotalMemoryUsed();
6889defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com}
6899defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
6909defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comint SkGraphics::GetFontCacheCountLimit() {
6919defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    return getSharedGlobals().getCacheCountLimit();
6929defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com}
6939defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
6949defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comint SkGraphics::SetFontCacheCountLimit(int count) {
6959defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    return getSharedGlobals().setCacheCountLimit(count);
6969defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com}
6979defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com
6989defd9148e467f08ccd45cb7800a82f2660ef42freed@google.comint SkGraphics::GetFontCacheCountUsed() {
6999defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    return getSharedGlobals().getCacheCountUsed();
7003094b00052a6652f3c11894b21aed2acb5381987reed@google.com}
7013094b00052a6652f3c11894b21aed2acb5381987reed@google.com
702490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.comvoid SkGraphics::PurgeFontCache() {
70312b8acf22365abbd361f5f5796184340a5472b08reed@google.com    getSharedGlobals().purgeAll();
704490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com    SkTypefaceCache::PurgeAll();
705490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com}
706490800bd6cfbaae642a67e373e343f29f7b6f917reed@google.com
707baaaeb0f86173a4ffb29cf75f90b9473ea7d2125reed@google.comsize_t SkGraphics::GetTLSFontCacheLimit() {
708baaaeb0f86173a4ffb29cf75f90b9473ea7d2125reed@google.com    const SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS();
7099defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com    return tls ? tls->getCacheSizeLimit() : 0;
710baaaeb0f86173a4ffb29cf75f90b9473ea7d2125reed@google.com}
711baaaeb0f86173a4ffb29cf75f90b9473ea7d2125reed@google.com
71271f48188df42fc0da08be7f2ff036d0a6ba1b8f0reed@google.comvoid SkGraphics::SetTLSFontCacheLimit(size_t bytes) {
713baaaeb0f86173a4ffb29cf75f90b9473ea7d2125reed@google.com    if (0 == bytes) {
714baaaeb0f86173a4ffb29cf75f90b9473ea7d2125reed@google.com        SkGlyphCache_Globals::DeleteTLS();
715baaaeb0f86173a4ffb29cf75f90b9473ea7d2125reed@google.com    } else {
7169defd9148e467f08ccd45cb7800a82f2660ef42freed@google.com        SkGlyphCache_Globals::GetTLS().setCacheSizeLimit(bytes);
717baaaeb0f86173a4ffb29cf75f90b9473ea7d2125reed@google.com    }
718baaaeb0f86173a4ffb29cf75f90b9473ea7d2125reed@google.com}
719