Adding drop shadow support

Change-Id: I9b1b9568d6cebc0761d96ab678b018571f705ae1
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 5595ab0..feb45ec 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -80,6 +80,37 @@
             nPenX, nPenY - height, 0, u1, v1);
 }
 
+void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
+                             uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
+    int nPenX = x + glyph->mBitmapLeft;
+    int nPenY = y + glyph->mBitmapTop;
+
+    uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
+    uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
+
+    if(nPenX < 0 || nPenY < 0) {
+        LOGE("Cannot render into a bitmap, some of the glyph is below zero");
+        return;
+    }
+
+    if(nPenX + glyph->mBitmapWidth >= bitmapW || nPenY + glyph->mBitmapHeight >= bitmapH) {
+        LOGE("Cannot render into a bitmap, dimentions too small");
+        return;
+    }
+
+    uint32_t cacheWidth = mState->getCacheWidth();
+    const uint8_t* cacheBuffer = mState->getTextTextureData();
+
+    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
+    for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
+        for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
+            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
+            bitmap[bY * bitmapW + bX] = tempCol;
+        }
+    }
+
+}
+
 Font::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) {
     CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueFor(utfChar);
     if (cachedGlyph == NULL) {
@@ -96,7 +127,7 @@
 }
 
 void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
-        int numGlyphs, int x, int y) {
+        int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
     if (numGlyphs == 0 || text == NULL || len == 0) {
         return;
     }
@@ -121,7 +152,12 @@
 
         // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
         if (cachedGlyph->mIsValid) {
-            drawCachedGlyph(cachedGlyph, penX, penY);
+            if(bitmap != NULL) {
+                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
+            }
+            else {
+                drawCachedGlyph(cachedGlyph, penX, penY);
+            }
         }
 
         penX += SkFixedFloor(cachedGlyph->mAdvanceX);
@@ -153,6 +189,8 @@
     uint32_t endX = startX + skiaGlyph.fWidth;
     uint32_t endY = startY + skiaGlyph.fHeight;
 
+    glyph->mStartX = startX;
+    glyph->mStartY = startY;
     glyph->mBitmapWidth = skiaGlyph.fWidth;
     glyph->mBitmapHeight = skiaGlyph.fHeight;
 
@@ -234,9 +272,9 @@
     }
     mCacheLines.clear();
 
-    delete mTextMeshPtr;
+    delete[] mTextMeshPtr;
+    delete[] mTextTexture;
 
-    delete mTextTexture;
     if(mTextureId) {
         glDeleteTextures(1, &mTextureId);
     }
@@ -308,14 +346,14 @@
 
     uint32_t cacheWidth = mCacheWidth;
 
-    unsigned char* cacheBuffer = mTextTexture;
-    unsigned char* bitmapBuffer = (unsigned char*) glyph.fImage;
+    uint8_t* cacheBuffer = mTextTexture;
+    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
     unsigned int stride = glyph.rowBytes();
 
     uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
     for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
         for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
-            unsigned char tempCol = bitmapBuffer[bY * stride + bX];
+            uint8_t tempCol = bitmapBuffer[bY * stride + bX];
             cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol;
         }
     }
@@ -324,7 +362,7 @@
 }
 
 void FontRenderer::initTextTexture() {
-    mTextTexture = new unsigned char[mCacheWidth * mCacheHeight];
+    mTextTexture = new uint8_t[mCacheWidth * mCacheHeight];
     mUploadTexture = false;
 
     glGenTextures(1, &mTextureId);
@@ -550,5 +588,144 @@
     }
 }
 
+void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
+    // Compute gaussian weights for the blur
+    // e is the euler's number
+    float e = 2.718281828459045f;
+    float pi = 3.1415926535897932f;
+    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
+    // x is of the form [-radius .. 0 .. radius]
+    // and sigma varies with radius.
+    // Based on some experimental radius values and sigma's
+    // we approximately fit sigma = f(radius) as
+    // sigma = radius * 0.4  + 0.6
+    // The larger the radius gets, the more our gaussian blur
+    // will resemble a box blur since with large sigma
+    // the gaussian curve begins to lose its shape
+    float sigma = 0.4f * (float)radius + 0.6f;
+
+    // Now compute the coefficints
+    // We will store some redundant values to save some math during
+    // the blur calculations
+    // precompute some values
+    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
+    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
+
+    float normalizeFactor = 0.0f;
+    for(int32_t r = -radius; r <= radius; r ++) {
+        float floatR = (float)r;
+        weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
+        normalizeFactor += weights[r + radius];
+    }
+
+    //Now we need to normalize the weights because all our coefficients need to add up to one
+    normalizeFactor = 1.0f / normalizeFactor;
+    for(int32_t r = -radius; r <= radius; r ++) {
+        weights[r + radius] *= normalizeFactor;
+    }
+}
+
+void FontRenderer::horizontalBlur(float* weights, int32_t radius,
+                                    const uint8_t* source, uint8_t* dest,
+                                    int32_t width, int32_t height) {
+    float blurredPixel = 0.0f;
+    float currentPixel = 0.0f;
+
+    for(int32_t y = 0; y < height; y ++) {
+
+        const uint8_t* input = source + y * width;
+        uint8_t* output = dest + y * width;
+
+        for(int32_t x = 0; x < width; x ++) {
+            blurredPixel = 0.0f;
+            const float* gPtr = weights;
+            // Optimization for non-border pixels
+            if ((x > radius) && (x < (width - radius))) {
+                const uint8_t *i = input + (x - radius);
+                for(int r = -radius; r <= radius; r ++) {
+                    currentPixel = (float)(*i);
+                    blurredPixel += currentPixel * gPtr[0];
+                    gPtr++;
+                    i++;
+                }
+            } else {
+                for(int32_t r = -radius; r <= radius; r ++) {
+                    // Stepping left and right away from the pixel
+                    int validW = x + r;
+                    if(validW < 0) {
+                        validW = 0;
+                    }
+                    if(validW > width - 1) {
+                        validW = width - 1;
+                    }
+
+                    currentPixel = (float)(input[validW]);
+                    blurredPixel += currentPixel * gPtr[0];
+                    gPtr++;
+                }
+            }
+            *output = (uint8_t)blurredPixel;
+            output ++;
+        }
+    }
+}
+
+void FontRenderer::verticalBlur(float* weights, int32_t radius,
+                                  const uint8_t* source, uint8_t* dest,
+                                  int32_t width, int32_t height) {
+    float blurredPixel = 0.0f;
+    float currentPixel = 0.0f;
+
+    for(int32_t y = 0; y < height; y ++) {
+
+        uint8_t* output = dest + y * width;
+
+        for(int32_t x = 0; x < width; x ++) {
+            blurredPixel = 0.0f;
+            const float* gPtr = weights;
+            const uint8_t* input = source + x;
+            // Optimization for non-border pixels
+            if ((y > radius) && (y < (height - radius))) {
+                const uint8_t *i = input + ((y - radius) * width);
+                for(int32_t r = -radius; r <= radius; r ++) {
+                    currentPixel = (float)(*i);
+                    blurredPixel += currentPixel * gPtr[0];
+                    gPtr++;
+                    i += width;
+                }
+            } else {
+                for(int32_t r = -radius; r <= radius; r ++) {
+                    int validH = y + r;
+                    // Clamp to zero and width
+                    if(validH < 0) {
+                        validH = 0;
+                    }
+                    if(validH > height - 1) {
+                        validH = height - 1;
+                    }
+
+                    const uint8_t *i = input + validH * width;
+                    currentPixel = (float)(*i);
+                    blurredPixel += currentPixel * gPtr[0];
+                    gPtr++;
+                }
+            }
+            *output = (uint8_t)blurredPixel;
+            output ++;
+        }
+    }
+}
+
+
+void FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) {
+    float *gaussian = new float[2 * radius + 1];
+    computeGaussianWeights(gaussian, radius);
+    uint8_t* scratch = new uint8_t[width * height];
+    horizontalBlur(gaussian, radius, image, scratch, width, height);
+    verticalBlur(gaussian, radius, scratch, image, width, height);
+    delete[] gaussian;
+    delete[] scratch;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 2f7a8ba..4cd902e 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -47,7 +47,8 @@
      * Renders the specified string of text.
      */
     void renderUTF(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
-            int numGlyphs, int x, int y);
+                     int numGlyphs, int x, int y,
+                     uint8_t *bitmap = NULL, uint32_t bitmapW = 0, uint32_t bitmapH = 0);
     /**
      * Creates a new font associated with the specified font state.
      */
@@ -60,7 +61,10 @@
         // Has the cache been invalidated?
         bool mIsValid;
         // Location of the cached glyph in the bitmap
-        // in case we need to resize the texture
+        // in case we need to resize the texture or
+        // render to bitmap
+        uint32_t mStartX;
+        uint32_t mStartY;
         uint32_t mBitmapWidth;
         uint32_t mBitmapHeight;
         // Also cache texture coords for the quad
@@ -73,8 +77,8 @@
         uint32_t mAdvanceX;
         uint32_t mAdvanceY;
         // Values below contain a glyph's origin in the bitmap
-        uint32_t mBitmapLeft;
-        uint32_t mBitmapTop;
+        int32_t mBitmapLeft;
+        int32_t mBitmapTop;
     };
 
     Font(FontRenderer* state, uint32_t fontId, float fontSize);
@@ -86,6 +90,8 @@
     CachedGlyphInfo* cacheGlyph(SkPaint* paint, int32_t glyph);
     void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo *glyph);
     void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y);
+    void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
+                          uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH);
 
     CachedGlyphInfo* getCachedUTFChar(SkPaint* paint, int32_t utfChar);
 
@@ -181,7 +187,10 @@
     Vector<Font*> mActiveFonts;
 
     // Texture to cache glyph bitmaps
-    unsigned char* mTextTexture;
+    uint8_t* mTextTexture;
+    const uint8_t* getTextTextureData() const {
+        return mTextTexture;
+    }
     GLuint mTextureId;
     void checkTextureUpdate();
     bool mUploadTexture;
@@ -196,6 +205,13 @@
     const Rect* mClip;
 
     bool mInitialized;
+
+    void computeGaussianWeights(float* weights, int32_t radius);
+    void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
+                         int32_t width, int32_t height);
+    void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
+                         int32_t width, int32_t height);
+    void blurImage(uint8_t* image, int32_t width, int32_t height, int32_t radius);
 };
 
 }; // namespace uirenderer