add charsToGlyphs to SkTypeface

Will disable new unittest until all backends are implemented.

On Mac, new API is 4x faster than old paint one, so next CL I will reimplement the paint calls in terms of the new typeface call.

R=eae@chromium.org

Review URL: https://codereview.chromium.org/18083023

git-svn-id: http://skia.googlecode.com/svn/trunk@9860 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/PaintTest.cpp b/tests/PaintTest.cpp
index 0db34b6..6d12ebe 100644
--- a/tests/PaintTest.cpp
+++ b/tests/PaintTest.cpp
@@ -1,15 +1,112 @@
-
 /*
  * Copyright 2011 Google Inc.
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+
 #include "Test.h"
 #include "SkPath.h"
 #include "SkPaint.h"
 #include "SkLayerDrawLooper.h"
 #include "SkBlurMaskFilter.h"
+#include "SkRandom.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+static size_t uni_to_utf8(const SkUnichar src[], void* dst, int count) {
+    char* u8 = (char*)dst;
+    for (int i = 0; i < count; ++i) {
+        int n = SkUTF8_FromUnichar(src[i], u8);
+        u8 += n;
+    }
+    return u8 - (char*)dst;
+}
+
+static size_t uni_to_utf16(const SkUnichar src[], void* dst, int count) {
+    uint16_t* u16 = (uint16_t*)dst;
+    for (int i = 0; i < count; ++i) {
+        int n = SkUTF16_FromUnichar(src[i], u16);
+        u16 += n;
+    }
+    return (char*)u16 - (char*)dst;
+}
+
+static size_t uni_to_utf32(const SkUnichar src[], void* dst, int count) {
+    SkUnichar* u32 = (SkUnichar*)dst;
+    if (src != u32) {
+        memcpy(u32, src, count * sizeof(SkUnichar));
+    }
+    return count * sizeof(SkUnichar);
+}
+
+static SkTypeface::Encoding paint2encoding(const SkPaint& paint) {
+    SkPaint::TextEncoding enc = paint.getTextEncoding();
+    SkASSERT(SkPaint::kGlyphID_TextEncoding != enc);
+    return (SkTypeface::Encoding)enc;
+}
+
+static int find_first_zero(const uint16_t glyphs[], int count) {
+    for (int i = 0; i < count; ++i) {
+        if (0 == glyphs[i]) {
+            return i;
+        }
+    }
+    return count;
+}
+
+static void test_cmap(skiatest::Reporter* reporter) {
+    static const int NGLYPHS = 64;
+
+    SkUnichar src[NGLYPHS];
+    SkUnichar dst[NGLYPHS]; // used for utf8, utf16, utf32 storage
+
+    static const struct {
+        size_t (*fSeedTextProc)(const SkUnichar[], void* dst, int count);
+        SkPaint::TextEncoding   fEncoding;
+    } gRec[] = {
+        { uni_to_utf8,  SkPaint::kUTF8_TextEncoding },
+        { uni_to_utf16, SkPaint::kUTF16_TextEncoding },
+        { uni_to_utf32, SkPaint::kUTF32_TextEncoding },
+    };
+
+    SkRandom rand;
+    SkPaint paint;
+    paint.setTypeface(SkTypeface::RefDefault())->unref();
+    SkTypeface* face = paint.getTypeface();
+
+    for (int i = 0; i < 1000; ++i) {
+        // generate some random text
+        for (int j = 0; j < NGLYPHS; ++j) {
+            src[j] = ' ' + j;
+        }
+        // inject some random chars, to sometimes abort early
+        src[rand.nextU() & 63] = rand.nextU() & 0xFFF;
+        
+        for (size_t k = 0; k < SK_ARRAY_COUNT(gRec); ++k) {
+            paint.setTextEncoding(gRec[k].fEncoding);
+
+            size_t len = gRec[k].fSeedTextProc(src, dst, NGLYPHS);
+            
+            uint16_t    glyphs0[NGLYPHS], glyphs1[NGLYPHS];
+    
+            bool contains = paint.containsText(dst, len);
+            int nglyphs = paint.textToGlyphs(dst, len, glyphs0);
+            int first = face->charsToGlyphs(dst, paint2encoding(paint), glyphs1, NGLYPHS);
+            int index = find_first_zero(glyphs1, NGLYPHS);
+
+            REPORTER_ASSERT(reporter, NGLYPHS == nglyphs);
+            REPORTER_ASSERT(reporter, index == first);
+            REPORTER_ASSERT(reporter,
+                        !memcmp(glyphs0, glyphs1, NGLYPHS * sizeof(uint16_t)));
+            if (contains) {
+                REPORTER_ASSERT(reporter, NGLYPHS == first);
+            } else {
+                REPORTER_ASSERT(reporter, NGLYPHS > first);
+            }
+        }
+    }
+}
 
 // temparary api for bicubic, just be sure we can set/clear it
 static void test_bicubic(skiatest::Reporter* reporter) {
@@ -134,6 +231,11 @@
     regression_measureText(reporter);
 
     test_bicubic(reporter);
+#ifdef SK_BUILD_FOR_MAC
+    // need to implement charsToGlyphs on other backends (e.g. linux, win)
+    // before we can run this tests everywhre
+    test_cmap(reporter);
+#endif
 }
 
 #include "TestClassDef.h"