Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 89a524ac authored by Alex Sakhartchouk's avatar Alex Sakhartchouk
Browse files

Adding drop shadow support

Change-Id: I9b1b9568d6cebc0761d96ab678b018571f705ae1
parent ae2036a8
Loading
Loading
Loading
Loading
+185 −8
Original line number Diff line number Diff line
@@ -80,6 +80,37 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) {
            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 @@ Font::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) {
}

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,8 +152,13 @@ void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t

        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
        if (cachedGlyph->mIsValid) {
            if(bitmap != NULL) {
                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
            }
            else {
                drawCachedGlyph(cachedGlyph, penX, penY);
            }
        }

        penX += SkFixedFloor(cachedGlyph->mAdvanceX);

@@ -153,6 +189,8 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
    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 @@ FontRenderer::~FontRenderer() {
    }
    mCacheLines.clear();

    delete mTextMeshPtr;
    delete[] mTextMeshPtr;
    delete[] mTextTexture;

    delete mTextTexture;
    if(mTextureId) {
        glDeleteTextures(1, &mTextureId);
    }
@@ -308,14 +346,14 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3

    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 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3
}

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::renderText(SkPaint* paint, const Rect* clip, const char *text
    }
}

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
+21 −5
Original line number Diff line number Diff line
@@ -47,7 +47,8 @@ public:
     * 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 @@ protected:
        // 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 @@ protected:
        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 @@ protected:
    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 @@ protected:
    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 @@ protected:
    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