add typefacecache
speedup lcd blits
clean up some samples



git-svn-id: http://skia.googlecode.com/svn/trunk@1220 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/Makefile b/Makefile
index 8548612..d03c12f 100644
--- a/Makefile
+++ b/Makefile
@@ -102,6 +102,7 @@
 #	SRC_LIST += src/ports/SkImageDecoder_CG.cpp
 	SRC_LIST += src/utils/mac/SkCreateCGImageRef.cpp
 	SRC_LIST += src/utils/mac/SkEGLContext_mac.cpp
+	SRC_LIST += src/core/SkTypefaceCache.cpp
 	SRC_LIST += src/ports/SkFontHost_mac_coretext.cpp
 
     # these are our registry-based factories
diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h
index daa6e54..d0f7c65 100644
--- a/include/core/SkFontHost.h
+++ b/include/core/SkFontHost.h
@@ -24,7 +24,6 @@
 class SkStream;
 class SkWStream;
 
-typedef uint32_t SkFontID;
 typedef uint32_t SkFontTableTag;
 
 /** \class SkFontHost
diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h
index c415329..e13a21d 100644
--- a/include/core/SkTypeface.h
+++ b/include/core/SkTypeface.h
@@ -24,6 +24,8 @@
 class SkAdvancedTypefaceMetrics;
 class SkWStream;
 
+typedef uint32_t SkFontID;
+
 /** \class SkTypeface
 
     The SkTypeface class specifies the typeface and intrinsic style of a font.
@@ -65,13 +67,13 @@
     /** Return a 32bit value for this typeface, unique for the underlying font
         data. Will never return 0.
      */
-    uint32_t uniqueID() const { return fUniqueID; }
+    SkFontID uniqueID() const { return fUniqueID; }
 
     /** Return the uniqueID for the specified typeface. If the face is null,
         resolve it to the default font and return its uniqueID. Will never
         return 0.
     */
-    static uint32_t UniqueID(const SkTypeface* face);
+    static SkFontID UniqueID(const SkTypeface* face);
 
     /** Returns true if the two typefaces reference the same underlying font,
         handling either being null (treating null as the default font)
@@ -147,11 +149,11 @@
 protected:
     /** uniqueID must be unique (please!) and non-zero
     */
-    SkTypeface(Style style, uint32_t uniqueID, bool isFixedWidth = false)
-        : fUniqueID(uniqueID), fStyle(style), fIsFixedWidth(isFixedWidth) {}
+    SkTypeface(Style style, SkFontID uniqueID, bool isFixedWidth = false);
+    virtual ~SkTypeface();
 
 private:
-    uint32_t    fUniqueID;
+    SkFontID    fUniqueID;
     Style       fStyle;
     bool        fIsFixedWidth;
 
diff --git a/samplecode/SampleAll.cpp b/samplecode/SampleAll.cpp
index 17b2829..f57bf38 100644
--- a/samplecode/SampleAll.cpp
+++ b/samplecode/SampleAll.cpp
@@ -343,23 +343,9 @@
 #endif
 }
 
-static void test_math()
-{
-    float x;
-    const float PI = 3.141593f;
-    
-    for (x = 0; x < 1; x += 0.05f)
-        printf("atan(%g) = %g\n", x, atanf(x) * 180/PI);
-    for (x = 1; x < 10000000; x *= 2)
-        printf("atan(%g) = %g\n", x, atanf(x) * 180/PI);
-}
-
 class DemoView : public SkView {
 public:
-    DemoView()
-    {
-        test_math();
-    }
+    DemoView() {}
 	
 protected:
     // overrides from SkEventSink
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 88c7f4b..266264e 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -1337,12 +1337,34 @@
     return this->INHERITED::onQuery(evt);
 }
 
+#define TEST_GPIPEx
+#include "SkGPipe.h"
+
 void SampleView::onDraw(SkCanvas* canvas) {
     this->onDrawBackground(canvas);
+
+#ifdef TEST_GPIPE
+    SkGPipeWriter writer;
+    SkCanvas* origCanvas = canvas;
+    canvas = writer.startRecording();
+#endif
+
     for (int i = 0; i < fRepeatCount; i++) {
         SkAutoCanvasRestore acr(canvas, true);
         this->onDrawContent(canvas);
     }
+
+#ifdef TEST_GPIPE
+    writer.endRecording();
+
+    size_t size = writer.flatten(NULL);
+    SkAutoMalloc storage(size);
+    writer.flatten(storage.get());
+
+    SkGPipeReader reader(origCanvas);
+    SkGPipeReader::Status status = reader.playback(storage.get(), size);
+    SkASSERT(SkGPipeReader::kDone_Status == status);
+#endif
 }
 
 void SampleView::onDrawBackground(SkCanvas* canvas) {
diff --git a/samplecode/SampleDraw.cpp b/samplecode/SampleDraw.cpp
index 39a64cf..54070d1 100644
--- a/samplecode/SampleDraw.cpp
+++ b/samplecode/SampleDraw.cpp
@@ -4,6 +4,30 @@
 #include "SkGraphics.h"
 #include "SkRandom.h"
 
+static void test_clearonlayers(SkCanvas* canvas) {
+    SkCanvas& c = *canvas;
+    
+    SkPaint paint;
+    paint.setColor(SK_ColorBLUE);
+    paint.setStyle(SkPaint::kStrokeAndFill_Style);
+    SkRect rect = SkRect::MakeXYWH(25, 25, 50, 50);
+    c.drawRect(rect, paint);
+    
+    c.clipRect(rect);
+    
+    c.saveLayer(NULL, NULL);
+    rect = SkRect::MakeXYWH(50, 10, 40, 80);
+    c.clipRect(rect, SkRegion::kUnion_Op);
+    
+    rect = SkRect::MakeXYWH(50, 0, 50, 100);
+    // You might draw something here, but it's not necessary.
+    // paint.setColor(SK_ColorRED);
+    // c.drawRect(rect, paint);
+    paint.setXfermodeMode(SkXfermode::kClear_Mode);
+    c.drawRect(rect, paint);
+    c.restore();
+}
+
 static void test_strokerect(SkCanvas* canvas, const SkRect& r) {
     SkPaint p;
     
@@ -277,8 +301,8 @@
 
     virtual void onDraw(SkCanvas* canvas) {
         this->drawBG(canvas);
-     //   test_strokerect(canvas);
-     //   return;
+        test_clearonlayers(canvas); return;
+     //   test_strokerect(canvas); return;
 
         for (Draw** iter = fList.begin(); iter < fList.end(); iter++) {
             (*iter)->draw(canvas);
diff --git a/samplecode/SampleFontScalerTest.cpp b/samplecode/SampleFontScalerTest.cpp
index c481503..0b0d349 100644
--- a/samplecode/SampleFontScalerTest.cpp
+++ b/samplecode/SampleFontScalerTest.cpp
@@ -29,7 +29,7 @@
 
 static const int gFaceCount = SK_ARRAY_COUNT(gFaces);
 
-class FontScalerTestView : public SkView {
+class FontScalerTestView : public SampleView {
     SkTypeface* fFaces[gFaceCount];
 
 public:
@@ -38,6 +38,7 @@
             fFaces[i] = SkTypeface::CreateFromName(gFaces[i].fName,
                                                    gFaces[i].fStyle);
         }
+        this->setBGColor(0xFFDDDDDD);
     }
 
     virtual ~FontScalerTestView() {
@@ -56,13 +57,7 @@
         return this->INHERITED::onQuery(evt);
     }
 
-    void drawBG(SkCanvas* canvas) {
-        canvas->drawColor(0xFFDDDDDD);
-    }
-
-    virtual void onDraw(SkCanvas* canvas) {
-        this->drawBG(canvas);
-
+    virtual void onDrawContent(SkCanvas* canvas) {
         SkPaint paint;
 
         // test handling of obscene cubic values (currently broken)
diff --git a/samplecode/SampleLines.cpp b/samplecode/SampleLines.cpp
index 4d05a9a..24291f3 100644
--- a/samplecode/SampleLines.cpp
+++ b/samplecode/SampleLines.cpp
@@ -25,30 +25,7 @@
 
 class LinesView : public SkView {
 public:
-	LinesView()
-    {
-        unsigned r = 0x1F;
-        unsigned g = 0x3F;
-        for (unsigned a = 0; a <= 0xF; a++) {
-            unsigned scale = 16 - SkAlpha15To16(a);
-            unsigned sr = (a << 1) | (a >> 3);
-            unsigned dr = r * scale >> 4;
-            unsigned sg = (a << 2) | (a >> 2);
-            unsigned dg = g * scale >> 4;
-            
-            unsigned ssg = sg & ~(~(a >> 3) & 1);
-            
-            printf("4444 sa=%d sr=%d sg=%d da=%d dr=%d dg=%d total-r=%d total-g=%d %d\n",
-                   a, sr, sg, scale, dr, dg, sr+dr, sg+dg, ssg+dg);
-        }
-        
-        for (unsigned aa = 0; aa <= 0xFF; aa++) {
-            unsigned invScale = SkAlpha255To256(255 - aa);
-            unsigned dst = SkAlphaMul(0xFF, invScale);
-            printf("8888 sa=%02x dst=%02x sum=%d %s\n", aa, dst, aa+dst,
-                   (aa+dst) > 0xFF ? "OVERFLOW" : "");
-        }
-    }
+	LinesView() {}
     
 protected:
     // overrides from SkEventSink
diff --git a/samplecode/SamplePicture.cpp b/samplecode/SamplePicture.cpp
index 6c018b7..00a9d2e 100644
--- a/samplecode/SamplePicture.cpp
+++ b/samplecode/SamplePicture.cpp
@@ -33,7 +33,7 @@
 
 protected:
     virtual void onDraw(SkCanvas* canvas) {
-        SkDebugf("---- sc %d\n", canvas->getSaveCount() - 1);
+    //    SkDebugf("---- sc %d\n", canvas->getSaveCount() - 1);
     }
 
 private:
diff --git a/samplecode/SamplePolyToPoly.cpp b/samplecode/SamplePolyToPoly.cpp
index 4b6686d..ccfe430 100644
--- a/samplecode/SamplePolyToPoly.cpp
+++ b/samplecode/SamplePolyToPoly.cpp
@@ -19,7 +19,6 @@
             bool success;
 
             success = m1.setPolyToPoly(src, dst, 3);
-            SkDebugf("--- setPolyToPoly1 %d\n", success);
 
             m2.reset();
             m2.set(SkMatrix::kMScaleX, dst[1].fX - dst[0].fX);
@@ -40,7 +39,6 @@
             };
 
             success = m2.setPolyToPoly((const SkPoint*)src1, (SkPoint*)dst1, 4);
-            SkDebugf("--- setPolyToPoly2 %d\n", success);
 
             {
                 const SkPoint src[] = {
@@ -57,8 +55,8 @@
                 SkMatrix m0, m1;
                 m0.setPolyToPoly(src, dst, 3);
               //  SkSetPoly3To3(&m1, src, dst);
-                m0.dump();
-                m1.dump();
+              //  m0.dump();
+              //  m1.dump();
             }
         }
     }
diff --git a/samplecode/SampleText.cpp b/samplecode/SampleText.cpp
index c1090ee..459923a 100644
--- a/samplecode/SampleText.cpp
+++ b/samplecode/SampleText.cpp
@@ -138,7 +138,7 @@
         mm = m;
     }
 
-    int length2 = paint.breakText(text, length, width, &mm);
+    SkDEBUGCODE(int length2 =) paint.breakText(text, length, width, &mm);
     SkASSERT(length2 == length);
     SkASSERT(mm == width);
 }
@@ -222,12 +222,6 @@
     { "Subpixel", SkPaint::kSubpixelText_Flag, true }
 };
 
-#ifdef SK_DEBUG
-    #define REPEAT_COUNT    1
-#else
-    #define REPEAT_COUNT    5
-#endif
-
 static int count_char_points(const SkPaint& paint, char c)
 {
     SkPath  path;
@@ -488,210 +482,8 @@
 
     virtual void onDraw(SkCanvas* canvas)
     {
-        inval(NULL);
-        if (false)
-        {
-            canvas->translate(SkIntToScalar(480), 0);
-            canvas->rotate(SkIntToScalar(90));
-        }
-
         this->drawBG(canvas);
 
-        if (false)
-        {
-            SkPaint p;
-
-            p.setAntiAlias(true);
-            p.setSubpixelText(true);
-         //   p.setLinearText(true);
-
-            SkScalar size = SkIntToScalar(6);
-            SkMSec   dur = 0;
-            const int LOOP = 16;
-            const int TIMES = 10;
-
-            for (int times = 0; times < TIMES; times++)
-            {
-                SkMSec now = SkTime::GetMSecs();
-                for (int loop = 0; loop < LOOP; loop++)
-                {
-                    p.setTextSize(size);
-                    size += SK_Scalar1/5;
-                    canvas->drawText("Hamburgefons", 12, SkIntToScalar(10), SkIntToScalar(50), p);
-                }
-                dur += SkTime::GetMSecs() - now;
-                SkGraphics::SetFontCacheUsed(0);
-            }
-
-            printf("----- duration = %g\n", dur * 1.0 / TIMES);
-            this->inval(NULL);
-            return;
-        }
-
-        if (false)
-        {
-            SkPaint p;
-            p.setAntiAlias(true);
-            for (int i = 6; i <= 36; i++)
-            {
-                SkRect r;
-                SkPaint::FontMetrics m;
-                p.setTextSize(SkIntToScalar(i));
-                p.getFontMetrics(&m);
-                int ascent = SkScalarRound(m.fAscent);
-                int descent = SkScalarRound(m.fDescent);
-                for (uint8_t c = ' '; c <= 127; c++)
-                {
-                    p.getTextWidths(&c, 1, NULL, &r);
-                    if (SkScalarRound(r.fTop) < ascent)
-                        printf("PS %d --- %c [%d] top=%g, ascent=%g ymax=%g\n", i, c, c,
-                                SkScalarToFloat(r.fTop), SkScalarToFloat(m.fAscent), SkScalarToFloat(m.fTop));
-                    if (SkScalarRound(r.fBottom) > descent)
-                        printf("PS %d --- %c [%d] bottom=%g, descent=%g ymin=%g\n", i, c, c,
-                                SkScalarToFloat(r.fBottom), SkScalarToFloat(m.fDescent), SkScalarToFloat(m.fBottom));
-                }
-            }
-        }
-
-        if (false)
-        {
-            SkPaint p;
-            p.setShader(fGradient);
-
-#ifdef SK_RELEASE
-            SkMSec now = SkTime::GetMSecs();
-            for (int i = 0; i < 100; i++)
-#endif
-            canvas->drawPaint(p);
-#ifdef SK_RELEASE
-            printf("----- %d ms\n", SkTime::GetMSecs() - now);
-            this->inval(NULL);
-#endif
-            return;
-        }
-
-        if (false)
-        {
-            SkBitmap    bm;
-
-            make_textstrip(&bm);
-            canvas->translate(0, SkIntToScalar(50));
-            for (int i = 0; i < 10; i++)
-            {
-                float gamma = 1 + i * 0.2f;
-                SkPowerMode mode(SkFloatToScalar(1 / gamma));
-                SkPaint     p;
-                p.setXfermode(&mode);
-
-                canvas->drawBitmap(bm, 0, SkIntToScalar(i) * bm.height(), &p);
-            }
-            return;
-        }
-
-        if (false)
-        {
-            SkPaint paint;
-
-            paint.setAntiAlias(true);
-            paint.setDevKernText(true);
-            SkMSec now = SkTime::GetMSecs();
-            for (int i = 0; i < 1000000; i++)
-            {
-                paint.measureText("Hamburgefons", 15, NULL, NULL);
-            }
-            printf("--------- measure %d\n", SkTime::GetMSecs() - now);
-            this->inval(NULL);
-            return;
-        }
-
-        if (false)
-        {
-            SkRegion    rgn;
-            SkPath      path;
-            SkPaint     paint;
-
-        //    make_badrgn(&rgn, -2);
-
-            if (false)
-            {
-                paint.setColor(SK_ColorBLUE);
-                canvas->drawIRect(rgn.getBounds(), paint);
-            }
-            paint.setColor(SK_ColorRED);
-            draw_rgn(rgn, canvas, paint);
-
-            rgn.getBoundaryPath(&path);
-            paint.setARGB(0x80, 0, 0, 0xFF);
-            canvas->drawPath(path, paint);
-            return;
-        }
-
-        if (false)
-        {
-            SkRect r = { SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(300), SkIntToScalar(300) };
-            SkPaint p;
-
-            p.setStyle(SkPaint::kStroke_Style);
-            p.setAlpha(0x80);
-            p.setStrokeWidth(SkIntToScalar(20));
-            canvas->drawRect(r, p);
-        }
-
-        if (false)
-        {
-            SkPaint p;
-            SkRect r = { SkIntToScalar(100), SkIntToScalar(100), SkIntToScalar(104), SkIntToScalar(104) };
-         //   r.offset(SK_ScalarHalf, SK_ScalarHalf);
-            p.setStyle(SkPaint::kStroke_Style);
-            p.setStrokeWidth(SK_Scalar1*2);
-        //    p.setAntiAliasOn(true);
-            canvas->drawRect(r, p);
-            return;
-        }
-
-        if (false)
-        {
-            Sk64    aa, bb;
-            int64_t a = (int64_t)6062080 * -30596;
-            int64_t b = (int64_t)4816896 * 57957;
-            aa.setMul(6062080, -30596);
-            bb.setMul(4816896, 57957);
-
-            a += b;
-            b = a >> 16;
-
-//            SkFixed c = aa.addGetFixed(bb);
-
-            printf("%d %d\n", (int)a, a >> 32);
-
-            SkBitmap    bm;
-            SkPaint     paint;
-            SkScalar    scale = SkFloatToScalar(0.5625f);
-            SkScalar    x = SkIntToScalar(100);
-            SkScalar    y = SkIntToScalar(100);
-
-            //paint.setFilterType(SkPaint::kBilinear_FilterType);
-
-            SkImageDecoder::DecodeFile("/app_web_browser.png", &bm);
-
-           // canvas->drawBitmap(bm, x, y, paint);
-            x += SkIntToScalar(100);
-            canvas->save();
-                canvas->translate(x, y);
-                canvas->scale(SkIntToScalar(2)/1, SkIntToScalar(2)/1);
-                canvas->translate(-x, -y);
-                canvas->drawBitmap(bm, x, y, &paint);
-            canvas->restore();
-            x += SkIntToScalar(100);
-            canvas->save();
-                canvas->translate(x, y);
-                canvas->scale(scale, scale);
-                canvas->translate(-x, -y);
-            //    canvas->drawBitmap(bm, x, y, paint);
-            canvas->restore();
-            return;
-        }
-
         SkAutoCanvasRestore restore(canvas, false);
         {
             SkRect r;
@@ -713,10 +505,6 @@
         paint.setAntiAlias(true);
         paint.setFlags(paint.getFlags() | gHints[index].fFlags);
 
-        SkMSec now = 0;
-        if (REPEAT_COUNT > 1)
-            now = SkTime::GetMSecs();
-
         SkRect clip;
         clip.set(SkIntToScalar(25), SkIntToScalar(34), SkIntToScalar(88), SkIntToScalar(155));
 
@@ -743,26 +531,17 @@
         }
 #endif
 
-        for (int j = 0; j < REPEAT_COUNT; j++)
-        {
-            SkScalar y = SkIntToScalar(0);
-            for (int i = 9; i <= 24; i++) {
-                paint.setTextSize(SkIntToScalar(i) /*+ (gRand.nextU() & 0xFFFF)*/);
-                for (SkScalar dx = 0; dx <= SkIntToScalar(3)/4; dx += SkIntToScalar(1) /* /4 */)
-                {
-                    y += paint.getFontSpacing();
-                    DrawTheText(canvas, text, length, SkIntToScalar(20) + dx, y, paint, fClickX, fMF);
-                }
-            }
-            if (gHints[index].fFlushCache) {
-//                SkGraphics::SetFontCacheUsed(0);
+        SkScalar y = SkIntToScalar(0);
+        for (int i = 9; i <= 24; i++) {
+            paint.setTextSize(SkIntToScalar(i) /*+ (gRand.nextU() & 0xFFFF)*/);
+            for (SkScalar dx = 0; dx <= SkIntToScalar(3)/4; dx += SkIntToScalar(1) /* /4 */)
+            {
+                y += paint.getFontSpacing();
+                DrawTheText(canvas, text, length, SkIntToScalar(20) + dx, y, paint, fClickX, fMF);
             }
         }
-
-        if (REPEAT_COUNT > 1)
-        {
-            printf("--------- FPS = %g\n", REPEAT_COUNT * 1000. / (SkTime::GetMSecs() - now));
-            this->inval(NULL);
+        if (gHints[index].fFlushCache) {
+//                SkGraphics::SetFontCacheUsed(0);
         }
     }
 
diff --git a/samplecode/SampleTypeface.cpp b/samplecode/SampleTypeface.cpp
index 5442e5f..63f1d5a 100644
--- a/samplecode/SampleTypeface.cpp
+++ b/samplecode/SampleTypeface.cpp
@@ -13,6 +13,7 @@
 #include "SkColorPriv.h"
 #include "SkColorFilter.h"
 #include "SkDither.h"
+#include "SkTypefaceCache.h"
 
 static int dither_4444(int x) {
     return ((x << 1) - ((x >> 4 << 4) | (x >> 4))) >> 4;
@@ -82,6 +83,8 @@
         for (int i = 0; i < gFaceCount; i++) {
             SkSafeUnref(fFaces[i]);
         }
+
+        SkTypefaceCache::Dump();
     }
 
 protected:
@@ -99,11 +102,6 @@
         paint.setAntiAlias(true);
         paint.setTextSize(SkIntToScalar(30));
 
-        if (false) {
-            paint.setStyle(SkPaint::kStroke_Style);
-            paint.setStrokeWidth(SkIntToScalar(1));
-        }
-
         const char* text = "Hamburgefons";
         const size_t textLen = strlen(text);
 
@@ -111,50 +109,12 @@
         SkScalar dy = paint.getFontMetrics(NULL);
         SkScalar y = dy;
 
+        paint.setLinearText(true);
         for (int i = 0; i < gFaceCount; i++) {
             paint.setTypeface(fFaces[i]);
             canvas->drawText(text, textLen, x, y, paint);
             y += dy;
         }
-
-        SkRect r;
-        if (false) {
-        r.set(10, 10, 100, 100);
-        paint.setStyle(SkPaint::kStrokeAndFill_Style);
-        paint.setColor(SK_ColorBLUE);
-        paint.setStrokeWidth(1);
-        canvas->drawRect(r, paint);
-        paint.setStrokeWidth(0);
-        }
-
-        if (false) {
-        r.set(294912.75f, 294912.75f, 884738.25f, 884738.25f);
-        canvas->scale(2.4414E-4f, 2.4414E-4f);
-        paint.setStyle(SkPaint::kFill_Style);
-        canvas->drawRect(r, paint);
-        }
-
-        if (false) {
-            SkScalar rad = 90;
-            SkScalar angle = 210;
-            SkScalar cx = 150;
-            SkScalar cy = 105;
-            r.set(cx - rad, cy - rad, cx + rad, cy + rad);
-            SkPath path;
-            path.arcTo(r, angle, -(angle + 90), true);
-            path.close();
-
-            paint.setColor(SK_ColorRED);
-            canvas->drawRect(path.getBounds(), paint);
-            paint.setColor(SK_ColorBLUE);
-            canvas->drawPath(path, paint);
-
-            paint.setColor(SK_ColorGREEN);
-            SkPoint pts[100];
-            int count = path.getPoints(pts, 100);
-            paint.setStrokeWidth(5);
-            canvas->drawPoints(SkCanvas::kPoints_PointMode, count, pts, paint);
-        }
     }
 
 private:
diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp
index d923315..361d6b6 100644
--- a/src/core/SkBlitter_ARGB32.cpp
+++ b/src/core/SkBlitter_ARGB32.cpp
@@ -40,14 +40,16 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static int upscale31To256(int value) {
+static inline int upscale31To32(int value) {
     SkASSERT((unsigned)value <= 31);
-    // 0..31 -> 0..255
-    value = (value << 3) | (value >> 2);
-    // 0..255 -> 0..256
-    value += (value >> 7);
-    SkASSERT((unsigned)value <= 256);
-    return value;
+    return value + (value >> 4);
+}
+
+static inline unsigned blend32(unsigned src, unsigned dst, unsigned scale) {
+    SkASSERT(src <= 0xFF);
+    SkASSERT(dst <= 0xFF);
+    SkASSERT(scale <= 32);
+    return dst + ((src - dst) * scale >> 5);
 }
 
 static void blit_lcd16_opaque(SkPMColor dst[], const uint16_t src[],
@@ -62,6 +64,8 @@
             continue;
         }
 
+        SkPMColor d = dst[i];
+        
         /*  We want all of these in 5bits, hence the shifts in case one of them
          *  (green) is 6bits.
          */
@@ -70,22 +74,21 @@
         int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
 
         // Now upscale them to 0..256, so we can use SkAlphaBlend
-        maskR = upscale31To256(maskR);
-        maskG = upscale31To256(maskG);
-        maskB = upscale31To256(maskB);
+        maskR = upscale31To32(maskR);
+        maskG = upscale31To32(maskG);
+        maskB = upscale31To32(maskB);
 
         int maskA = SkMax32(SkMax32(maskR, maskG), maskB);
 
-        SkPMColor d = dst[i];
         int dstA = SkGetPackedA32(d);
         int dstR = SkGetPackedR32(d);
         int dstG = SkGetPackedG32(d);
         int dstB = SkGetPackedB32(d);
 
-        dst[i] = SkPackARGB32(SkAlphaBlend(0xFF, dstA, maskA),
-                              SkAlphaBlend(srcR, dstR, maskR),
-                              SkAlphaBlend(srcG, dstG, maskG),
-                              SkAlphaBlend(srcB, dstB, maskB));
+        dst[i] = SkPackARGB32(blend32(0xFF, dstA, maskA),
+                              blend32(srcR, dstR, maskR),
+                              blend32(srcG, dstG, maskG),
+                              blend32(srcB, dstB, maskB));
     }
 }
 
diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp
index 9a764fc..03610d2 100644
--- a/src/core/SkTypeface.cpp
+++ b/src/core/SkTypeface.cpp
@@ -18,6 +18,29 @@
 #include "SkTypeface.h"
 #include "SkFontHost.h"
 
+#define TRACE_LIFECYCLE
+
+#ifdef TRACE_LIFECYCLE
+    static int32_t gTypefaceCounter;
+#endif
+
+SkTypeface::SkTypeface(Style style, SkFontID fontID, bool isFixedWidth)
+    : fUniqueID(fontID), fStyle(style), fIsFixedWidth(isFixedWidth) {
+#ifdef TRACE_LIFECYCLE
+    SkDebugf("SkTypeface: create  %p fontID %d total %d\n",
+             this, fontID, ++gTypefaceCounter);
+#endif
+}
+
+SkTypeface::~SkTypeface() {
+#ifdef TRACE_LIFECYCLE
+    SkDebugf("SkTypeface: destroy %p fontID %d total %d\n",
+             this, fUniqueID, --gTypefaceCounter);
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 uint32_t SkTypeface::UniqueID(const SkTypeface* face) {
     if (face) {
         return face->uniqueID();
diff --git a/src/core/SkTypefaceCache.cpp b/src/core/SkTypefaceCache.cpp
new file mode 100644
index 0000000..4db6bfb
--- /dev/null
+++ b/src/core/SkTypefaceCache.cpp
@@ -0,0 +1,121 @@
+/*
+    Copyright 2011 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+
+#include "SkTypefaceCache.h"
+#include "SkThread.h"
+
+#define TYPEFACE_CACHE_LIMIT    128
+
+void SkTypefaceCache::add(SkTypeface* face, SkTypeface::Style requestedStyle) {
+    if (fArray.count() >= TYPEFACE_CACHE_LIMIT) {
+        this->purge(TYPEFACE_CACHE_LIMIT >> 2);
+    }
+
+    Rec* rec = fArray.append();
+    rec->fFace = face;
+    rec->fRequestedStyle = requestedStyle;
+    face->ref();
+}
+
+SkTypeface* SkTypefaceCache::findByID(SkFontID fontID) const {
+    const Rec* curr = fArray.begin();
+    const Rec* stop = fArray.end();
+    while (curr < stop) {
+        if (curr->fFace->uniqueID() == fontID) {
+            return curr->fFace;
+        }
+        curr += 1;
+    }
+    return NULL;
+}
+
+SkTypeface* SkTypefaceCache::findByProc(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;
+        }
+        curr += 1;
+    }
+    return NULL;
+}
+
+void SkTypefaceCache::purge(int numToPurge) {
+    int count = fArray.count();
+    int i = 0;
+    while (i < count) {
+        SkTypeface* face = fArray[i].fFace;
+        if (1 == face->getRefCnt()) {
+            face->unref();
+            fArray.remove(i);
+            --count;
+            if (--numToPurge == 0) {
+                return;
+            }
+        } else {
+            ++i;
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkTypefaceCache& SkTypefaceCache::Get() {
+    static SkTypefaceCache gCache;
+    return gCache;
+}
+
+SkFontID SkTypefaceCache::NewFontID() {
+    static int32_t gFontID;
+    return sk_atomic_inc(&gFontID) + 1;
+}
+
+static SkMutex gMutex;
+
+void SkTypefaceCache::Add(SkTypeface* face, SkTypeface::Style requestedStyle) {
+    SkAutoMutexAcquire ama(gMutex);
+    Get().add(face, requestedStyle);
+}
+
+SkTypeface* SkTypefaceCache::FindByID(SkFontID fontID) {
+    SkAutoMutexAcquire ama(gMutex);
+    return Get().findByID(fontID);
+}
+
+SkTypeface* SkTypefaceCache::FindByProc(FindProc proc, void* ctx) {
+    SkAutoMutexAcquire ama(gMutex);
+    return Get().findByProc(proc, ctx);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+static bool DumpProc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
+    SkDebugf("SkTypefaceCache: face %p fontID %d style %d refcnt %d\n",
+             face, face->uniqueID(), style, face->getRefCnt());
+    return false;
+}
+#endif
+
+void SkTypefaceCache::Dump() {
+#ifdef SK_DEBUG
+    SkAutoMutexAcquire ama(gMutex);
+    (void)Get().findByProc(DumpProc, NULL);
+#endif
+}
+
diff --git a/src/core/SkTypefaceCache.h b/src/core/SkTypefaceCache.h
new file mode 100644
index 0000000..91411a4
--- /dev/null
+++ b/src/core/SkTypefaceCache.h
@@ -0,0 +1,82 @@
+/*
+    Copyright 2011 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+
+#ifndef SkTypefaceCache_DEFINED
+#define SkTypefaceCache_DEFINED
+
+#include "SkTypeface.h"
+#include "SkTDArray.h"
+
+/*  TODO
+ *  Provide std way to cache name+requestedStyle aliases to the same typeface.
+ *
+ *  The current mechanism ends up create a diff typeface for each one, even if
+ *  they map to the same internal obj (e.g. CTFontRef on the mac)
+ */
+
+class SkTypefaceCache {
+public:
+    typedef bool (*FindProc)(SkTypeface*, SkTypeface::Style, void* context);
+
+    /**
+     *  Helper: returns a unique fontID to pass to the constructor of
+     *  your subclass of SkTypeface
+     */
+    static SkFontID NewFontID();
+
+    /**
+     *  Add a typeface to the cache. This ref()s the typeface, so that the
+     *  cache is also an owner. Later, if we need to purge the cache, it will
+     *  unref() typefaces whose refcnt is 1 (meaning only the cache is an owner).
+     */
+    static void Add(SkTypeface*, SkTypeface::Style requested);
+
+    /**
+     *  Search the cache for a typeface with the specified fontID (uniqueID).
+     *  If one is found, return it (its reference count is unmodified). If none
+     *  is found, return NULL.
+     */
+    static SkTypeface* FindByID(SkFontID fontID);
+
+    /**
+     *  Iterate through the cache, calling proc(typeface, ctx) with each
+     *  typeface. If proc returns true, then we return that typeface (its
+     *  reference count is unmodified). If it never returns true, we return NULL.
+     */
+    static SkTypeface* FindByProc(FindProc proc, void* ctx);
+
+    /**
+     *  Debugging only: dumps the status of the typefaces in the cache
+     */
+    static void Dump();
+
+private:
+    static SkTypefaceCache& Get();
+
+    void add(SkTypeface*, SkTypeface::Style requested);
+    SkTypeface* findByID(SkFontID findID) const;
+    SkTypeface* findByProc(FindProc proc, void* ctx) const;
+    void purge(int count);
+
+    struct Rec {
+        SkTypeface*         fFace;
+        SkTypeface::Style   fRequestedStyle;
+    };
+    SkTDArray<Rec> fArray;
+};
+
+#endif
diff --git a/src/ports/SkFontHost_mac_coretext.cpp b/src/ports/SkFontHost_mac_coretext.cpp
index cdf3eb3..82bde7b 100644
--- a/src/ports/SkFontHost_mac_coretext.cpp
+++ b/src/ports/SkFontHost_mac_coretext.cpp
@@ -23,23 +23,11 @@
 #include "SkString.h"
 #include "SkTypeface_mac.h"
 #include "SkUtils.h"
-
-
-static const SkFontID kSkInvalidFontID          = 0;
+#include "SkTypefaceCache.h"
 
 static const size_t FONT_CACHE_MEMORY_BUDGET    = 1024 * 1024;
 static const char FONT_DEFAULT_NAME[]           = "Lucida Sans";
 
-typedef struct {
-    SkString                name;
-    SkTypeface::Style       style;
-    SkFontID                fontID;
-    CTFontRef               fontRef;
-} SkNativeFontInfo;
-
-typedef std::vector<SkNativeFontInfo>   SkNativeFontInfoList;
-typedef SkNativeFontInfoList::iterator  SkNativeFontInfoListIterator;
-
 //============================================================================
 //      Macros
 //----------------------------------------------------------------------------
@@ -74,233 +62,193 @@
     return (SkTypeface::Style)style;
 }
 
-
-//============================================================================
-//      SkNativeFontCache
-//----------------------------------------------------------------------------
-#pragma mark -
-class SkNativeFontCache {
+class SkTypeface_Mac : public SkTypeface {
 public:
-            SkNativeFontCache(void);
-    virtual ~SkNativeFontCache(void);
+    SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isMonospace)
+        : SkTypeface(style, fontID, isMonospace), fFontRef(0) {}
 
-    bool IsValid(SkFontID fontID);
-    CTFontRef GetFont(SkFontID fontID);
-    SkNativeFontInfo GetFontInfo(const char familyName[], SkTypeface::Style);
-    SkNativeFontInfo CreateFont(const char familyName[], SkTypeface::Style);
-    SkNativeFontInfo CreateFromCTFont(CTFontRef);
+    virtual ~SkTypeface_Mac() { CFRelease(fFontRef); }
 
-    static SkNativeFontCache* Get(void);
-
-private:
-    CTFontRef CreateNativeFont(const char familyName[], SkTypeface::Style style);
-
-
-private:
-    SkNativeFontInfoList mFonts;
-    SkMutex mMutex;
+    SkString    fName;
+    CTFontRef   fFontRef;
 };
 
-SkNativeFontCache::SkNativeFontCache(void)
-{   SkAutoMutexAcquire      acquireLock(mMutex);
-    SkNativeFontInfo        fontInfo;
-
-
-    // Initialise ourselves
-    //
-    // SkTypeface uses a uint32_t to identify fonts, however CoreText font references
-    // are opaque pointers.
-    //
-    // To support 64-bit builds, we need a separate index to look up a 64-bit font
-    // reference from its 32-bit SkFontID. As an ID of 0 is reserved, we insert a
-    // dummy entry into the cache so we can use the array index as the font ID.
-    //
-    // This could be simplified if SkFontID was changed to a intptr_t, and SkTypeface
-    // returned an SkFontID from uniqueID().
-    fontInfo.name    = SkString("__SkNativeFontCache__");
-    fontInfo.style   = SkTypeface::kNormal;
-    fontInfo.fontID  = kSkInvalidFontID;
-    fontInfo.fontRef = NULL;
-
-    mFonts.push_back(fontInfo);
+static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) {
+    bool isMonospace;
+    SkTypeface::Style style = computeStyleBits(fontRef, &isMonospace);
+    SkTypeface_Mac* face = new SkTypeface_Mac(style,
+                                              SkTypefaceCache::NewFontID(),
+                                              isMonospace);
+    face->fFontRef = fontRef;   // we take over ownership of fontRef
+    face->fName.set(name);
+    return face;
 }
 
-SkNativeFontCache::~SkNativeFontCache(void)
-{   SkAutoMutexAcquire                  acquireLock(mMutex);
-    SkNativeFontInfoListIterator        theIter;
-
-
-    // Clean up
-    for (theIter = mFonts.begin(); theIter != mFonts.end(); theIter++)
-        CFSafeRelease(theIter->fontRef);
-}
-
-bool SkNativeFontCache::IsValid(SkFontID fontID)
-{   SkAutoMutexAcquire  acquireLock(mMutex);
-    bool                isValid;
-
-
-    // Check the ID
-    isValid = (fontID >= 1 && fontID < mFonts.size());
-    return(isValid);
-}
-
-CTFontRef SkNativeFontCache::GetFont(SkFontID fontID)
-{   SkAutoMutexAcquire  acquireLock(mMutex);
-
-
-    // Validate our parameters
-    SkASSERT(fontID >= 1 && fontID < mFonts.size());
-
-
-    // Get the font
-    return(mFonts.at(fontID).fontRef);
-}
-
-SkNativeFontInfo SkNativeFontCache::GetFontInfo(const char familyName[],
-                                                SkTypeface::Style theStyle)
-{   SkAutoMutexAcquire              acquireLock(mMutex);
-    SkNativeFontInfo                fontInfo;
-    SkNativeFontInfoListIterator    theIter;
-
-    // Validate our parameters
-    SkASSERT(familyName && *familyName);
-
-    // Get the state we need
-    fontInfo.style   = SkTypeface::kNormal;
-    fontInfo.fontID  = kSkInvalidFontID;
-    fontInfo.fontRef = NULL;
-
-    // Get the font
-    for (theIter = mFonts.begin(); theIter != mFonts.end(); theIter++) {
-        if (theIter->style == theStyle && theIter->name.equals(familyName)) {
-            return *theIter;
-        }
-    }
-
-    return fontInfo;
-}
-
-SkNativeFontInfo SkNativeFontCache::CreateFont(const char familyName[],
-                                               SkTypeface::Style theStyle) {
-    SkAutoMutexAcquire      acquireLock(mMutex);
-    SkNativeFontInfo        fontInfo;
-    
-    
-    // Validate our parameters
-    SkASSERT(familyName && *familyName);
-    
-    
-    // Create the font
-    fontInfo.name.set(familyName);
-    fontInfo.fontID = mFonts.size();
-    fontInfo.fontRef = CreateNativeFont(familyName, theStyle);
-    fontInfo.style = computeStyleBits(fontInfo.fontRef, NULL);
-    
-    mFonts.push_back(fontInfo);
-    return(fontInfo);
-}
-
-SkNativeFontInfo SkNativeFontCache::CreateFromCTFont(CTFontRef font) {
-    SkAutoMutexAcquire      acquireLock(mMutex);
-    SkNativeFontInfo        fontInfo;
-    
-    // TODO: need to query the font's name
-//    fontInfo.name.set(familyName);
-    fontInfo.fontID = mFonts.size();
-    fontInfo.fontRef = font;
-    CFRetain(font);
-    fontInfo.style = computeStyleBits(font, NULL);
-    
-    mFonts.push_back(fontInfo);
-    return(fontInfo);
-}
-
-SkNativeFontCache *SkNativeFontCache::Get(void) {
-    static SkNativeFontCache    sInstance;
-    // We use a local static for well-defined static initialisation order.
-    return &sInstance;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-CTFontRef SkNativeFontCache::CreateNativeFont(const char familyName[],
-                                              SkTypeface::Style theStyle) {
+static SkTypeface* NewFromName(const char familyName[],
+                               SkTypeface::Style theStyle) {
     CFMutableDictionaryRef      cfAttributes, cfTraits;
     CFNumberRef                 cfFontTraits;
     CTFontSymbolicTraits        ctFontTraits;
     CTFontDescriptorRef         ctFontDesc;
     CFStringRef                 cfFontName;
     CTFontRef                   ctFont;
-
-
+    
+    
     // Get the state we need
     ctFontDesc   = NULL;
     ctFont       = NULL;
     ctFontTraits = 0;
-
-    if (theStyle & SkTypeface::kBold)
+    
+    if (theStyle & SkTypeface::kBold) {
         ctFontTraits |= kCTFontBoldTrait;
+    }
 
-    if (theStyle & SkTypeface::kItalic)
+    if (theStyle & SkTypeface::kItalic) {
         ctFontTraits |= kCTFontItalicTrait;
-
-
+    }
+    
     // Create the font info
     cfFontName   = CFStringCreateWithCString(NULL, familyName, kCFStringEncodingUTF8);
     cfFontTraits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits);
     cfAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
     cfTraits     = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-
-
+    
+    
     // Create the font
     if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) {
         CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
-
+        
         CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName);
         CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute,     cfTraits);
-
+        
         ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
         if (ctFontDesc != NULL) {
             ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
         }
     }
-
+    
     CFSafeRelease(cfFontName);
     CFSafeRelease(cfFontTraits);
     CFSafeRelease(cfAttributes);
     CFSafeRelease(cfTraits);
     CFSafeRelease(ctFontDesc);
 
-    return(ctFont);
+    return ctFont ? NewFromFontRef(ctFont, familyName) : NULL;
 }
 
-//============================================================================
-//      SkTypeface_Mac
-//----------------------------------------------------------------------------
-#pragma mark -
-class SkTypeface_Mac : public SkTypeface {
-public:
-    SkTypeface_Mac(SkTypeface::Style style, uint32_t fontID);
+static CTFontRef GetFontRefFromFontID(SkFontID fontID) {
+    SkTypeface_Mac* face = reinterpret_cast<SkTypeface_Mac*>(SkTypefaceCache::FindByID(fontID));
+    return face ? face->fFontRef : 0;
+}
+
+static SkTypeface* GetDefaultFace() {
+    static SkTypeface* gDefaultFace;
+
+    if (NULL == gDefaultFace) {
+        gDefaultFace = new SkTypeface_Mac(SkTypeface::kNormal,
+                                          SkTypefaceCache::NewFontID(), false);
+    }
+    return gDefaultFace;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct FontRefRec {
+    CTFontRef   fFontRef;
 };
 
+static bool FindByFontRef(SkTypeface* face, SkTypeface::Style, void* ctx) {
+    const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
+    const FontRefRec* rec = reinterpret_cast<const FontRefRec*>(ctx);
 
-SkTypeface_Mac::SkTypeface_Mac(SkTypeface::Style style, uint32_t fontID)
-    : SkTypeface(style, fontID) {
+    return rec->fFontRef == mface->fFontRef;
 }
 
+/*  This function is visible on the outside. It first searches the cache, and if
+ *  not found, returns a new entry (after adding it to the cache).
+ */
+SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
+    FontRefRec rec = { fontRef };
+    SkTypeface* face = SkTypefaceCache::FindByProc(FindByFontRef, &rec);
+    if (face) {
+        face->ref();
+    } else {
+        face = NewFromFontRef(fontRef, NULL);
+        SkTypefaceCache::Add(face, face->style());
+    }
+    SkASSERT(face->getRefCnt() > 1);
+    return face;
+}
 
-SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef font) {
-    SkNativeFontInfo info;
+struct NameStyleRec {
+    const char*         fName;
+    SkTypeface::Style   fStyle;
+};
+
+static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style,
+                            void* ctx) {
+    const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
+    const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx);
     
-    info = SkNativeFontCache::Get()->CreateFromCTFont(font);
-    return new SkTypeface_Mac(info.style, info.fontID);
+    return rec->fStyle == style && mface->fName.equals(rec->fName);
 }
 
-//============================================================================
-//      SkScalerContext_Mac
-//----------------------------------------------------------------------------
-#pragma mark -
+static const char* map_css_names(const char* name) {
+    static const struct {
+        const char* fFrom;  // name the caller specified
+        const char* fTo;    // "canonical" name we map to
+    } gPairs[] = {
+        { "sans-serif", "Helvetica" },
+        { "serif",      "Times"     },
+        { "monospace",  "Courier"   }
+    };
+    
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
+        if (strcmp(name, gPairs[i].fFrom) == 0) {
+            return gPairs[i].fTo;
+        }
+    }
+    return name;    // no change
+}
+
+SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
+                                       const char familyName[],
+                                       const void* data, size_t bytelength,
+                                       SkTypeface::Style style) {
+    if (familyName) {
+        familyName = map_css_names(familyName);
+    }
+    
+    // Clone an existing typeface
+    // TODO: only clone if style matches the familyFace's style...
+    if (familyName == NULL && familyFace != NULL) {
+        familyFace->ref();
+        return const_cast<SkTypeface*>(familyFace);
+    }
+    
+    if (!familyName || !*familyName) {
+        familyName = FONT_DEFAULT_NAME;
+    }
+    
+    NameStyleRec rec = { familyName, style };
+    SkTypeface* face = SkTypefaceCache::FindByProc(FindByNameStyle, &rec);
+
+    if (face) {
+        face->ref();
+    } else {
+        face = NewFromName(familyName, style);
+        if (face) {
+            SkTypefaceCache::Add(face, style);
+        } else {
+            face = GetDefaultFace();
+            face->ref();
+        }
+    }
+    return face;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 class SkScalerContext_Mac : public SkScalerContext {
 public:
                                         SkScalerContext_Mac(const SkDescriptor* desc);
@@ -341,7 +289,7 @@
     // Get the state we need
     fRec.getSingleMatrix(&skMatrix);
 
-    ctFont    = SkNativeFontCache::Get()->GetFont(fRec.fFontID);
+    ctFont    = GetFontRefFromFontID(fRec.fFontID);
     numGlyphs = CTFontGetGlyphCount(ctFont);
     SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
 
@@ -642,56 +590,7 @@
 }
 
 
-static const char* map_css_names(const char* name) {
-    static const struct {
-        const char* fFrom;
-        const char* fTo;
-    } gPairs[] = {
-        { "sans-serif", "Helvetica" },
-        { "serif",      "Times"     },
-        { "monospace",  "Courier"   }
-    };
-
-    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
-        if (strcmp(name, gPairs[i].fFrom) == 0) {
-            return gPairs[i].fTo;
-        }
-    }
-    return name;    // no change
-}
-
-///////////////////////////////////////////////////////////////////////////
-#pragma mark -
-
-SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
-                                       const char familyName[],
-                                       const void* data, size_t bytelength,
-                                       SkTypeface::Style style) {
-    if (familyName) {
-        familyName = map_css_names(familyName);
-    }
-
-    SkNativeFontCache* fontTable = SkNativeFontCache::Get();
-
-    // Clone an existing typeface
-    // TODO: only clone if style matches the familyFace's style...
-    if (familyName == NULL && familyFace != NULL) {
-        familyFace->ref();
-        return const_cast<SkTypeface*>(familyFace);
-    }
-
-    if (!familyName || !*familyName) {
-        familyName = FONT_DEFAULT_NAME;
-    }
-
-    // Get the native font
-    SkNativeFontInfo fontInfo = fontTable->GetFontInfo(familyName, style);
-    if (fontInfo.fontID == kSkInvalidFontID) {
-        fontInfo = fontTable->CreateFont(familyName, style);
-    }
-
-    return new SkTypeface_Mac(fontInfo.style, fontInfo.fontID);
-}
+///////////////////////////////////////////////////////////////////////////////
 
 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
 {
@@ -713,76 +612,50 @@
     return NULL;
 }
 
-///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
 
-bool SkFontHost::ValidFontID(SkFontID uniqueID)
-{
-
-    // Check the font ID
-    return(SkNativeFontCache::Get()->IsValid(uniqueID));
+bool SkFontHost::ValidFontID(SkFontID fontID) {
+    return SkTypefaceCache::FindByID(fontID) != NULL;
 }
 
-SkStream* SkFontHost::OpenStream(SkFontID uniqueID)
-{
+SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
     SkASSERT(!"SkFontHost::OpenStream unimplemented");
     return(NULL);
 }
 
-size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, int32_t* index)
-{
+size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
+                               int32_t* index) {
     SkASSERT(!"SkFontHost::GetFileName unimplemented");
     return(0);
 }
 
-///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
 
-void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream)
-{
+void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
     SkASSERT(!"SkFontHost::Serialize unimplemented");
 }
 
-SkTypeface* SkFontHost::Deserialize(SkStream* stream)
-{
+SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
     SkASSERT(!"SkFontHost::Deserialize unimplemented");
     return(NULL);
 }
 
-///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
 
-SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc)
-{
+SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
     return new SkScalerContext_Mac(desc);
 }
 
-uint32_t SkFontHost::NextLogicalFont(uint32_t fontID)
-{   SkTypeface      *typeFace;
-    uint32_t        newFontID;
-
-
-    // Get the state we need
-    newFontID = kSkInvalidFontID;
-    typeFace  = CreateTypeface(NULL, FONT_DEFAULT_NAME, NULL, 0, SkTypeface::kNormal);
-
-    if (typeFace == NULL)
-        return(0);
-
-
-    // Get the next font
-    //
-    // When we're passed in the default font, we've reached the end.
-    newFontID = typeFace->uniqueID();
-    if (newFontID == fontID)
-        newFontID = 0;
-
-
-    // Clean up
-    typeFace->unref();
-
-    return(newFontID);
+SkFontID SkFontHost::NextLogicalFont(SkFontID fontID) {
+    SkFontID nextFontID = 0;
+    SkTypeface* face = GetDefaultFace();
+    if (face->uniqueID() != fontID) {
+        nextFontID = face->uniqueID();
+    }
+    return nextFontID;
 }
 
-void SkFontHost::FilterRec(SkScalerContext::Rec* rec)
-{
+void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
     // we only support 2 levels of hinting
     SkPaint::Hinting h = rec->getHinting();
     if (SkPaint::kSlight_Hinting == h) {
@@ -800,35 +673,32 @@
 
 ///////////////////////////////////////////////////////////////////////////
 
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar)
-{
-    if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
+size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
+    if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) {
         return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
-    else
-        return 0;   // nothing to do
-}
-
-int SkFontHost::ComputeGammaFlag(const SkPaint& paint)
-{
+    }
     return 0;
 }
 
-void SkFontHost::GetGammaTables(const uint8_t* tables[2])
-{
+int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
+    return 0;
+}
+
+void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
     tables[0] = NULL;   // black gamma (e.g. exp=1.4)
     tables[1] = NULL;   // white gamma (e.g. exp= 1/1.4)
 }
 
 ///////////////////////////////////////////////////////////////////////////
 
-int SkFontHost::CountTables(SkFontID fontID)
-{   int             numTables;
+int SkFontHost::CountTables(SkFontID fontID) {
+    int             numTables;
     CFArrayRef      cfArray;
     CTFontRef       ctFont;
 
 
     // Get the state we need
-    ctFont    = SkNativeFontCache::Get()->GetFont(fontID);
+    ctFont    = GetFontRefFromFontID(fontID);
     cfArray   = CTFontCopyAvailableTables(ctFont, kCTFontTableOptionNoOptions);
     numTables = 0;
 
@@ -850,7 +720,7 @@
 
 
     // Get the state we need
-    ctFont    = SkNativeFontCache::Get()->GetFont(fontID);
+    ctFont    = GetFontRefFromFontID(fontID);
     cfArray   = CTFontCopyAvailableTables(ctFont, kCTFontTableOptionNoOptions);
     numTables = 0;
 
@@ -875,7 +745,7 @@
 
 
     // Get the state we need
-    ctFont  = SkNativeFontCache::Get()->GetFont(fontID);
+    ctFont  = GetFontRefFromFontID(fontID);
     cfData  = CTFontCopyTable(ctFont, (CTFontTableTag) tag, kCTFontTableOptionNoOptions);
     theSize = 0;
 
@@ -898,7 +768,7 @@
 
 
     // Get the state we need
-    ctFont  = SkNativeFontCache::Get()->GetFont(fontID);
+    ctFont  = GetFontRefFromFontID(fontID);
     cfData  = CTFontCopyTable(ctFont, (CTFontTableTag) tag, kCTFontTableOptionNoOptions);
     theSize = 0;
 
diff --git a/xcode/maccore/maccore.xcodeproj/project.pbxproj b/xcode/maccore/maccore.xcodeproj/project.pbxproj
index 7d4ccba..2dce372 100644
--- a/xcode/maccore/maccore.xcodeproj/project.pbxproj
+++ b/xcode/maccore/maccore.xcodeproj/project.pbxproj
@@ -16,6 +16,7 @@
 		00488AF40F86532E00C08A57 /* SkDebug_stdio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00488AF30F86532E00C08A57 /* SkDebug_stdio.cpp */; };
 		005B11BF12EFDC2D00A08864 /* SkFontHost_mac_coretext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27D0F41C11BD227D001B8EBE /* SkFontHost_mac_coretext.cpp */; };
 		007C8DC910B4694D008CDB57 /* SkUtils_opts_none.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007C8DC810B4694D008CDB57 /* SkUtils_opts_none.cpp */; };
+		00AB17D2136EE742004E1B73 /* SkTypefaceCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00AB17D1136EE742004E1B73 /* SkTypefaceCache.cpp */; };
 		27739F2B0F11407000F233EA /* SkCreateCGImageRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27739F2A0F11407000F233EA /* SkCreateCGImageRef.cpp */; };
 		27739F2D0F11408100F233EA /* SkImageDecoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27739F2C0F11408100F233EA /* SkImageDecoder.cpp */; };
 /* End PBXBuildFile section */
@@ -31,6 +32,7 @@
 		002884E00EFABFFC0083E387 /* SkGlobals_global.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkGlobals_global.cpp; path = ../../src/ports/SkGlobals_global.cpp; sourceTree = SOURCE_ROOT; };
 		00488AF30F86532E00C08A57 /* SkDebug_stdio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkDebug_stdio.cpp; path = ../../src/ports/SkDebug_stdio.cpp; sourceTree = SOURCE_ROOT; };
 		007C8DC810B4694D008CDB57 /* SkUtils_opts_none.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkUtils_opts_none.cpp; path = ../../src/opts/SkUtils_opts_none.cpp; sourceTree = SOURCE_ROOT; };
+		00AB17D1136EE742004E1B73 /* SkTypefaceCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkTypefaceCache.cpp; path = ../../src/core/SkTypefaceCache.cpp; sourceTree = SOURCE_ROOT; };
 		27739F2A0F11407000F233EA /* SkCreateCGImageRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkCreateCGImageRef.cpp; path = ../../src/utils/mac/SkCreateCGImageRef.cpp; sourceTree = SOURCE_ROOT; };
 		27739F2C0F11408100F233EA /* SkImageDecoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkImageDecoder.cpp; path = ../../src/images/SkImageDecoder.cpp; sourceTree = SOURCE_ROOT; };
 		27739F2E0F11409100F233EA /* SkImageDecoder_CG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkImageDecoder_CG.cpp; path = ../../src/ports/SkImageDecoder_CG.cpp; sourceTree = SOURCE_ROOT; };
@@ -77,6 +79,7 @@
 			children = (
 				27D0F41B11BD227D001B8EBE /* SkFontHost_mac_atsui.cpp */,
 				27D0F41C11BD227D001B8EBE /* SkFontHost_mac_coretext.cpp */,
+				00AB17D1136EE742004E1B73 /* SkTypefaceCache.cpp */,
 				007C8DC810B4694D008CDB57 /* SkUtils_opts_none.cpp */,
 				00488AF30F86532E00C08A57 /* SkDebug_stdio.cpp */,
 				002884E00EFABFFC0083E387 /* SkGlobals_global.cpp */,
@@ -183,6 +186,7 @@
 				003144D50FB8491400B10956 /* SkImageDecoder_CG.cpp in Sources */,
 				007C8DC910B4694D008CDB57 /* SkUtils_opts_none.cpp in Sources */,
 				005B11BF12EFDC2D00A08864 /* SkFontHost_mac_coretext.cpp in Sources */,
+				00AB17D2136EE742004E1B73 /* SkTypefaceCache.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -228,7 +232,7 @@
 				HEADER_SEARCH_PATHS = "/opt/local/include/**";
 				PREBINDING = NO;
 				SDKROOT = "";
-				USER_HEADER_SEARCH_PATHS = "../../include//**";
+				USER_HEADER_SEARCH_PATHS = "../../src/core ../../include//**";
 			};
 			name = Debug;
 		};
@@ -248,7 +252,7 @@
 				HEADER_SEARCH_PATHS = "/opt/local/include/**";
 				PREBINDING = NO;
 				SDKROOT = "";
-				USER_HEADER_SEARCH_PATHS = "../../include//**";
+				USER_HEADER_SEARCH_PATHS = "../../src/core ../../include//**";
 			};
 			name = Release;
 		};