Merge changes from the android repo upstream to Skia
Review URL: https://codereview.appspot.com/5545070

git-svn-id: http://skia.googlecode.com/svn/trunk@3199 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 14ab405..034486d 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1517,7 +1517,12 @@
                                       const SkIRect& center, const SkRect& dst,
                                       const SkPaint* paint) {
     if (NULL == paint || paint->canComputeFastBounds()) {
-        if (this->quickReject(dst, paint2EdgeType(paint))) {
+        SkRect storage;
+        const SkRect* bounds = &dst;
+        if (paint) {
+            bounds = &paint->computeFastBounds(dst, &storage);
+        }
+        if (this->quickReject(*bounds, paint2EdgeType(paint))) {
             return;
         }
     }
diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h
index 090a73f..2895c54 100644
--- a/src/core/SkGlyphCache.h
+++ b/src/core/SkGlyphCache.h
@@ -73,6 +73,14 @@
     */
     unsigned getGlyphCount();
 
+#ifdef SK_BUILD_FOR_ANDROID
+    /** Returns the base glyph count for this strike.
+    */
+    unsigned getBaseGlyphCount(SkUnichar charCode) const {
+        return fScalerContext->getBaseGlyphCount(charCode);
+    }
+#endif
+
     /** Return the image associated with the glyph. If it has not been generated
         this will trigger that.
     */
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 3b9714e..0578f3c 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -22,6 +22,7 @@
 #include "SkTypeface.h"
 #include "SkXfermode.h"
 #include "SkAutoKern.h"
+#include "SkGlyphCache.h"
 
 // define this to get a printf for out-of-range parameter in setters
 // e.g. setTextSize(-1)
@@ -162,6 +163,14 @@
 }
 #endif
 
+#ifdef SK_BUILD_FOR_ANDROID
+unsigned SkPaint::getBaseGlyphCount(SkUnichar text) const {
+    SkAutoGlyphCache autoCache(*this, NULL);
+    SkGlyphCache* cache = autoCache.getCache();
+    return cache->getBaseGlyphCount(text);
+}
+#endif
+
 void SkPaint::setHinting(Hinting hintingLevel) {
     GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting);
     fHinting = hintingLevel;
@@ -397,6 +406,16 @@
     return glyph;
 }
 
+const SkGlyph& SkPaint::getGlyphMetrics(uint16_t glyphId) {
+    SkGlyphCache* cache;
+    descriptorProc(NULL, DetachDescProc, &cache, true);
+
+    const SkGlyph& glyph = cache->getGlyphIDMetrics(glyphId);
+
+    SkGlyphCache::AttachCache(cache);
+    return glyph;
+}
+
 const void* SkPaint::findImage(const SkGlyph& glyph) {
     // See ::detachCache()
     SkGlyphCache* cache;
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index 4403da6..2921b1e 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -175,6 +175,32 @@
     return ctx;
 }
 
+#ifdef SK_BUILD_FOR_ANDROID
+/*  This loops through all available fallback contexts (if needed) until it
+    finds some context that can handle the unichar and return it.
+
+    As this is somewhat expensive operation, it should only be done on the first
+    char of a run.
+ */
+unsigned SkScalerContext::getBaseGlyphCount(SkUnichar uni) {
+    SkScalerContext* ctx = this;
+    unsigned glyphID;
+    for (;;) {
+        glyphID = ctx->generateCharToGlyph(uni);
+        if (glyphID) {
+            break;  // found it
+        }
+        ctx = ctx->getNextContext();
+        if (NULL == ctx) {
+            SkDebugf("--- no context for char %x\n", uni);
+            // just return the original context (this)
+            return this->fBaseGlyphCount;
+        }
+    }
+    return ctx->fBaseGlyphCount;
+}
+#endif
+
 /*  This loops through all available fallback contexts (if needed) until it
     finds some context that can handle the unichar. If all fail, returns 0
  */
diff --git a/src/gpu/GrTesselatedPathRenderer.cpp b/src/gpu/GrTesselatedPathRenderer.cpp
index f7fd8e4..f6fcdef 100644
--- a/src/gpu/GrTesselatedPathRenderer.cpp
+++ b/src/gpu/GrTesselatedPathRenderer.cpp
@@ -61,7 +61,7 @@
         Sk_gluTessCallback(fTess, GLU_TESS_COMBINE_DATA, (TESSCB) &combineCB);
         fInVertices = new double[count * 3];
     }
-    ~GrTess() {
+    virtual ~GrTess() {
         Sk_gluDeleteTess(fTess);
         delete[] fInVertices;
     }
diff --git a/src/opts/SkBlitRow_opts_arm.cpp b/src/opts/SkBlitRow_opts_arm.cpp
index 761bf74..20a82c8 100644
--- a/src/opts/SkBlitRow_opts_arm.cpp
+++ b/src/opts/SkBlitRow_opts_arm.cpp
@@ -988,7 +988,7 @@
 
 	    /* calculate 'd', which will be 0..7 */
 	    /* dbase[] is 0..7; alpha is 0..256; 16 bits suffice */
-#if SK_BUILD_FOR_ANDROID
+#if defined(SK_BUILD_FOR_ANDROID)
 	    /* SkAlpha255To256() semantic a+1 vs a+a>>7 */
 	    alpha8 = vaddw_u8(vmovl_u8(sa), vdup_n_u8(1));
 #else
diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp
index a3bd79c..9a6d633 100644
--- a/src/ports/SkFontHost_android.cpp
+++ b/src/ports/SkFontHost_android.cpp
@@ -1,4 +1,4 @@
-/*
+/* libs/graphics/ports/SkFontHost_android.cpp
 **
 ** Copyright 2006, The Android Open Source Project
 **
@@ -26,6 +26,8 @@
 #include "FontHostConfiguration_android.h"
 #include <stdio.h>
 
+#define FONT_CACHE_MEMORY_BUDGET    (768 * 1024)
+
 #ifndef SK_FONT_FILE_PREFIX
     #define SK_FONT_FILE_PREFIX          "/fonts/"
 #endif
@@ -179,7 +181,7 @@
         prev = curr;
         curr = next;
     }
-    SkDEBUGFAIL("Yikes, couldn't find family in our list to remove/delete");
+    SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
 }
 
 static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
@@ -462,9 +464,11 @@
         // shouldn't get here
         gNumSystemFonts = 0;
     }
+//    SkDebugf("---- We have %d system fonts", gNumSystemFonts);
     for (size_t i = 0; i < gNumSystemFonts; ++i) {
         gSystemFonts[i].fFileName = fontInfo[i].fFileName;
         gSystemFonts[i].fNames = fontInfo[i].fNames;
+//        SkDebugf("---- gSystemFonts[%d] fileName=%s", i, fontInfo[i].fFileName);
     }
     fontFamilies.deleteAll();
 }
@@ -509,11 +513,13 @@
                                      isFixedWidth) // filename
                                     );
 
+//        SkDebugf("---- SkTypeface[%d] %s fontID %d\n", i, rec[i].fFileName, tf->uniqueID());
+
         if (rec[i].fNames != NULL) {
             // see if this is one of our fallback fonts
             if (rec[i].fNames == gFBNames) {
-            //    SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
-            //             rec[i].fFileName, fallbackCount, tf->uniqueID());
+//                SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
+//                         rec[i].fFileName, fallbackCount, tf->uniqueID());
                 gFallbackFonts[fallbackCount++] = tf->uniqueID();
             }
 
@@ -760,4 +766,3 @@
     stream->unref();
     return face;
 }
-
diff --git a/src/ports/SkImageRef_ashmem.cpp b/src/ports/SkImageRef_ashmem.cpp
index 8c69b38..f9c6aff 100644
--- a/src/ports/SkImageRef_ashmem.cpp
+++ b/src/ports/SkImageRef_ashmem.cpp
@@ -91,15 +91,17 @@
             
             int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
             if (err) {
-                SkDebugf("------ ashmem_set_prot_region(%d) failed %d %d\n",
-                         fd, err, errno);
+                SkDebugf("------ ashmem_set_prot_region(%d) failed %d\n",
+                         fd, err);
+                close(fd);
                 return false;
             }
             
             addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
             if (-1 == (long)addr) {
-                SkDebugf("---------- mmap failed for imageref_ashmem size=%d err=%d\n",
-                         size, errno);
+                SkDebugf("---------- mmap failed for imageref_ashmem size=%d\n",
+                         size);
+                close(fd);
                 return false;
             }
             
@@ -178,8 +180,7 @@
             SkDebugf("===== ashmem purged %d\n", fBitmap.getSize());
 #endif
         } else {
-            SkDebugf("===== ashmem pin_region(%d) returned %d, treating as error %d\n",
-                     fRec.fFD, pin, errno);
+            SkDebugf("===== ashmem pin_region(%d) returned %d\n", fRec.fFD, pin);
             // return null result for failure
             if (ct) {
                 *ct = NULL;
diff --git a/src/utils/SkNinePatch.cpp b/src/utils/SkNinePatch.cpp
index 9729a13..26ae8eb 100644
--- a/src/utils/SkNinePatch.cpp
+++ b/src/utils/SkNinePatch.cpp
@@ -46,6 +46,31 @@
     return indices - startIndices;
 }
 
+// Computes the delta between vertices along a single axis
+static SkScalar computeVertexDelta(bool isStretchyVertex,
+                                   SkScalar currentVertex,
+                                   SkScalar prevVertex,
+                                   SkScalar stretchFactor) {
+    // the standard delta between vertices if no stretching is required
+    SkScalar delta = currentVertex - prevVertex;
+
+    // if the stretch factor is negative or zero we need to shrink the 9-patch
+    // to fit within the target bounds.  This means that we will eliminate all
+    // stretchy areas and scale the fixed areas to fit within the target bounds.
+    if (stretchFactor <= 0) {
+        if (isStretchyVertex)
+            delta = 0; // collapse stretchable areas
+        else
+            delta = SkScalarMul(delta, -stretchFactor); // scale fixed areas
+    // if the stretch factor is positive then we use the standard delta for
+    // fixed and scale the stretchable areas to fill the target bounds.
+    } else if (isStretchyVertex) {
+        delta = SkScalarMul(delta, stretchFactor);
+    }
+
+    return delta;
+}
+
 static void fillRow(SkPoint verts[], SkPoint texs[],
                     const SkScalar vy, const SkScalar ty,
                     const SkRect& bounds, const int32_t xDivs[], int numXDivs,
@@ -53,21 +78,14 @@
     SkScalar vx = bounds.fLeft;
     verts->set(vx, vy); verts++;
     texs->set(0, ty); texs++;
+
+    SkScalar prev = 0;
     for (int x = 0; x < numXDivs; x++) {
-        SkScalar tx = SkIntToScalar(xDivs[x]);
-        if (stretchX >= 0) {
-            if (x & 1) {
-                vx += stretchX;
-            } else {
-                vx += tx;
-            }
-        } else {
-            if (x & 1) {
-                ; // do nothing
-            } else {
-                vx += SkScalarMul(tx, -stretchX);
-            }
-        }
+
+        const SkScalar tx = SkIntToScalar(xDivs[x]);
+        vx += computeVertexDelta(x & 1, tx, prev, stretchX);
+        prev = tx;
+
         verts->set(vx, vy); verts++;
         texs->set(tx, ty); texs++;
     }
@@ -139,12 +157,11 @@
         for (int i = 1; i < numXDivs; i += 2) {
             stretchSize += xDivs[i] - xDivs[i-1];
         }
-        int fixed = bitmap.width() - stretchSize;
-        stretchX = (bounds.width() - SkIntToScalar(fixed)) / numXStretch;
-        if (stretchX < 0) {
-            // reuse stretchX, but keep it negative as a signal
-            stretchX = -SkIntToScalar(bitmap.width()) / fixed;
-        }
+        const SkScalar fixed = SkIntToScalar(bitmap.width() - stretchSize);
+        if (bounds.width() >= fixed)
+            stretchX = (bounds.width() - fixed) / stretchSize;
+        else // reuse stretchX, but keep it negative as a signal
+            stretchX = SkScalarDiv(-bounds.width(), fixed);
     }
     
     if (numYStretch > 0) {
@@ -152,12 +169,11 @@
         for (int i = 1; i < numYDivs; i += 2) {
             stretchSize += yDivs[i] - yDivs[i-1];
         }
-        int fixed = bitmap.height() - stretchSize;
-        stretchY = (bounds.height() - SkIntToScalar(fixed)) / numYStretch;
-        if (stretchY < 0) {
-            // reuse stretchY, but keep it negative as a signal
-            stretchY = -SkIntToScalar(bitmap.height()) / fixed;
-        }
+        const SkScalar fixed = SkIntToScalar(bitmap.height() - stretchSize);
+        if (bounds.height() >= fixed)
+            stretchY = (bounds.height() - fixed) / stretchSize;
+        else // reuse stretchX, but keep it negative as a signal
+            stretchY = SkScalarDiv(-bounds.height(), fixed);
     }
     
 #if 0