Add color emoji fallback for distance field text.

BUG=skia:3033

Review URL: https://codereview.chromium.org/670533002
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index 5793ba2..86cc83c 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -54,3 +54,6 @@
 megalooper_1x4
 megalooper_4x1
 imagefiltersbase
+
+# jvanverth - adding color emoji to df text
+dftext
diff --git a/gm/dftext.cpp b/gm/dftext.cpp
index 6f75c46..16fe4bd 100755
--- a/gm/dftext.cpp
+++ b/gm/dftext.cpp
@@ -5,30 +5,44 @@
  * found in the LICENSE file.
  */
 #include "gm.h"
+#include "Resources.h"
+#include "SkCanvas.h"
+#include "SkStream.h"
 #include "SkSurface.h"
 #include "SkTypeface.h"
 
-namespace skiagm {
-
-class DFTextGM : public GM {
+class DFTextGM : public skiagm::GM {
 public:
     DFTextGM() {
         this->setBGColor(0xFFFFFFFF);
+        fTypeface = NULL;
     }
 
     virtual ~DFTextGM() {
+        SkSafeUnref(fTypeface);
     }
 
 protected:
+    virtual void onOnceBeforeDraw() SK_OVERRIDE {
+        SkString filename = GetResourcePath("/Funkster.ttf");
+        SkAutoTUnref<SkFILEStream> stream(new SkFILEStream(filename.c_str()));
+        if (!stream->isValid()) {
+            SkDebugf("Could not find Funkster.ttf, please set --resourcePath correctly.\n");
+            return;
+        }
+
+        fTypeface = SkTypeface::CreateFromStream(stream);
+    }
+
     virtual uint32_t onGetFlags() const SK_OVERRIDE {
         return kGPUOnly_Flag;
     }
 
-    virtual SkString onShortName() {
+    virtual SkString onShortName() SK_OVERRIDE {
         return SkString("dftext");
     }
 
-    virtual SkISize onISize() {
+    virtual SkISize onISize() SK_OVERRIDE {
         return SkISize::Make(1024, 768);
     }
 
@@ -185,6 +199,10 @@
             y += paint.getFontMetrics(NULL);
         }
 
+        // check color emoji
+        paint.setTypeface(fTypeface);
+        canvas->drawText(text, textLen, 670, 100, paint);
+
 #if SK_SUPPORT_GPU
         // render offscreen buffer
         if (surface) {
@@ -199,12 +217,9 @@
     }
 
 private:
-    typedef GM INHERITED;
+    SkTypeface* fTypeface;
+
+    typedef skiagm::GM INHERITED;
 };
 
-//////////////////////////////////////////////////////////////////////////////
-
-static GM* MyFactory(void*) { return new DFTextGM; }
-static GMRegistry reg(MyFactory);
-
-}
+DEF_GM( return SkNEW(DFTextGM); )
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp
index 6b047e4..dcaee48 100755
--- a/src/gpu/GrDistanceFieldTextContext.cpp
+++ b/src/gpu/GrDistanceFieldTextContext.cpp
@@ -294,9 +294,12 @@
     setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
 
     const char*        stop = text + byteLength;
+    SkTArray<char>     fallbackTxt;
+    SkTArray<SkScalar> fallbackPos;
 
     if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
         while (text < stop) {
+            const char* lastText = text;
             // the last 2 parameters are ignored
             const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
 
@@ -304,12 +307,19 @@
                 SkScalar x = offset.x() + pos[0];
                 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);
 
-                this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
-                                                glyph.getSubXFixed(),
-                                                glyph.getSubYFixed()),
-                                  SkScalarToFixed(x),
-                                  SkScalarToFixed(y),
-                                  fontScaler);
+                if (!this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
+                                                     glyph.getSubXFixed(),
+                                                     glyph.getSubYFixed()),
+                                       SkScalarToFixed(x),
+                                       SkScalarToFixed(y),
+                                       fontScaler)) {
+                    // couldn't append, send to fallback
+                    fallbackTxt.push_back_n(text-lastText, lastText);
+                    fallbackPos.push_back(pos[0]);
+                    if (2 == scalarsPerPosition) {
+                        fallbackPos.push_back(pos[1]);
+                    }
+                }
             }
             pos += scalarsPerPosition;
         }
@@ -317,6 +327,7 @@
         SkScalar alignMul = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? SK_ScalarHalf
                                                                               : SK_Scalar1;
         while (text < stop) {
+            const char* lastText = text;
             // the last 2 parameters are ignored
             const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
 
@@ -327,18 +338,30 @@
                 SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX)*alignMul*fTextRatio;
                 SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY)*alignMul*fTextRatio;
 
-                this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
-                                                glyph.getSubXFixed(),
-                                                glyph.getSubYFixed()),
-                                  SkScalarToFixed(x - advanceX),
-                                  SkScalarToFixed(y - advanceY),
-                                  fontScaler);
+                if (!this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
+                                                     glyph.getSubXFixed(),
+                                                     glyph.getSubYFixed()),
+                                       SkScalarToFixed(x - advanceX),
+                                       SkScalarToFixed(y - advanceY),
+                                       fontScaler)) {
+                    // couldn't append, send to fallback
+                    fallbackTxt.push_back_n(text-lastText, lastText);
+                    fallbackPos.push_back(pos[0]);
+                    if (2 == scalarsPerPosition) {
+                        fallbackPos.push_back(pos[1]);
+                    }
+                }
             }
             pos += scalarsPerPosition;
         }
     }
 
     this->finish();
+    
+    if (fallbackTxt.count() > 0) {
+        fFallbackTextContext->drawPosText(paint, skPaint, fallbackTxt.begin(), fallbackTxt.count(),
+                                          fallbackPos.begin(), scalarsPerPosition, offset);
+    }
 }
 
 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
@@ -398,11 +421,13 @@
     
 }
 
-void GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed,
+// Returns true if this method handled the glyph, false if needs to be passed to fallback
+//
+bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed,
                                              SkFixed vx, SkFixed vy,
                                              GrFontScaler* scaler) {
     if (NULL == fDrawTarget) {
-        return;
+        return true;
     }
 
     if (NULL == fStrike) {
@@ -411,12 +436,12 @@
 
     GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
     if (NULL == glyph || glyph->fBounds.isEmpty()) {
-        return;
+        return true;
     }
 
-    // TODO: support color glyphs
+    // fallback to color glyph support
     if (kA8_GrMaskFormat != glyph->fMaskFormat) {
-        return;
+        return false;
     }
 
     SkScalar sx = SkFixedToScalar(vx);
@@ -474,7 +499,7 @@
             if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
                 // flag the glyph as being dead?
                 delete path;
-                return;
+                return true;
             }
             glyph->fPath = path;
         }
@@ -490,7 +515,7 @@
         am.setPreConcat(fContext, ctm, &tmpPaint);
         GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
         fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
-        return;
+        return true;
     }
 
 HAS_ATLAS:
@@ -606,6 +631,8 @@
     }
 
     fCurrVertex += 4;
+    
+    return true;
 }
 
 void GrDistanceFieldTextContext::flush() {
diff --git a/src/gpu/GrDistanceFieldTextContext.h b/src/gpu/GrDistanceFieldTextContext.h
index 6fa2d6f..e0ef7e2 100644
--- a/src/gpu/GrDistanceFieldTextContext.h
+++ b/src/gpu/GrDistanceFieldTextContext.h
@@ -58,7 +58,7 @@
                                const SkPoint& offset) SK_OVERRIDE;
 
     void init(const GrPaint&, const SkPaint&);
-    void appendGlyph(GrGlyph::PackedID, SkFixed left, SkFixed top, GrFontScaler*);
+    bool appendGlyph(GrGlyph::PackedID, SkFixed left, SkFixed top, GrFontScaler*);
     void setupCoverageEffect(const SkColor& filteredColor);
     void flush();                 // automatically called by destructor
     void finish();