Loading libs/hwui/FontRenderer.cpp +185 −8 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; } Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -234,9 +272,9 @@ FontRenderer::~FontRenderer() { } mCacheLines.clear(); delete mTextMeshPtr; delete[] mTextMeshPtr; delete[] mTextTexture; delete mTextTexture; if(mTextureId) { glDeleteTextures(1, &mTextureId); } Loading Loading @@ -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; } } Loading @@ -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); Loading Loading @@ -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 libs/hwui/FontRenderer.h +21 −5 Original line number Diff line number Diff line Loading @@ -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. */ Loading @@ -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 Loading @@ -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); Loading @@ -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); Loading Loading @@ -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; Loading @@ -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 Loading Loading
libs/hwui/FontRenderer.cpp +185 −8 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; } Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -234,9 +272,9 @@ FontRenderer::~FontRenderer() { } mCacheLines.clear(); delete mTextMeshPtr; delete[] mTextMeshPtr; delete[] mTextTexture; delete mTextTexture; if(mTextureId) { glDeleteTextures(1, &mTextureId); } Loading Loading @@ -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; } } Loading @@ -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); Loading Loading @@ -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
libs/hwui/FontRenderer.h +21 −5 Original line number Diff line number Diff line Loading @@ -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. */ Loading @@ -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 Loading @@ -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); Loading @@ -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); Loading Loading @@ -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; Loading @@ -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 Loading