WeakRefCnt
http://codereview.appspot.com/5649046/


git-svn-id: http://skia.googlecode.com/svn/trunk@3978 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkTypefaceCache.cpp b/src/core/SkTypefaceCache.cpp
index f4397a6..ee5ced9 100644
--- a/src/core/SkTypefaceCache.cpp
+++ b/src/core/SkTypefaceCache.cpp
@@ -13,7 +13,9 @@
 
 #define TYPEFACE_CACHE_LIMIT    128
 
-void SkTypefaceCache::add(SkTypeface* face, SkTypeface::Style requestedStyle) {
+void SkTypefaceCache::add(SkTypeface* face,
+                          SkTypeface::Style requestedStyle,
+                          bool strong) {
     if (fArray.count() >= TYPEFACE_CACHE_LIMIT) {
         this->purge(TYPEFACE_CACHE_LIMIT >> 2);
     }
@@ -21,7 +23,12 @@
     Rec* rec = fArray.append();
     rec->fFace = face;
     rec->fRequestedStyle = requestedStyle;
-    face->ref();
+    rec->fStrong = strong;
+    if (strong) {
+        face->ref();
+    } else {
+        face->weak_ref();
+    }
 }
 
 SkTypeface* SkTypefaceCache::findByID(SkFontID fontID) const {
@@ -36,12 +43,20 @@
     return NULL;
 }
 
-SkTypeface* SkTypefaceCache::findByProc(FindProc proc, void* ctx) const {
+SkTypeface* SkTypefaceCache::findByProcAndRef(FindProc proc, void* ctx) const {
     const Rec* curr = fArray.begin();
     const Rec* stop = fArray.end();
     while (curr < stop) {
-        if (proc(curr->fFace, curr->fRequestedStyle, ctx)) {
-            return curr->fFace;
+        SkTypeface* currFace = curr->fFace;
+        if (proc(currFace, curr->fRequestedStyle, ctx)) {
+            if (curr->fStrong) {
+                currFace->ref();
+                return currFace;
+            } else if (currFace->try_ref()) {
+                return currFace;
+            } else {
+                //remove currFace from fArray?
+            }
         }
         curr += 1;
     }
@@ -53,8 +68,15 @@
     int i = 0;
     while (i < count) {
         SkTypeface* face = fArray[i].fFace;
-        if (1 == face->getRefCnt()) {
-            face->unref();
+        bool strong = fArray[i].fStrong;
+        if ((strong && face->getRefCnt() == 1) ||
+            (!strong && face->weak_expired()))
+        {
+            if (strong) {
+                face->unref();
+            } else {
+                face->weak_unref();
+            }
             fArray.remove(i);
             --count;
             if (--numToPurge == 0) {
@@ -84,9 +106,11 @@
 
 SK_DECLARE_STATIC_MUTEX(gMutex);
 
-void SkTypefaceCache::Add(SkTypeface* face, SkTypeface::Style requestedStyle) {
+void SkTypefaceCache::Add(SkTypeface* face,
+                          SkTypeface::Style requestedStyle,
+                          bool strong) {
     SkAutoMutexAcquire ama(gMutex);
-    Get().add(face, requestedStyle);
+    Get().add(face, requestedStyle, strong);
 }
 
 SkTypeface* SkTypefaceCache::FindByID(SkFontID fontID) {
@@ -96,8 +120,7 @@
 
 SkTypeface* SkTypefaceCache::FindByProcAndRef(FindProc proc, void* ctx) {
     SkAutoMutexAcquire ama(gMutex);
-    SkTypeface* typeface = Get().findByProc(proc, ctx);
-    SkSafeRef(typeface);
+    SkTypeface* typeface = Get().findByProcAndRef(proc, ctx);
     return typeface;
 }
 
@@ -119,7 +142,7 @@
 void SkTypefaceCache::Dump() {
 #ifdef SK_DEBUG
     SkAutoMutexAcquire ama(gMutex);
-    (void)Get().findByProc(DumpProc, NULL);
+    (void)Get().findByProcAndRef(DumpProc, NULL);
 #endif
 }
 
diff --git a/src/core/SkTypefaceCache.h b/src/core/SkTypefaceCache.h
index e65ec90..b6cab81 100644
--- a/src/core/SkTypefaceCache.h
+++ b/src/core/SkTypefaceCache.h
@@ -26,7 +26,7 @@
     /**
      * Callback for FindByProc. Returns true if the given typeface is a match
      * for the given context. The passed typeface is owned by the cache and is
-     * not additionally ref()ed.
+     * not additionally ref()ed. The typeface may be in the disposed state.
      */
     typedef bool (*FindProc)(SkTypeface*, SkTypeface::Style, void* context);
 
@@ -42,7 +42,9 @@
      *  whose refcnt is 1 (meaning only the cache is an owner) will be
      *  unref()ed.
      */
-    static void Add(SkTypeface*, SkTypeface::Style requested);
+    static void Add(SkTypeface*,
+                    SkTypeface::Style requested,
+                    bool strong = true);
 
     /**
      *  Search the cache for a typeface with the specified fontID (uniqueID).
@@ -75,14 +77,15 @@
 private:
     static SkTypefaceCache& Get();
 
-    void add(SkTypeface*, SkTypeface::Style requested);
+    void add(SkTypeface*, SkTypeface::Style requested, bool strong = true);
     SkTypeface* findByID(SkFontID findID) const;
-    SkTypeface* findByProc(FindProc proc, void* ctx) const;
+    SkTypeface* findByProcAndRef(FindProc proc, void* ctx) const;
     void purge(int count);
     void purgeAll();
 
     struct Rec {
         SkTypeface*         fFace;
+        bool                fStrong;
         SkTypeface::Style   fRequestedStyle;
     };
     SkTDArray<Rec> fArray;
diff --git a/src/ports/SkThread_none.cpp b/src/ports/SkThread_none.cpp
index a948a54..56bbbae 100644
--- a/src/ports/SkThread_none.cpp
+++ b/src/ports/SkThread_none.cpp
@@ -21,6 +21,14 @@
     *addr = value - 1;
     return value;
 }
+void sk_membar_aquire__after_atomic_dec() { }
+
+int32_t sk_atomic_conditional_inc(int32_t* addr) {
+    int32_t value = *addr;
+    if (value != 0) ++*addr;
+    return value;
+}
+void sk_membar_aquire__after_atomic_conditional_inc() { }
 
 SkMutex::SkMutex() {}
 
diff --git a/src/ports/SkThread_pthread.cpp b/src/ports/SkThread_pthread.cpp
index 6a4fade..d0bb3ac 100644
--- a/src/ports/SkThread_pthread.cpp
+++ b/src/ports/SkThread_pthread.cpp
@@ -39,6 +39,27 @@
 {
     return __sync_fetch_and_add(addr, -1);
 }
+void sk_membar_aquire__after_atomic_dec() { }
+
+int32_t sk_atomic_conditional_inc(int32_t* addr)
+{
+    int32_t value = *addr;
+
+    while (true) {
+        if (value == 0) {
+            return 0;
+        }
+
+        int32_t before = __sync_val_compare_and_swap(addr, value, value + 1);
+
+        if (before == value) {
+            return value;
+        } else {
+            value = before;
+        }
+    }
+}
+void sk_membar_aquire__after_atomic_conditional_inc() { }
 
 #else
 
@@ -61,6 +82,17 @@
     *addr = value - 1;
     return value;
 }
+void sk_membar_aquire__after_atomic_dec() { }
+
+int32_t sk_atomic_conditional_inc(int32_t* addr)
+{
+    SkAutoMutexAcquire ac(gAtomicMutex);
+
+    int32_t value = *addr;
+    if (value != 0) ++*addr;
+    return value;
+}
+void sk_membar_aquire__after_atomic_conditional_inc() { }
 
 #endif
 
diff --git a/src/ports/SkThread_win.cpp b/src/ports/SkThread_win.cpp
index 6c960e2..e833314 100644
--- a/src/ports/SkThread_win.cpp
+++ b/src/ports/SkThread_win.cpp
@@ -17,6 +17,7 @@
 //directive.
 //The pragma appears to be unnecessary, but doesn't hurt.
 #pragma intrinsic(_InterlockedIncrement, _InterlockedDecrement)
+#pragma intrinsic(_InterlockedCompareExchange)
 
 int32_t sk_atomic_inc(int32_t* addr) {
     // InterlockedIncrement returns the new value, we want to return the old.
@@ -26,6 +27,22 @@
 int32_t sk_atomic_dec(int32_t* addr) {
     return _InterlockedDecrement(reinterpret_cast<LONG*>(addr)) + 1;
 }
+void sk_membar_aquire__after_atomic_dec() { }
+
+int32_t sk_atomic_conditional_inc(int32_t* addr) {
+    while (true) {
+        LONG value = static_cast<LONG const volatile&>(*addr);
+        if (value == 0) {
+            return 0;
+        }
+        if (_InterlockedCompareExchange(reinterpret_cast<LONG*>(addr),
+                                        value + 1,
+                                        value) == value) {
+            return value;
+        }
+    }
+}
+void sk_membar_aquire__after_atomic_conditional_inc() { }
 
 SkMutex::SkMutex() {
     SK_COMPILE_ASSERT(sizeof(fStorage) > sizeof(CRITICAL_SECTION),