Merge "Adding drop shadow support"
This commit is contained in:
committed by
Android (Google) Code Review
commit
a275354c54
@@ -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,7 +152,12 @@ 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) {
|
||||
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 @@ 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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user