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