Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "OpenGLRenderer"
     18 
     19 #include <SkUtils.h>
     20 
     21 #include <cutils/properties.h>
     22 
     23 #include <utils/Log.h>
     24 
     25 #include "Debug.h"
     26 #include "FontRenderer.h"
     27 
     28 namespace android {
     29 namespace uirenderer {
     30 
     31 ///////////////////////////////////////////////////////////////////////////////
     32 // Defines
     33 ///////////////////////////////////////////////////////////////////////////////
     34 
     35 #define DEFAULT_TEXT_CACHE_WIDTH 1024
     36 #define DEFAULT_TEXT_CACHE_HEIGHT 256
     37 
     38 // We should query these values from the GL context
     39 #define MAX_TEXT_CACHE_WIDTH 2048
     40 #define MAX_TEXT_CACHE_HEIGHT 2048
     41 
     42 ///////////////////////////////////////////////////////////////////////////////
     43 // Font
     44 ///////////////////////////////////////////////////////////////////////////////
     45 
     46 Font::Font(FontRenderer* state, uint32_t fontId, float fontSize,
     47         int flags, uint32_t italicStyle, uint32_t scaleX,
     48         SkPaint::Style style, uint32_t strokeWidth) :
     49         mState(state), mFontId(fontId), mFontSize(fontSize),
     50         mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
     51         mStyle(style), mStrokeWidth(mStrokeWidth) {
     52 }
     53 
     54 
     55 Font::~Font() {
     56     for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) {
     57         if (mState->mActiveFonts[ct] == this) {
     58             mState->mActiveFonts.removeAt(ct);
     59             break;
     60         }
     61     }
     62 
     63     for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
     64         delete mCachedGlyphs.valueAt(i);
     65     }
     66 }
     67 
     68 void Font::invalidateTextureCache() {
     69     for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
     70         mCachedGlyphs.valueAt(i)->mIsValid = false;
     71     }
     72 }
     73 
     74 void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds) {
     75     int nPenX = x + glyph->mBitmapLeft;
     76     int nPenY = y + glyph->mBitmapTop;
     77 
     78     int width = (int) glyph->mBitmapWidth;
     79     int height = (int) glyph->mBitmapHeight;
     80 
     81     if (bounds->bottom > nPenY) {
     82         bounds->bottom = nPenY;
     83     }
     84     if (bounds->left > nPenX) {
     85         bounds->left = nPenX;
     86     }
     87     if (bounds->right < nPenX + width) {
     88         bounds->right = nPenX + width;
     89     }
     90     if (bounds->top < nPenY + height) {
     91         bounds->top = nPenY + height;
     92     }
     93 }
     94 
     95 void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) {
     96     int nPenX = x + glyph->mBitmapLeft;
     97     int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
     98 
     99     float u1 = glyph->mBitmapMinU;
    100     float u2 = glyph->mBitmapMaxU;
    101     float v1 = glyph->mBitmapMinV;
    102     float v2 = glyph->mBitmapMaxV;
    103 
    104     int width = (int) glyph->mBitmapWidth;
    105     int height = (int) glyph->mBitmapHeight;
    106 
    107     mState->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
    108             nPenX + width, nPenY, 0, u2, v2,
    109             nPenX + width, nPenY - height, 0, u2, v1,
    110             nPenX, nPenY - height, 0, u1, v1);
    111 }
    112 
    113 void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
    114         uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
    115     int nPenX = x + glyph->mBitmapLeft;
    116     int nPenY = y + glyph->mBitmapTop;
    117 
    118     uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
    119     uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
    120 
    121     uint32_t cacheWidth = mState->getCacheWidth();
    122     const uint8_t* cacheBuffer = mState->getTextTextureData();
    123 
    124     uint32_t cacheX = 0, cacheY = 0;
    125     int32_t bX = 0, bY = 0;
    126     for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
    127         for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
    128             if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
    129                 LOGE("Skipping invalid index");
    130                 continue;
    131             }
    132             uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
    133             bitmap[bY * bitmapW + bX] = tempCol;
    134         }
    135     }
    136 
    137 }
    138 
    139 Font::CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
    140     CachedGlyphInfo* cachedGlyph = NULL;
    141     ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
    142     if (index >= 0) {
    143         cachedGlyph = mCachedGlyphs.valueAt(index);
    144     } else {
    145         cachedGlyph = cacheGlyph(paint, textUnit);
    146     }
    147 
    148     // Is the glyph still in texture cache?
    149     if (!cachedGlyph->mIsValid) {
    150         const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
    151         updateGlyphCache(paint, skiaGlyph, cachedGlyph);
    152     }
    153 
    154     return cachedGlyph;
    155 }
    156 
    157 void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
    158         int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
    159     if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
    160         render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
    161                 bitmapW, bitmapH, NULL);
    162     } else {
    163         render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
    164                 0, 0, NULL);
    165     }
    166 }
    167 
    168 void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
    169         int numGlyphs, Rect *bounds) {
    170     if (bounds == NULL) {
    171         LOGE("No return rectangle provided to measure text");
    172         return;
    173     }
    174     bounds->set(1e6, -1e6, -1e6, 1e6);
    175     render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds);
    176 }
    177 
    178 #define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16)
    179 
    180 void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
    181         int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
    182         uint32_t bitmapW, uint32_t bitmapH,Rect *bounds) {
    183     if (numGlyphs == 0 || text == NULL || len == 0) {
    184         return;
    185     }
    186 
    187     float penX = x;
    188     int penY = y;
    189     int glyphsLeft = 1;
    190     if (numGlyphs > 0) {
    191         glyphsLeft = numGlyphs;
    192     }
    193 
    194     SkFixed prevRsbDelta = 0;
    195     penX += 0.5f;
    196 
    197     text += start;
    198 
    199     while (glyphsLeft > 0) {
    200         glyph_t glyph = GET_GLYPH(text);
    201 
    202         // Reached the end of the string
    203         if (IS_END_OF_STRING(glyph)) {
    204             break;
    205         }
    206 
    207         CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
    208         penX += SkFixedToFloat(SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta));
    209         prevRsbDelta = cachedGlyph->mRsbDelta;
    210 
    211         // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
    212         if (cachedGlyph->mIsValid) {
    213             switch(mode) {
    214             case FRAMEBUFFER:
    215                 drawCachedGlyph(cachedGlyph, (int) floorf(penX), penY);
    216                 break;
    217             case BITMAP:
    218                 drawCachedGlyph(cachedGlyph, (int) floorf(penX), penY, bitmap, bitmapW, bitmapH);
    219                 break;
    220             case MEASURE:
    221                 measureCachedGlyph(cachedGlyph, (int) floorf(penX), penY, bounds);
    222                 break;
    223             }
    224         }
    225 
    226         penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
    227 
    228         // If we were given a specific number of glyphs, decrement
    229         if (numGlyphs > 0) {
    230             glyphsLeft--;
    231         }
    232     }
    233 }
    234 
    235 void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) {
    236     glyph->mAdvanceX = skiaGlyph.fAdvanceX;
    237     glyph->mAdvanceY = skiaGlyph.fAdvanceY;
    238     glyph->mBitmapLeft = skiaGlyph.fLeft;
    239     glyph->mBitmapTop = skiaGlyph.fTop;
    240     glyph->mLsbDelta = skiaGlyph.fLsbDelta;
    241     glyph->mRsbDelta = skiaGlyph.fRsbDelta;
    242 
    243     uint32_t startX = 0;
    244     uint32_t startY = 0;
    245 
    246     // Get the bitmap for the glyph
    247     paint->findImage(skiaGlyph);
    248     glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY);
    249 
    250     if (!glyph->mIsValid) {
    251         return;
    252     }
    253 
    254     uint32_t endX = startX + skiaGlyph.fWidth;
    255     uint32_t endY = startY + skiaGlyph.fHeight;
    256 
    257     glyph->mStartX = startX;
    258     glyph->mStartY = startY;
    259     glyph->mBitmapWidth = skiaGlyph.fWidth;
    260     glyph->mBitmapHeight = skiaGlyph.fHeight;
    261 
    262     uint32_t cacheWidth = mState->getCacheWidth();
    263     uint32_t cacheHeight = mState->getCacheHeight();
    264 
    265     glyph->mBitmapMinU = (float) startX / (float) cacheWidth;
    266     glyph->mBitmapMinV = (float) startY / (float) cacheHeight;
    267     glyph->mBitmapMaxU = (float) endX / (float) cacheWidth;
    268     glyph->mBitmapMaxV = (float) endY / (float) cacheHeight;
    269 
    270     mState->mUploadTexture = true;
    271 }
    272 
    273 Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) {
    274     CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
    275     mCachedGlyphs.add(glyph, newGlyph);
    276 
    277     const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
    278     newGlyph->mGlyphIndex = skiaGlyph.fID;
    279     newGlyph->mIsValid = false;
    280 
    281     updateGlyphCache(paint, skiaGlyph, newGlyph);
    282 
    283     return newGlyph;
    284 }
    285 
    286 Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
    287         int flags, uint32_t italicStyle, uint32_t scaleX,
    288         SkPaint::Style style, uint32_t strokeWidth) {
    289     Vector<Font*> &activeFonts = state->mActiveFonts;
    290 
    291     for (uint32_t i = 0; i < activeFonts.size(); i++) {
    292         Font* font = activeFonts[i];
    293         if (font->mFontId == fontId && font->mFontSize == fontSize &&
    294                 font->mFlags == flags && font->mItalicStyle == italicStyle &&
    295                 font->mScaleX == scaleX && font->mStyle == style &&
    296                 (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
    297             return font;
    298         }
    299     }
    300 
    301     Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
    302             scaleX, style, strokeWidth);
    303     activeFonts.push(newFont);
    304     return newFont;
    305 }
    306 
    307 ///////////////////////////////////////////////////////////////////////////////
    308 // FontRenderer
    309 ///////////////////////////////////////////////////////////////////////////////
    310 
    311 static bool sLogFontRendererCreate = true;
    312 
    313 FontRenderer::FontRenderer() {
    314     if (sLogFontRendererCreate) {
    315         INIT_LOGD("Creating FontRenderer");
    316     }
    317 
    318     mGammaTable = NULL;
    319     mInitialized = false;
    320     mMaxNumberOfQuads = 1024;
    321     mCurrentQuadIndex = 0;
    322     mTextureId = 0;
    323 
    324     mTextMeshPtr = NULL;
    325     mTextTexture = NULL;
    326 
    327     mIndexBufferID = 0;
    328     mPositionAttrSlot = -1;
    329     mTexcoordAttrSlot = -1;
    330 
    331     mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
    332     mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT;
    333 
    334     char property[PROPERTY_VALUE_MAX];
    335     if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) {
    336         if (sLogFontRendererCreate) {
    337             INIT_LOGD("  Setting text cache width to %s pixels", property);
    338         }
    339         mCacheWidth = atoi(property);
    340     } else {
    341         if (sLogFontRendererCreate) {
    342             INIT_LOGD("  Using default text cache width of %i pixels", mCacheWidth);
    343         }
    344     }
    345 
    346     if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) {
    347         if (sLogFontRendererCreate) {
    348             INIT_LOGD("  Setting text cache width to %s pixels", property);
    349         }
    350         mCacheHeight = atoi(property);
    351     } else {
    352         if (sLogFontRendererCreate) {
    353             INIT_LOGD("  Using default text cache height of %i pixels", mCacheHeight);
    354         }
    355     }
    356 
    357     sLogFontRendererCreate = false;
    358 }
    359 
    360 FontRenderer::~FontRenderer() {
    361     for (uint32_t i = 0; i < mCacheLines.size(); i++) {
    362         delete mCacheLines[i];
    363     }
    364     mCacheLines.clear();
    365 
    366     if (mInitialized) {
    367         delete[] mTextMeshPtr;
    368         delete[] mTextTexture;
    369     }
    370 
    371     if (mTextureId) {
    372         glDeleteTextures(1, &mTextureId);
    373     }
    374 
    375     Vector<Font*> fontsToDereference = mActiveFonts;
    376     for (uint32_t i = 0; i < fontsToDereference.size(); i++) {
    377         delete fontsToDereference[i];
    378     }
    379 }
    380 
    381 void FontRenderer::flushAllAndInvalidate() {
    382     if (mCurrentQuadIndex != 0) {
    383         issueDrawCommand();
    384         mCurrentQuadIndex = 0;
    385     }
    386     for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
    387         mActiveFonts[i]->invalidateTextureCache();
    388     }
    389     for (uint32_t i = 0; i < mCacheLines.size(); i++) {
    390         mCacheLines[i]->mCurrentCol = 0;
    391     }
    392 }
    393 
    394 bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
    395     // If the glyph is too tall, don't cache it
    396     if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
    397         if (mCacheHeight < MAX_TEXT_CACHE_HEIGHT) {
    398             // Default cache not large enough for large glyphs - resize cache to
    399             // max size and try again
    400             flushAllAndInvalidate();
    401             initTextTexture(true);
    402         }
    403         if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
    404             LOGE("Font size to large to fit in cache. width, height = %i, %i",
    405                     (int) glyph.fWidth, (int) glyph.fHeight);
    406             return false;
    407         }
    408     }
    409 
    410     // Now copy the bitmap into the cache texture
    411     uint32_t startX = 0;
    412     uint32_t startY = 0;
    413 
    414     bool bitmapFit = false;
    415     for (uint32_t i = 0; i < mCacheLines.size(); i++) {
    416         bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
    417         if (bitmapFit) {
    418             break;
    419         }
    420     }
    421 
    422     // If the new glyph didn't fit, flush the state so far and invalidate everything
    423     if (!bitmapFit) {
    424         flushAllAndInvalidate();
    425 
    426         // Try to fit it again
    427         for (uint32_t i = 0; i < mCacheLines.size(); i++) {
    428             bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
    429             if (bitmapFit) {
    430                 break;
    431             }
    432         }
    433 
    434         // if we still don't fit, something is wrong and we shouldn't draw
    435         if (!bitmapFit) {
    436             LOGE("Bitmap doesn't fit in cache. width, height = %i, %i",
    437                     (int) glyph.fWidth, (int) glyph.fHeight);
    438             return false;
    439         }
    440     }
    441 
    442     *retOriginX = startX;
    443     *retOriginY = startY;
    444 
    445     uint32_t endX = startX + glyph.fWidth;
    446     uint32_t endY = startY + glyph.fHeight;
    447 
    448     uint32_t cacheWidth = mCacheWidth;
    449 
    450     uint8_t* cacheBuffer = mTextTexture;
    451     uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
    452     unsigned int stride = glyph.rowBytes();
    453 
    454     uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
    455     for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
    456         for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
    457             uint8_t tempCol = bitmapBuffer[bY * stride + bX];
    458             cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
    459         }
    460     }
    461 
    462     return true;
    463 }
    464 
    465 void FontRenderer::initTextTexture(bool largeFonts) {
    466     mCacheLines.clear();
    467     if (largeFonts) {
    468         mCacheWidth = MAX_TEXT_CACHE_WIDTH;
    469         mCacheHeight = MAX_TEXT_CACHE_HEIGHT;
    470     }
    471 
    472     mTextTexture = new uint8_t[mCacheWidth * mCacheHeight];
    473     memset(mTextTexture, 0, mCacheWidth * mCacheHeight * sizeof(uint8_t));
    474 
    475     mUploadTexture = false;
    476 
    477     if (mTextureId != 0) {
    478         glDeleteTextures(1, &mTextureId);
    479     }
    480     glGenTextures(1, &mTextureId);
    481     glBindTexture(GL_TEXTURE_2D, mTextureId);
    482     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    483     // Initialize texture dimensions
    484     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0,
    485             GL_ALPHA, GL_UNSIGNED_BYTE, 0);
    486 
    487     mLinearFiltering = false;
    488     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    489     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    490 
    491     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    492     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    493 
    494     // Split up our cache texture into lines of certain widths
    495     int nextLine = 0;
    496     mCacheLines.push(new CacheTextureLine(mCacheWidth, 18, nextLine, 0));
    497     nextLine += mCacheLines.top()->mMaxHeight;
    498     mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0));
    499     nextLine += mCacheLines.top()->mMaxHeight;
    500     mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0));
    501     nextLine += mCacheLines.top()->mMaxHeight;
    502     mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0));
    503     nextLine += mCacheLines.top()->mMaxHeight;
    504     mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0));
    505     nextLine += mCacheLines.top()->mMaxHeight;
    506     mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0));
    507     nextLine += mCacheLines.top()->mMaxHeight;
    508     if (largeFonts) {
    509         int nextSize = 76;
    510         // Make several new lines with increasing font sizes
    511         while (nextSize < (int)(mCacheHeight - nextLine - (2 * nextSize))) {
    512             mCacheLines.push(new CacheTextureLine(mCacheWidth, nextSize, nextLine, 0));
    513             nextLine += mCacheLines.top()->mMaxHeight;
    514             nextSize += 50;
    515         }
    516     }
    517     mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0));
    518 }
    519 
    520 // Avoid having to reallocate memory and render quad by quad
    521 void FontRenderer::initVertexArrayBuffers() {
    522     uint32_t numIndicies = mMaxNumberOfQuads * 6;
    523     uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t);
    524     uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
    525 
    526     // Four verts, two triangles , six indices per quad
    527     for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) {
    528         int i6 = i * 6;
    529         int i4 = i * 4;
    530 
    531         indexBufferData[i6 + 0] = i4 + 0;
    532         indexBufferData[i6 + 1] = i4 + 1;
    533         indexBufferData[i6 + 2] = i4 + 2;
    534 
    535         indexBufferData[i6 + 3] = i4 + 0;
    536         indexBufferData[i6 + 4] = i4 + 2;
    537         indexBufferData[i6 + 5] = i4 + 3;
    538     }
    539 
    540     glGenBuffers(1, &mIndexBufferID);
    541     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
    542     glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW);
    543     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    544 
    545     free(indexBufferData);
    546 
    547     uint32_t coordSize = 3;
    548     uint32_t uvSize = 2;
    549     uint32_t vertsPerQuad = 4;
    550     uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize;
    551     mTextMeshPtr = new float[vertexBufferSize];
    552 }
    553 
    554 // We don't want to allocate anything unless we actually draw text
    555 void FontRenderer::checkInit() {
    556     if (mInitialized) {
    557         return;
    558     }
    559 
    560     initTextTexture();
    561     initVertexArrayBuffers();
    562 
    563     // We store a string with letters in a rough frequency of occurrence
    564     mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq ");
    565     mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ");
    566     mLatinPrecache += String16(",.?!()-+@;:`'");
    567     mLatinPrecache += String16("0123456789");
    568 
    569     mInitialized = true;
    570 }
    571 
    572 void FontRenderer::checkTextureUpdate() {
    573     if (!mUploadTexture) {
    574         return;
    575     }
    576 
    577     glBindTexture(GL_TEXTURE_2D, mTextureId);
    578 
    579     // Iterate over all the cache lines and see which ones need to be updated
    580     for (uint32_t i = 0; i < mCacheLines.size(); i++) {
    581         CacheTextureLine* cl = mCacheLines[i];
    582         if(cl->mDirty) {
    583             uint32_t xOffset = 0;
    584             uint32_t yOffset = cl->mCurrentRow;
    585             uint32_t width   = mCacheWidth;
    586             uint32_t height  = cl->mMaxHeight;
    587             void* textureData = mTextTexture + yOffset*width;
    588 
    589             glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
    590                     GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
    591 
    592             cl->mDirty = false;
    593         }
    594     }
    595 
    596     mUploadTexture = false;
    597 }
    598 
    599 void FontRenderer::issueDrawCommand() {
    600     checkTextureUpdate();
    601 
    602     float* vtx = mTextMeshPtr;
    603     float* tex = vtx + 3;
    604 
    605     glVertexAttribPointer(mPositionAttrSlot, 3, GL_FLOAT, false, 20, vtx);
    606     glVertexAttribPointer(mTexcoordAttrSlot, 2, GL_FLOAT, false, 20, tex);
    607 
    608     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
    609     glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
    610 
    611     mDrawn = true;
    612 }
    613 
    614 void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2,
    615         float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3,
    616         float x4, float y4, float z4, float u4, float v4) {
    617     if (mClip &&
    618             (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
    619         return;
    620     }
    621 
    622     const uint32_t vertsPerQuad = 4;
    623     const uint32_t floatsPerVert = 5;
    624     float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
    625 
    626     (*currentPos++) = x1;
    627     (*currentPos++) = y1;
    628     (*currentPos++) = z1;
    629     (*currentPos++) = u1;
    630     (*currentPos++) = v1;
    631 
    632     (*currentPos++) = x2;
    633     (*currentPos++) = y2;
    634     (*currentPos++) = z2;
    635     (*currentPos++) = u2;
    636     (*currentPos++) = v2;
    637 
    638     (*currentPos++) = x3;
    639     (*currentPos++) = y3;
    640     (*currentPos++) = z3;
    641     (*currentPos++) = u3;
    642     (*currentPos++) = v3;
    643 
    644     (*currentPos++) = x4;
    645     (*currentPos++) = y4;
    646     (*currentPos++) = z4;
    647     (*currentPos++) = u4;
    648     (*currentPos++) = v4;
    649 
    650     mCurrentQuadIndex++;
    651 
    652     if (mBounds) {
    653         mBounds->left = fmin(mBounds->left, x1);
    654         mBounds->top = fmin(mBounds->top, y3);
    655         mBounds->right = fmax(mBounds->right, x3);
    656         mBounds->bottom = fmax(mBounds->bottom, y1);
    657     }
    658 
    659     if (mCurrentQuadIndex == mMaxNumberOfQuads) {
    660         issueDrawCommand();
    661         mCurrentQuadIndex = 0;
    662     }
    663 }
    664 
    665 uint32_t FontRenderer::getRemainingCacheCapacity() {
    666     uint32_t remainingCapacity = 0;
    667     float totalPixels = 0;
    668     for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
    669          remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
    670          totalPixels += mCacheLines[i]->mMaxWidth;
    671     }
    672     remainingCapacity = (remainingCapacity * 100) / totalPixels;
    673     return remainingCapacity;
    674 }
    675 
    676 void FontRenderer::precacheLatin(SkPaint* paint) {
    677     // Remaining capacity is measured in %
    678     uint32_t remainingCapacity = getRemainingCacheCapacity();
    679     uint32_t precacheIdx = 0;
    680     while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
    681         mCurrentFont->getCachedGlyph(paint, (int32_t) mLatinPrecache[precacheIdx]);
    682         remainingCapacity = getRemainingCacheCapacity();
    683         precacheIdx ++;
    684     }
    685 }
    686 
    687 void FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) {
    688     uint32_t currentNumFonts = mActiveFonts.size();
    689     int flags = 0;
    690     if (paint->isFakeBoldText()) {
    691         flags |= Font::kFakeBold;
    692     }
    693 
    694     const float skewX = paint->getTextSkewX();
    695     uint32_t italicStyle = *(uint32_t*) &skewX;
    696     const float scaleXFloat = paint->getTextScaleX();
    697     uint32_t scaleX = *(uint32_t*) &scaleXFloat;
    698     SkPaint::Style style = paint->getStyle();
    699     const float strokeWidthFloat = paint->getStrokeWidth();
    700     uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
    701     mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle,
    702             scaleX, style, strokeWidth);
    703 
    704     const float maxPrecacheFontSize = 40.0f;
    705     bool isNewFont = currentNumFonts != mActiveFonts.size();
    706 
    707     if (isNewFont && fontSize <= maxPrecacheFontSize) {
    708         precacheLatin(paint);
    709     }
    710 }
    711 
    712 FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
    713         uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) {
    714     checkInit();
    715 
    716     if (!mCurrentFont) {
    717         DropShadow image;
    718         image.width = 0;
    719         image.height = 0;
    720         image.image = NULL;
    721         image.penX = 0;
    722         image.penY = 0;
    723         return image;
    724     }
    725 
    726     mClip = NULL;
    727     mBounds = NULL;
    728 
    729     Rect bounds;
    730     mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds);
    731 
    732     uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
    733     uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
    734     uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight];
    735 
    736     for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) {
    737         dataBuffer[i] = 0;
    738     }
    739 
    740     int penX = radius - bounds.left;
    741     int penY = radius - bounds.bottom;
    742 
    743     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
    744             dataBuffer, paddedWidth, paddedHeight);
    745     blurImage(dataBuffer, paddedWidth, paddedHeight, radius);
    746 
    747     DropShadow image;
    748     image.width = paddedWidth;
    749     image.height = paddedHeight;
    750     image.image = dataBuffer;
    751     image.penX = penX;
    752     image.penY = penY;
    753     return image;
    754 }
    755 
    756 bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
    757         uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) {
    758     checkInit();
    759 
    760     if (!mCurrentFont) {
    761         LOGE("No font set");
    762         return false;
    763     }
    764 
    765     if (mPositionAttrSlot < 0 || mTexcoordAttrSlot < 0) {
    766         LOGE("Font renderer unable to draw, attribute slots undefined");
    767         return false;
    768     }
    769 
    770     mDrawn = false;
    771     mBounds = bounds;
    772     mClip = clip;
    773 
    774     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y);
    775 
    776     mBounds = NULL;
    777     mClip = NULL;
    778 
    779     if (mCurrentQuadIndex != 0) {
    780         issueDrawCommand();
    781         mCurrentQuadIndex = 0;
    782     }
    783 
    784     return mDrawn;
    785 }
    786 
    787 void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
    788     // Compute gaussian weights for the blur
    789     // e is the euler's number
    790     float e = 2.718281828459045f;
    791     float pi = 3.1415926535897932f;
    792     // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
    793     // x is of the form [-radius .. 0 .. radius]
    794     // and sigma varies with radius.
    795     // Based on some experimental radius values and sigma's
    796     // we approximately fit sigma = f(radius) as
    797     // sigma = radius * 0.3  + 0.6
    798     // The larger the radius gets, the more our gaussian blur
    799     // will resemble a box blur since with large sigma
    800     // the gaussian curve begins to lose its shape
    801     float sigma = 0.3f * (float) radius + 0.6f;
    802 
    803     // Now compute the coefficints
    804     // We will store some redundant values to save some math during
    805     // the blur calculations
    806     // precompute some values
    807     float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
    808     float coeff2 = - 1.0f / (2.0f * sigma * sigma);
    809 
    810     float normalizeFactor = 0.0f;
    811     for (int32_t r = -radius; r <= radius; r ++) {
    812         float floatR = (float) r;
    813         weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
    814         normalizeFactor += weights[r + radius];
    815     }
    816 
    817     //Now we need to normalize the weights because all our coefficients need to add up to one
    818     normalizeFactor = 1.0f / normalizeFactor;
    819     for (int32_t r = -radius; r <= radius; r ++) {
    820         weights[r + radius] *= normalizeFactor;
    821     }
    822 }
    823 
    824 void FontRenderer::horizontalBlur(float* weights, int32_t radius,
    825         const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
    826     float blurredPixel = 0.0f;
    827     float currentPixel = 0.0f;
    828 
    829     for (int32_t y = 0; y < height; y ++) {
    830 
    831         const uint8_t* input = source + y * width;
    832         uint8_t* output = dest + y * width;
    833 
    834         for (int32_t x = 0; x < width; x ++) {
    835             blurredPixel = 0.0f;
    836             const float* gPtr = weights;
    837             // Optimization for non-border pixels
    838             if (x > radius && x < (width - radius)) {
    839                 const uint8_t *i = input + (x - radius);
    840                 for (int r = -radius; r <= radius; r ++) {
    841                     currentPixel = (float) (*i);
    842                     blurredPixel += currentPixel * gPtr[0];
    843                     gPtr++;
    844                     i++;
    845                 }
    846             } else {
    847                 for (int32_t r = -radius; r <= radius; r ++) {
    848                     // Stepping left and right away from the pixel
    849                     int validW = x + r;
    850                     if (validW < 0) {
    851                         validW = 0;
    852                     }
    853                     if (validW > width - 1) {
    854                         validW = width - 1;
    855                     }
    856 
    857                     currentPixel = (float) input[validW];
    858                     blurredPixel += currentPixel * gPtr[0];
    859                     gPtr++;
    860                 }
    861             }
    862             *output = (uint8_t)blurredPixel;
    863             output ++;
    864         }
    865     }
    866 }
    867 
    868 void FontRenderer::verticalBlur(float* weights, int32_t radius,
    869         const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
    870     float blurredPixel = 0.0f;
    871     float currentPixel = 0.0f;
    872 
    873     for (int32_t y = 0; y < height; y ++) {
    874 
    875         uint8_t* output = dest + y * width;
    876 
    877         for (int32_t x = 0; x < width; x ++) {
    878             blurredPixel = 0.0f;
    879             const float* gPtr = weights;
    880             const uint8_t* input = source + x;
    881             // Optimization for non-border pixels
    882             if (y > radius && y < (height - radius)) {
    883                 const uint8_t *i = input + ((y - radius) * width);
    884                 for (int32_t r = -radius; r <= radius; r ++) {
    885                     currentPixel = (float)(*i);
    886                     blurredPixel += currentPixel * gPtr[0];
    887                     gPtr++;
    888                     i += width;
    889                 }
    890             } else {
    891                 for (int32_t r = -radius; r <= radius; r ++) {
    892                     int validH = y + r;
    893                     // Clamp to zero and width
    894                     if (validH < 0) {
    895                         validH = 0;
    896                     }
    897                     if (validH > height - 1) {
    898                         validH = height - 1;
    899                     }
    900 
    901                     const uint8_t *i = input + validH * width;
    902                     currentPixel = (float) (*i);
    903                     blurredPixel += currentPixel * gPtr[0];
    904                     gPtr++;
    905                 }
    906             }
    907             *output = (uint8_t) blurredPixel;
    908             output ++;
    909         }
    910     }
    911 }
    912 
    913 
    914 void FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) {
    915     float *gaussian = new float[2 * radius + 1];
    916     computeGaussianWeights(gaussian, radius);
    917     uint8_t* scratch = new uint8_t[width * height];
    918     horizontalBlur(gaussian, radius, image, scratch, width, height);
    919     verticalBlur(gaussian, radius, scratch, image, width, height);
    920     delete[] gaussian;
    921     delete[] scratch;
    922 }
    923 
    924 }; // namespace uirenderer
    925 }; // namespace android
    926