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 
    169 void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
    170         int numGlyphs, Rect *bounds) {
    171     if (bounds == NULL) {
    172         LOGE("No return rectangle provided to measure text");
    173         return;
    174     }
    175     bounds->set(1e6, -1e6, -1e6, 1e6);
    176     render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds);
    177 }
    178 
    179 #define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16)
    180 
    181 void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
    182         int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
    183         uint32_t bitmapW, uint32_t bitmapH,Rect *bounds) {
    184     if (numGlyphs == 0 || text == NULL || len == 0) {
    185         return;
    186     }
    187 
    188     float penX = x;
    189     int penY = y;
    190     int glyphsLeft = 1;
    191     if (numGlyphs > 0) {
    192         glyphsLeft = numGlyphs;
    193     }
    194 
    195     SkFixed prevRsbDelta = 0;
    196     penX += 0.5f;
    197 
    198     text += start;
    199 
    200     while (glyphsLeft > 0) {
    201         glyph_t glyph = GET_GLYPH(text);
    202 
    203         // Reached the end of the string
    204         if (IS_END_OF_STRING(glyph)) {
    205             break;
    206         }
    207 
    208         CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
    209         penX += SkFixedToFloat(SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta));
    210         prevRsbDelta = cachedGlyph->mRsbDelta;
    211 
    212         // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
    213         if (cachedGlyph->mIsValid) {
    214             switch(mode) {
    215             case FRAMEBUFFER:
    216                 drawCachedGlyph(cachedGlyph, (int) floorf(penX), penY);
    217                 break;
    218             case BITMAP:
    219                 drawCachedGlyph(cachedGlyph, (int) floorf(penX), penY, bitmap, bitmapW, bitmapH);
    220                 break;
    221             case MEASURE:
    222                 measureCachedGlyph(cachedGlyph, (int) floorf(penX), penY, bounds);
    223                 break;
    224             }
    225         }
    226 
    227         penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
    228 
    229         // If we were given a specific number of glyphs, decrement
    230         if (numGlyphs > 0) {
    231             glyphsLeft--;
    232         }
    233     }
    234 }
    235 
    236 void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) {
    237     glyph->mAdvanceX = skiaGlyph.fAdvanceX;
    238     glyph->mAdvanceY = skiaGlyph.fAdvanceY;
    239     glyph->mBitmapLeft = skiaGlyph.fLeft;
    240     glyph->mBitmapTop = skiaGlyph.fTop;
    241     glyph->mLsbDelta = skiaGlyph.fLsbDelta;
    242     glyph->mRsbDelta = skiaGlyph.fRsbDelta;
    243 
    244     uint32_t startX = 0;
    245     uint32_t startY = 0;
    246 
    247     // Get the bitmap for the glyph
    248     paint->findImage(skiaGlyph);
    249     glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY);
    250 
    251     if (!glyph->mIsValid) {
    252         return;
    253     }
    254 
    255     uint32_t endX = startX + skiaGlyph.fWidth;
    256     uint32_t endY = startY + skiaGlyph.fHeight;
    257 
    258     glyph->mStartX = startX;
    259     glyph->mStartY = startY;
    260     glyph->mBitmapWidth = skiaGlyph.fWidth;
    261     glyph->mBitmapHeight = skiaGlyph.fHeight;
    262 
    263     uint32_t cacheWidth = mState->getCacheWidth();
    264     uint32_t cacheHeight = mState->getCacheHeight();
    265 
    266     glyph->mBitmapMinU = (float) startX / (float) cacheWidth;
    267     glyph->mBitmapMinV = (float) startY / (float) cacheHeight;
    268     glyph->mBitmapMaxU = (float) endX / (float) cacheWidth;
    269     glyph->mBitmapMaxV = (float) endY / (float) cacheHeight;
    270 
    271     mState->mUploadTexture = true;
    272 }
    273 
    274 Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) {
    275     CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
    276     mCachedGlyphs.add(glyph, newGlyph);
    277 
    278     const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
    279     newGlyph->mGlyphIndex = skiaGlyph.fID;
    280     newGlyph->mIsValid = false;
    281 
    282     updateGlyphCache(paint, skiaGlyph, newGlyph);
    283 
    284     return newGlyph;
    285 }
    286 
    287 Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
    288         int flags, uint32_t italicStyle, uint32_t scaleX,
    289         SkPaint::Style style, uint32_t strokeWidth) {
    290     Vector<Font*> &activeFonts = state->mActiveFonts;
    291 
    292     for (uint32_t i = 0; i < activeFonts.size(); i++) {
    293         Font* font = activeFonts[i];
    294         if (font->mFontId == fontId && font->mFontSize == fontSize &&
    295                 font->mFlags == flags && font->mItalicStyle == italicStyle &&
    296                 font->mScaleX == scaleX && font->mStyle == style &&
    297                 (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
    298             return font;
    299         }
    300     }
    301 
    302     Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
    303             scaleX, style, strokeWidth);
    304     activeFonts.push(newFont);
    305     return newFont;
    306 }
    307 
    308 ///////////////////////////////////////////////////////////////////////////////
    309 // FontRenderer
    310 ///////////////////////////////////////////////////////////////////////////////
    311 
    312 static bool sLogFontRendererCreate = true;
    313 
    314 FontRenderer::FontRenderer() {
    315     if (sLogFontRendererCreate) {
    316         INIT_LOGD("Creating FontRenderer");
    317     }
    318 
    319     mGammaTable = NULL;
    320     mInitialized = false;
    321     mMaxNumberOfQuads = 1024;
    322     mCurrentQuadIndex = 0;
    323     mTextureId = 0;
    324 
    325     mTextMeshPtr = NULL;
    326     mTextTexture = NULL;
    327 
    328     mIndexBufferID = 0;
    329     mPositionAttrSlot = -1;
    330     mTexcoordAttrSlot = -1;
    331 
    332     mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
    333     mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT;
    334 
    335     char property[PROPERTY_VALUE_MAX];
    336     if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) {
    337         if (sLogFontRendererCreate) {
    338             INIT_LOGD("  Setting text cache width to %s pixels", property);
    339         }
    340         mCacheWidth = atoi(property);
    341     } else {
    342         if (sLogFontRendererCreate) {
    343             INIT_LOGD("  Using default text cache width of %i pixels", mCacheWidth);
    344         }
    345     }
    346 
    347     if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) {
    348         if (sLogFontRendererCreate) {
    349             INIT_LOGD("  Setting text cache width to %s pixels", property);
    350         }
    351         mCacheHeight = atoi(property);
    352     } else {
    353         if (sLogFontRendererCreate) {
    354             INIT_LOGD("  Using default text cache height of %i pixels", mCacheHeight);
    355         }
    356     }
    357 
    358     sLogFontRendererCreate = false;
    359 }
    360 
    361 FontRenderer::~FontRenderer() {
    362     for (uint32_t i = 0; i < mCacheLines.size(); i++) {
    363         delete mCacheLines[i];
    364     }
    365     mCacheLines.clear();
    366 
    367     if (mInitialized) {
    368         delete[] mTextMeshPtr;
    369         delete[] mTextTexture;
    370     }
    371 
    372     if (mTextureId) {
    373         glDeleteTextures(1, &mTextureId);
    374     }
    375 
    376     Vector<Font*> fontsToDereference = mActiveFonts;
    377     for (uint32_t i = 0; i < fontsToDereference.size(); i++) {
    378         delete fontsToDereference[i];
    379     }
    380 }
    381 
    382 void FontRenderer::flushAllAndInvalidate() {
    383     if (mCurrentQuadIndex != 0) {
    384         issueDrawCommand();
    385         mCurrentQuadIndex = 0;
    386     }
    387     for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
    388         mActiveFonts[i]->invalidateTextureCache();
    389     }
    390     for (uint32_t i = 0; i < mCacheLines.size(); i++) {
    391         mCacheLines[i]->mCurrentCol = 0;
    392     }
    393 }
    394 
    395 bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
    396     // If the glyph is too tall, don't cache it
    397     if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
    398         if (mCacheHeight < MAX_TEXT_CACHE_HEIGHT) {
    399             // Default cache not large enough for large glyphs - resize cache to
    400             // max size and try again
    401             flushAllAndInvalidate();
    402             initTextTexture(true);
    403         }
    404         if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
    405             LOGE("Font size to large to fit in cache. width, height = %i, %i",
    406                     (int) glyph.fWidth, (int) glyph.fHeight);
    407             return false;
    408         }
    409     }
    410 
    411     // Now copy the bitmap into the cache texture
    412     uint32_t startX = 0;
    413     uint32_t startY = 0;
    414 
    415     bool bitmapFit = false;
    416     for (uint32_t i = 0; i < mCacheLines.size(); i++) {
    417         bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
    418         if (bitmapFit) {
    419             break;
    420         }
    421     }
    422 
    423     // If the new glyph didn't fit, flush the state so far and invalidate everything
    424     if (!bitmapFit) {
    425         flushAllAndInvalidate();
    426 
    427         // Try to fit it again
    428         for (uint32_t i = 0; i < mCacheLines.size(); i++) {
    429             bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
    430             if (bitmapFit) {
    431                 break;
    432             }
    433         }
    434 
    435         // if we still don't fit, something is wrong and we shouldn't draw
    436         if (!bitmapFit) {
    437             LOGE("Bitmap doesn't fit in cache. width, height = %i, %i",
    438                     (int) glyph.fWidth, (int) glyph.fHeight);
    439             return false;
    440         }
    441     }
    442 
    443     *retOriginX = startX;
    444     *retOriginY = startY;
    445 
    446     uint32_t endX = startX + glyph.fWidth;
    447     uint32_t endY = startY + glyph.fHeight;
    448 
    449     uint32_t cacheWidth = mCacheWidth;
    450 
    451     uint8_t* cacheBuffer = mTextTexture;
    452     uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
    453     unsigned int stride = glyph.rowBytes();
    454 
    455     uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
    456     for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
    457         for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
    458             uint8_t tempCol = bitmapBuffer[bY * stride + bX];
    459             cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
    460         }
    461     }
    462 
    463     return true;
    464 }
    465 
    466 void FontRenderer::initTextTexture(bool largeFonts) {
    467     mCacheLines.clear();
    468     if (largeFonts) {
    469         mCacheWidth = MAX_TEXT_CACHE_WIDTH;
    470         mCacheHeight = MAX_TEXT_CACHE_HEIGHT;
    471     }
    472 
    473     mTextTexture = new uint8_t[mCacheWidth * mCacheHeight];
    474     memset(mTextTexture, 0, mCacheWidth * mCacheHeight * sizeof(uint8_t));
    475 
    476     mUploadTexture = false;
    477 
    478     if (mTextureId != 0) {
    479         glDeleteTextures(1, &mTextureId);
    480     }
    481     glGenTextures(1, &mTextureId);
    482     glBindTexture(GL_TEXTURE_2D, mTextureId);
    483     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    484     // Initialize texture dimensions
    485     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0,
    486             GL_ALPHA, GL_UNSIGNED_BYTE, 0);
    487 
    488     mLinearFiltering = false;
    489     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    490     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    491 
    492     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    493     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    494 
    495     // Split up our cache texture into lines of certain widths
    496     int nextLine = 0;
    497     mCacheLines.push(new CacheTextureLine(mCacheWidth, 18, nextLine, 0));
    498     nextLine += mCacheLines.top()->mMaxHeight;
    499     mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0));
    500     nextLine += mCacheLines.top()->mMaxHeight;
    501     mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0));
    502     nextLine += mCacheLines.top()->mMaxHeight;
    503     mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0));
    504     nextLine += mCacheLines.top()->mMaxHeight;
    505     mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0));
    506     nextLine += mCacheLines.top()->mMaxHeight;
    507     mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0));
    508     nextLine += mCacheLines.top()->mMaxHeight;
    509     if (largeFonts) {
    510         int nextSize = 76;
    511         // Make several new lines with increasing font sizes
    512         while (nextSize < (int)(mCacheHeight - nextLine - (2 * nextSize))) {
    513             mCacheLines.push(new CacheTextureLine(mCacheWidth, nextSize, nextLine, 0));
    514             nextLine += mCacheLines.top()->mMaxHeight;
    515             nextSize += 50;
    516         }
    517     }
    518     mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0));
    519 }
    520 
    521 // Avoid having to reallocate memory and render quad by quad
    522 void FontRenderer::initVertexArrayBuffers() {
    523     uint32_t numIndicies = mMaxNumberOfQuads * 6;
    524     uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t);
    525     uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
    526 
    527     // Four verts, two triangles , six indices per quad
    528     for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) {
    529         int i6 = i * 6;
    530         int i4 = i * 4;
    531 
    532         indexBufferData[i6 + 0] = i4 + 0;
    533         indexBufferData[i6 + 1] = i4 + 1;
    534         indexBufferData[i6 + 2] = i4 + 2;
    535 
    536         indexBufferData[i6 + 3] = i4 + 0;
    537         indexBufferData[i6 + 4] = i4 + 2;
    538         indexBufferData[i6 + 5] = i4 + 3;
    539     }
    540 
    541     glGenBuffers(1, &mIndexBufferID);
    542     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
    543     glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW);
    544     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    545 
    546     free(indexBufferData);
    547 
    548     uint32_t coordSize = 3;
    549     uint32_t uvSize = 2;
    550     uint32_t vertsPerQuad = 4;
    551     uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize;
    552     mTextMeshPtr = new float[vertexBufferSize];
    553 }
    554 
    555 // We don't want to allocate anything unless we actually draw text
    556 void FontRenderer::checkInit() {
    557     if (mInitialized) {
    558         return;
    559     }
    560 
    561     initTextTexture();
    562     initVertexArrayBuffers();
    563 
    564     // We store a string with letters in a rough frequency of occurrence
    565     mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq ");
    566     mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ");
    567     mLatinPrecache += String16(",.?!()-+@;:`'");
    568     mLatinPrecache += String16("0123456789");
    569 
    570     mInitialized = true;
    571 }
    572 
    573 void FontRenderer::checkTextureUpdate() {
    574     if (!mUploadTexture) {
    575         return;
    576     }
    577 
    578     glBindTexture(GL_TEXTURE_2D, mTextureId);
    579 
    580     // Iterate over all the cache lines and see which ones need to be updated
    581     for (uint32_t i = 0; i < mCacheLines.size(); i++) {
    582         CacheTextureLine* cl = mCacheLines[i];
    583         if(cl->mDirty) {
    584             uint32_t xOffset = 0;
    585             uint32_t yOffset = cl->mCurrentRow;
    586             uint32_t width   = mCacheWidth;
    587             uint32_t height  = cl->mMaxHeight;
    588             void* textureData = mTextTexture + yOffset*width;
    589 
    590             glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
    591                     GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
    592 
    593             cl->mDirty = false;
    594         }
    595     }
    596 
    597     mUploadTexture = false;
    598 }
    599 
    600 void FontRenderer::issueDrawCommand() {
    601     checkTextureUpdate();
    602 
    603     float* vtx = mTextMeshPtr;
    604     float* tex = vtx + 3;
    605 
    606     glVertexAttribPointer(mPositionAttrSlot, 3, GL_FLOAT, false, 20, vtx);
    607     glVertexAttribPointer(mTexcoordAttrSlot, 2, GL_FLOAT, false, 20, tex);
    608 
    609     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
    610     glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
    611 
    612     mDrawn = true;
    613 }
    614 
    615 void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2,
    616         float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3,
    617         float x4, float y4, float z4, float u4, float v4) {
    618     if (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     Rect bounds;
    727     mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds);
    728     uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
    729     uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
    730     uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight];
    731     for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) {
    732         dataBuffer[i] = 0;
    733     }
    734 
    735     int penX = radius - bounds.left;
    736     int penY = radius - bounds.bottom;
    737 
    738     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
    739             dataBuffer, paddedWidth, paddedHeight);
    740     blurImage(dataBuffer, paddedWidth, paddedHeight, radius);
    741 
    742     DropShadow image;
    743     image.width = paddedWidth;
    744     image.height = paddedHeight;
    745     image.image = dataBuffer;
    746     image.penX = penX;
    747     image.penY = penY;
    748     return image;
    749 }
    750 
    751 bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
    752         uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) {
    753     checkInit();
    754 
    755     if (!mCurrentFont) {
    756         LOGE("No font set");
    757         return false;
    758     }
    759 
    760     if (mPositionAttrSlot < 0 || mTexcoordAttrSlot < 0) {
    761         LOGE("Font renderer unable to draw, attribute slots undefined");
    762         return false;
    763     }
    764 
    765     mDrawn = false;
    766     mBounds = bounds;
    767     mClip = clip;
    768     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y);
    769     mBounds = NULL;
    770 
    771     if (mCurrentQuadIndex != 0) {
    772         issueDrawCommand();
    773         mCurrentQuadIndex = 0;
    774     }
    775 
    776     return mDrawn;
    777 }
    778 
    779 void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
    780     // Compute gaussian weights for the blur
    781     // e is the euler's number
    782     float e = 2.718281828459045f;
    783     float pi = 3.1415926535897932f;
    784     // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
    785     // x is of the form [-radius .. 0 .. radius]
    786     // and sigma varies with radius.
    787     // Based on some experimental radius values and sigma's
    788     // we approximately fit sigma = f(radius) as
    789     // sigma = radius * 0.3  + 0.6
    790     // The larger the radius gets, the more our gaussian blur
    791     // will resemble a box blur since with large sigma
    792     // the gaussian curve begins to lose its shape
    793     float sigma = 0.3f * (float) radius + 0.6f;
    794 
    795     // Now compute the coefficints
    796     // We will store some redundant values to save some math during
    797     // the blur calculations
    798     // precompute some values
    799     float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
    800     float coeff2 = - 1.0f / (2.0f * sigma * sigma);
    801 
    802     float normalizeFactor = 0.0f;
    803     for (int32_t r = -radius; r <= radius; r ++) {
    804         float floatR = (float) r;
    805         weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
    806         normalizeFactor += weights[r + radius];
    807     }
    808 
    809     //Now we need to normalize the weights because all our coefficients need to add up to one
    810     normalizeFactor = 1.0f / normalizeFactor;
    811     for (int32_t r = -radius; r <= radius; r ++) {
    812         weights[r + radius] *= normalizeFactor;
    813     }
    814 }
    815 
    816 void FontRenderer::horizontalBlur(float* weights, int32_t radius,
    817         const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
    818     float blurredPixel = 0.0f;
    819     float currentPixel = 0.0f;
    820 
    821     for (int32_t y = 0; y < height; y ++) {
    822 
    823         const uint8_t* input = source + y * width;
    824         uint8_t* output = dest + y * width;
    825 
    826         for (int32_t x = 0; x < width; x ++) {
    827             blurredPixel = 0.0f;
    828             const float* gPtr = weights;
    829             // Optimization for non-border pixels
    830             if (x > radius && x < (width - radius)) {
    831                 const uint8_t *i = input + (x - radius);
    832                 for (int r = -radius; r <= radius; r ++) {
    833                     currentPixel = (float) (*i);
    834                     blurredPixel += currentPixel * gPtr[0];
    835                     gPtr++;
    836                     i++;
    837                 }
    838             } else {
    839                 for (int32_t r = -radius; r <= radius; r ++) {
    840                     // Stepping left and right away from the pixel
    841                     int validW = x + r;
    842                     if (validW < 0) {
    843                         validW = 0;
    844                     }
    845                     if (validW > width - 1) {
    846                         validW = width - 1;
    847                     }
    848 
    849                     currentPixel = (float) input[validW];
    850                     blurredPixel += currentPixel * gPtr[0];
    851                     gPtr++;
    852                 }
    853             }
    854             *output = (uint8_t)blurredPixel;
    855             output ++;
    856         }
    857     }
    858 }
    859 
    860 void FontRenderer::verticalBlur(float* weights, int32_t radius,
    861         const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
    862     float blurredPixel = 0.0f;
    863     float currentPixel = 0.0f;
    864 
    865     for (int32_t y = 0; y < height; y ++) {
    866 
    867         uint8_t* output = dest + y * width;
    868 
    869         for (int32_t x = 0; x < width; x ++) {
    870             blurredPixel = 0.0f;
    871             const float* gPtr = weights;
    872             const uint8_t* input = source + x;
    873             // Optimization for non-border pixels
    874             if (y > radius && y < (height - radius)) {
    875                 const uint8_t *i = input + ((y - radius) * width);
    876                 for (int32_t r = -radius; r <= radius; r ++) {
    877                     currentPixel = (float)(*i);
    878                     blurredPixel += currentPixel * gPtr[0];
    879                     gPtr++;
    880                     i += width;
    881                 }
    882             } else {
    883                 for (int32_t r = -radius; r <= radius; r ++) {
    884                     int validH = y + r;
    885                     // Clamp to zero and width
    886                     if (validH < 0) {
    887                         validH = 0;
    888                     }
    889                     if (validH > height - 1) {
    890                         validH = height - 1;
    891                     }
    892 
    893                     const uint8_t *i = input + validH * width;
    894                     currentPixel = (float) (*i);
    895                     blurredPixel += currentPixel * gPtr[0];
    896                     gPtr++;
    897                 }
    898             }
    899             *output = (uint8_t) blurredPixel;
    900             output ++;
    901         }
    902     }
    903 }
    904 
    905 
    906 void FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) {
    907     float *gaussian = new float[2 * radius + 1];
    908     computeGaussianWeights(gaussian, radius);
    909     uint8_t* scratch = new uint8_t[width * height];
    910     horizontalBlur(gaussian, radius, image, scratch, width, height);
    911     verticalBlur(gaussian, radius, scratch, image, width, height);
    912     delete[] gaussian;
    913     delete[] scratch;
    914 }
    915 
    916 }; // namespace uirenderer
    917 }; // namespace android
    918