1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 
11 #include "SkTypefaceCache.h"
12 #include "SkThread.h"
13 
14 #define TYPEFACE_CACHE_LIMIT    1024
15 
SkTypefaceCache()16 SkTypefaceCache::SkTypefaceCache() {}
17 
~SkTypefaceCache()18 SkTypefaceCache::~SkTypefaceCache() {
19     const Rec* curr = fArray.begin();
20     const Rec* stop = fArray.end();
21     while (curr < stop) {
22         curr->fFace->unref();
23         curr += 1;
24     }
25 }
26 
add(SkTypeface * face,const SkFontStyle & requestedStyle)27 void SkTypefaceCache::add(SkTypeface* face, const SkFontStyle& requestedStyle) {
28     if (fArray.count() >= TYPEFACE_CACHE_LIMIT) {
29         this->purge(TYPEFACE_CACHE_LIMIT >> 2);
30     }
31 
32     Rec* rec = fArray.append();
33     rec->fFace = SkRef(face);
34     rec->fRequestedStyle = requestedStyle;
35 }
36 
findByProcAndRef(FindProc proc,void * ctx) const37 SkTypeface* SkTypefaceCache::findByProcAndRef(FindProc proc, void* ctx) const {
38     const Rec* curr = fArray.begin();
39     const Rec* stop = fArray.end();
40     while (curr < stop) {
41         SkTypeface* currFace = curr->fFace;
42         if (proc(currFace, curr->fRequestedStyle, ctx)) {
43             return SkRef(currFace);
44         }
45         curr += 1;
46     }
47     return NULL;
48 }
49 
purge(int numToPurge)50 void SkTypefaceCache::purge(int numToPurge) {
51     int count = fArray.count();
52     int i = 0;
53     while (i < count) {
54         SkTypeface* face = fArray[i].fFace;
55         if (face->unique()) {
56             face->unref();
57             fArray.remove(i);
58             --count;
59             if (--numToPurge == 0) {
60                 return;
61             }
62         } else {
63             ++i;
64         }
65     }
66 }
67 
purgeAll()68 void SkTypefaceCache::purgeAll() {
69     this->purge(fArray.count());
70 }
71 
72 ///////////////////////////////////////////////////////////////////////////////
73 
Get()74 SkTypefaceCache& SkTypefaceCache::Get() {
75     static SkTypefaceCache gCache;
76     return gCache;
77 }
78 
NewFontID()79 SkFontID SkTypefaceCache::NewFontID() {
80     static int32_t gFontID;
81     return sk_atomic_inc(&gFontID) + 1;
82 }
83 
84 SK_DECLARE_STATIC_MUTEX(gMutex);
85 
Add(SkTypeface * face,const SkFontStyle & requestedStyle)86 void SkTypefaceCache::Add(SkTypeface* face, const SkFontStyle& requestedStyle) {
87     SkAutoMutexAcquire ama(gMutex);
88     Get().add(face, requestedStyle);
89 }
90 
FindByProcAndRef(FindProc proc,void * ctx)91 SkTypeface* SkTypefaceCache::FindByProcAndRef(FindProc proc, void* ctx) {
92     SkAutoMutexAcquire ama(gMutex);
93     SkTypeface* typeface = Get().findByProcAndRef(proc, ctx);
94     return typeface;
95 }
96 
PurgeAll()97 void SkTypefaceCache::PurgeAll() {
98     SkAutoMutexAcquire ama(gMutex);
99     Get().purgeAll();
100 }
101 
102 ///////////////////////////////////////////////////////////////////////////////
103 
104 #ifdef SK_DEBUG
DumpProc(SkTypeface * face,const SkFontStyle & s,void * ctx)105 static bool DumpProc(SkTypeface* face, const SkFontStyle& s, void* ctx) {
106     SkDebugf("SkTypefaceCache: face %p fontID %d weight %d width %d style %d refcnt %d\n",
107              face, face->uniqueID(), s.weight(), s.width(), s.slant(), face->getRefCnt());
108     return false;
109 }
110 #endif
111 
Dump()112 void SkTypefaceCache::Dump() {
113 #ifdef SK_DEBUG
114     SkAutoMutexAcquire ama(gMutex);
115     (void)Get().findByProcAndRef(DumpProc, NULL);
116 #endif
117 }
118