Home | History | Annotate | Download | only in rs
      1 
      2 /*
      3  * Copyright (C) 2009 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 #include "rsContext.h"
     19 #include "rs.h"
     20 #include "rsFont.h"
     21 #include "rsProgramFragment.h"
     22 #include "rsMesh.h"
     23 #ifdef HAVE_ANDROID_OS
     24 #include <cutils/properties.h>
     25 #endif
     26 
     27 #ifndef ANDROID_RS_SERIALIZE
     28 #include <ft2build.h>
     29 #include FT_FREETYPE_H
     30 #include FT_BITMAP_H
     31 #endif //ANDROID_RS_SERIALIZE
     32 
     33 using namespace android;
     34 using namespace android::renderscript;
     35 
     36 Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
     37     mInitialized = false;
     38     mHasKerning = false;
     39     mFace = NULL;
     40 }
     41 
     42 bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
     43 #ifndef ANDROID_RS_SERIALIZE
     44     if (mInitialized) {
     45         ALOGE("Reinitialization of fonts not supported");
     46         return false;
     47     }
     48 
     49     FT_Error error = 0;
     50     if (data != NULL && dataLen > 0) {
     51         error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
     52     } else {
     53         error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
     54     }
     55 
     56     if (error) {
     57         ALOGE("Unable to initialize font %s", name);
     58         return false;
     59     }
     60 
     61     mFontName = rsuCopyString(name);
     62     mFontSize = fontSize;
     63     mDpi = dpi;
     64 
     65     error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
     66     if (error) {
     67         ALOGE("Unable to set font size on %s", name);
     68         return false;
     69     }
     70 
     71     mHasKerning = FT_HAS_KERNING(mFace);
     72 
     73     mInitialized = true;
     74 #endif //ANDROID_RS_SERIALIZE
     75     return true;
     76 }
     77 
     78 void Font::preDestroy() const {
     79     for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
     80         if (mRSC->mStateFont.mActiveFonts[ct] == this) {
     81             mRSC->mStateFont.mActiveFonts.removeAt(ct);
     82             break;
     83         }
     84     }
     85 }
     86 
     87 void Font::invalidateTextureCache() {
     88     for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
     89         mCachedGlyphs.valueAt(i)->mIsValid = false;
     90     }
     91 }
     92 
     93 void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
     94     FontState *state = &mRSC->mStateFont;
     95 
     96     int32_t nPenX = x + glyph->mBitmapLeft;
     97     int32_t 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     int32_t width = (int32_t) glyph->mBitmapWidth;
    105     int32_t height = (int32_t) glyph->mBitmapHeight;
    106 
    107     state->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, int32_t x, int32_t y,
    114                            uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
    115     int32_t nPenX = x + glyph->mBitmapLeft;
    116     int32_t nPenY = y + glyph->mBitmapTop;
    117 
    118     uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
    119     uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
    120 
    121     FontState *state = &mRSC->mStateFont;
    122     uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
    123     const uint8_t* cacheBuffer = state->mCacheBuffer;
    124 
    125     uint32_t cacheX = 0, cacheY = 0;
    126     int32_t bX = 0, bY = 0;
    127     for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
    128         for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
    129             if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
    130                 ALOGE("Skipping invalid index");
    131                 continue;
    132             }
    133             uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
    134             bitmap[bY * bitmapW + bX] = tempCol;
    135         }
    136     }
    137 }
    138 
    139 void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
    140     int32_t nPenX = x + glyph->mBitmapLeft;
    141     int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
    142 
    143     int32_t width = (int32_t) glyph->mBitmapWidth;
    144     int32_t height = (int32_t) glyph->mBitmapHeight;
    145 
    146     // 0, 0 is top left, so bottom is a positive number
    147     if (bounds->bottom < nPenY) {
    148         bounds->bottom = nPenY;
    149     }
    150     if (bounds->left > nPenX) {
    151         bounds->left = nPenX;
    152     }
    153     if (bounds->right < nPenX + width) {
    154         bounds->right = nPenX + width;
    155     }
    156     if (bounds->top > nPenY - height) {
    157         bounds->top = nPenY - height;
    158     }
    159 }
    160 
    161 void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
    162                      uint32_t start, int32_t numGlyphs,
    163                      RenderMode mode, Rect *bounds,
    164                      uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
    165     if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
    166         return;
    167     }
    168 
    169     if (mode == Font::MEASURE) {
    170         if (bounds == NULL) {
    171             ALOGE("No return rectangle provided to measure text");
    172             return;
    173         }
    174         // Reset min and max of the bounding box to something large
    175         bounds->set(1e6, -1e6, 1e6, -1e6);
    176     }
    177 
    178     int32_t penX = x, penY = y;
    179     int32_t glyphsLeft = 1;
    180     if (numGlyphs > 0) {
    181         glyphsLeft = numGlyphs;
    182     }
    183 
    184     size_t index = start;
    185     size_t nextIndex = 0;
    186 
    187     while (glyphsLeft > 0) {
    188 
    189         int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
    190 
    191         // Reached the end of the string or encountered
    192         if (utfChar < 0) {
    193             break;
    194         }
    195 
    196         // Move to the next character in the array
    197         index = nextIndex;
    198 
    199         CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
    200 
    201         // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
    202         if (cachedGlyph->mIsValid) {
    203             switch (mode) {
    204             case FRAMEBUFFER:
    205                 drawCachedGlyph(cachedGlyph, penX, penY);
    206                 break;
    207             case BITMAP:
    208                 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
    209                 break;
    210             case MEASURE:
    211                 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
    212                 break;
    213             }
    214         }
    215 
    216         penX += (cachedGlyph->mAdvanceX >> 6);
    217 
    218         // If we were given a specific number of glyphs, decrement
    219         if (numGlyphs > 0) {
    220             glyphsLeft --;
    221         }
    222     }
    223 }
    224 
    225 Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
    226 
    227     CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
    228     if (cachedGlyph == NULL) {
    229         cachedGlyph = cacheGlyph((uint32_t)utfChar);
    230     }
    231     // Is the glyph still in texture cache?
    232     if (!cachedGlyph->mIsValid) {
    233         updateGlyphCache(cachedGlyph);
    234     }
    235 
    236     return cachedGlyph;
    237 }
    238 
    239 void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
    240 #ifndef ANDROID_RS_SERIALIZE
    241     FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
    242     if (error) {
    243         ALOGE("Couldn't load glyph.");
    244         return;
    245     }
    246 
    247     glyph->mAdvanceX = mFace->glyph->advance.x;
    248     glyph->mAdvanceY = mFace->glyph->advance.y;
    249     glyph->mBitmapLeft = mFace->glyph->bitmap_left;
    250     glyph->mBitmapTop = mFace->glyph->bitmap_top;
    251 
    252     FT_Bitmap *bitmap = &mFace->glyph->bitmap;
    253 
    254     // Now copy the bitmap into the cache texture
    255     uint32_t startX = 0;
    256     uint32_t startY = 0;
    257 
    258     // Let the font state figure out where to put the bitmap
    259     FontState *state = &mRSC->mStateFont;
    260     glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
    261 
    262     if (!glyph->mIsValid) {
    263         return;
    264     }
    265 
    266     uint32_t endX = startX + bitmap->width;
    267     uint32_t endY = startY + bitmap->rows;
    268 
    269     glyph->mBitmapMinX = startX;
    270     glyph->mBitmapMinY = startY;
    271     glyph->mBitmapWidth = bitmap->width;
    272     glyph->mBitmapHeight = bitmap->rows;
    273 
    274     uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
    275     uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
    276 
    277     glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
    278     glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
    279     glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
    280     glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
    281 #endif //ANDROID_RS_SERIALIZE
    282 }
    283 
    284 Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
    285     CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
    286     mCachedGlyphs.add(glyph, newGlyph);
    287 #ifndef ANDROID_RS_SERIALIZE
    288     newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
    289     newGlyph->mIsValid = false;
    290 #endif //ANDROID_RS_SERIALIZE
    291     updateGlyphCache(newGlyph);
    292 
    293     return newGlyph;
    294 }
    295 
    296 Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
    297                     const void *data, uint32_t dataLen) {
    298     rsc->mStateFont.checkInit();
    299     Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
    300 
    301     for (uint32_t i = 0; i < activeFonts.size(); i ++) {
    302         Font *ithFont = activeFonts[i];
    303         if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
    304             return ithFont;
    305         }
    306     }
    307 
    308     Font *newFont = new Font(rsc);
    309     bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
    310     if (isInitialized) {
    311         activeFonts.push(newFont);
    312         rsc->mStateFont.precacheLatin(newFont);
    313         return newFont;
    314     }
    315 
    316     ObjectBase::checkDelete(newFont);
    317     return NULL;
    318 }
    319 
    320 Font::~Font() {
    321 #ifndef ANDROID_RS_SERIALIZE
    322     if (mFace) {
    323         FT_Done_Face(mFace);
    324     }
    325 #endif
    326 
    327     for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
    328         CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
    329         delete glyph;
    330     }
    331 }
    332 
    333 FontState::FontState() {
    334     mInitialized = false;
    335     mMaxNumberOfQuads = 1024;
    336     mCurrentQuadIndex = 0;
    337     mRSC = NULL;
    338 #ifndef ANDROID_RS_SERIALIZE
    339     mLibrary = NULL;
    340 #endif //ANDROID_RS_SERIALIZE
    341 
    342     float gamma = DEFAULT_TEXT_GAMMA;
    343     int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
    344     int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
    345 
    346 #ifdef HAVE_ANDROID_OS
    347     // Get the renderer properties
    348     char property[PROPERTY_VALUE_MAX];
    349 
    350     // Get the gamma
    351     if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
    352         gamma = atof(property);
    353     }
    354 
    355     // Get the black gamma threshold
    356     if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
    357         blackThreshold = atoi(property);
    358     }
    359 
    360     // Get the white gamma threshold
    361     if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
    362         whiteThreshold = atoi(property);
    363     }
    364 #endif
    365 
    366     mBlackThreshold = (float)(blackThreshold) / 255.0f;
    367     mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
    368 
    369     // Compute the gamma tables
    370     mBlackGamma = gamma;
    371     mWhiteGamma = 1.0f / gamma;
    372 
    373     setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
    374 }
    375 
    376 FontState::~FontState() {
    377     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
    378         delete mCacheLines[i];
    379     }
    380 
    381     rsAssert(!mActiveFonts.size());
    382 }
    383 #ifndef ANDROID_RS_SERIALIZE
    384 FT_Library FontState::getLib() {
    385     if (!mLibrary) {
    386         FT_Error error = FT_Init_FreeType(&mLibrary);
    387         if (error) {
    388             ALOGE("Unable to initialize freetype");
    389             return NULL;
    390         }
    391     }
    392 
    393     return mLibrary;
    394 }
    395 #endif //ANDROID_RS_SERIALIZE
    396 
    397 
    398 void FontState::init(Context *rsc) {
    399     mRSC = rsc;
    400 }
    401 
    402 void FontState::flushAllAndInvalidate() {
    403     if (mCurrentQuadIndex != 0) {
    404         issueDrawCommand();
    405         mCurrentQuadIndex = 0;
    406     }
    407     for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
    408         mActiveFonts[i]->invalidateTextureCache();
    409     }
    410     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
    411         mCacheLines[i]->mCurrentCol = 0;
    412     }
    413 }
    414 
    415 #ifndef ANDROID_RS_SERIALIZE
    416 bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
    417     // If the glyph is too tall, don't cache it
    418     if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
    419         ALOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
    420         return false;
    421     }
    422 
    423     // Now copy the bitmap into the cache texture
    424     uint32_t startX = 0;
    425     uint32_t startY = 0;
    426 
    427     bool bitmapFit = false;
    428     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
    429         bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
    430         if (bitmapFit) {
    431             break;
    432         }
    433     }
    434 
    435     // If the new glyph didn't fit, flush the state so far and invalidate everything
    436     if (!bitmapFit) {
    437         flushAllAndInvalidate();
    438 
    439         // Try to fit it again
    440         for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
    441             bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
    442             if (bitmapFit) {
    443                 break;
    444             }
    445         }
    446 
    447         // if we still don't fit, something is wrong and we shouldn't draw
    448         if (!bitmapFit) {
    449             ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
    450             return false;
    451         }
    452     }
    453 
    454     *retOriginX = startX;
    455     *retOriginY = startY;
    456 
    457     uint32_t endX = startX + bitmap->width;
    458     uint32_t endY = startY + bitmap->rows;
    459 
    460     uint32_t cacheWidth = getCacheTextureType()->getDimX();
    461 
    462     uint8_t *cacheBuffer = mCacheBuffer;
    463     uint8_t *bitmapBuffer = bitmap->buffer;
    464 
    465     uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
    466     for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
    467         for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
    468             uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
    469             cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
    470         }
    471     }
    472 
    473     // This will dirty the texture and the shader so next time
    474     // we draw it will upload the data
    475 
    476     mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
    477         RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
    478         mCacheBuffer, mCacheWidth*mCacheHeight, mCacheWidth);
    479 
    480     mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
    481 
    482     // Some debug code
    483     /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
    484         ALOGE("Cache Line: H: %u Empty Space: %f",
    485              mCacheLines[i]->mMaxHeight,
    486               (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
    487 
    488     }*/
    489 
    490     return true;
    491 }
    492 #endif //ANDROID_RS_SERIALIZE
    493 
    494 void FontState::initRenderState() {
    495     const char *shaderString = "varying vec2 varTex0;\n"
    496                                "void main() {\n"
    497                                "  lowp vec4 col = UNI_Color;\n"
    498                                "  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"
    499                                "  col.a = pow(col.a, UNI_Gamma);\n"
    500                                "  gl_FragColor = col;\n"
    501                                "}\n";
    502 
    503     const char *textureNames[] = { "Tex0" };
    504     const size_t textureNamesLengths[] = { 4 };
    505     size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
    506 
    507     ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
    508                                                                 RS_KIND_USER, false, 4);
    509     ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
    510                                                                 RS_KIND_USER, false, 1);
    511 
    512     const char *ebn1[] = { "Color", "Gamma" };
    513     const Element *ebe1[] = {colorElem.get(), gammaElem.get()};
    514     ObjectBaseRef<const Element> constInput = Element::create(mRSC, 2, ebe1, ebn1);
    515 
    516     ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false, 0);
    517 
    518     uintptr_t tmp[4];
    519     tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
    520     tmp[1] = (uintptr_t)inputType.get();
    521     tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
    522     tmp[3] = RS_TEXTURE_2D;
    523 
    524     mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
    525                                                           RS_ALLOCATION_USAGE_SCRIPT |
    526                                                           RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
    527     ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
    528                                               textureNames, numTextures, textureNamesLengths,
    529                                               tmp, 4);
    530     mFontShaderF.set(pf);
    531     mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
    532 
    533     mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
    534                                          RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
    535                                          RS_SAMPLER_CLAMP).get());
    536     mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
    537 
    538     mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
    539                                                         false, false,
    540                                                         RS_BLEND_SRC_SRC_ALPHA,
    541                                                         RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
    542                                                         RS_DEPTH_FUNC_ALWAYS).get());
    543     mFontProgramStore->init();
    544 }
    545 
    546 void FontState::initTextTexture() {
    547     ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
    548                                                                 RS_KIND_PIXEL_A, true, 1);
    549 
    550     // We will allocate a texture to initially hold 32 character bitmaps
    551     mCacheHeight = 256;
    552     mCacheWidth = 1024;
    553     ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
    554                                                    mCacheWidth, mCacheHeight, 0, false, false, 0);
    555     mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
    556 
    557 
    558     Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
    559                                 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
    560     mTextTexture.set(cacheAlloc);
    561 
    562     // Split up our cache texture into lines of certain widths
    563     int32_t nextLine = 0;
    564     mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
    565     nextLine += mCacheLines.top()->mMaxHeight;
    566     mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
    567     nextLine += mCacheLines.top()->mMaxHeight;
    568     mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
    569     nextLine += mCacheLines.top()->mMaxHeight;
    570     mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
    571     nextLine += mCacheLines.top()->mMaxHeight;
    572     mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
    573     nextLine += mCacheLines.top()->mMaxHeight;
    574     mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
    575     nextLine += mCacheLines.top()->mMaxHeight;
    576     mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
    577 }
    578 
    579 // Avoid having to reallocate memory and render quad by quad
    580 void FontState::initVertexArrayBuffers() {
    581     // Now lets write index data
    582     ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
    583     uint32_t numIndicies = mMaxNumberOfQuads * 6;
    584     ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false, 0);
    585 
    586     Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
    587                                                           RS_ALLOCATION_USAGE_SCRIPT |
    588                                                           RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
    589     uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
    590 
    591     // Four verts, two triangles , six indices per quad
    592     for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
    593         int32_t i6 = i * 6;
    594         int32_t i4 = i * 4;
    595 
    596         indexPtr[i6 + 0] = i4 + 0;
    597         indexPtr[i6 + 1] = i4 + 1;
    598         indexPtr[i6 + 2] = i4 + 2;
    599 
    600         indexPtr[i6 + 3] = i4 + 0;
    601         indexPtr[i6 + 4] = i4 + 2;
    602         indexPtr[i6 + 5] = i4 + 3;
    603     }
    604 
    605     indexAlloc->sendDirty(mRSC);
    606 
    607     ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
    608     ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
    609 
    610     const char *ebn1[] = { "position", "texture0" };
    611     const Element *ebe1[] = {posElem.get(), texElem.get()};
    612     ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
    613 
    614     ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
    615                                                           mMaxNumberOfQuads * 4,
    616                                                           0, 0, false, false, 0);
    617 
    618     Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
    619                                                            RS_ALLOCATION_USAGE_SCRIPT);
    620     mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
    621 
    622     mMesh.set(new Mesh(mRSC, 1, 1));
    623     mMesh->setVertexBuffer(vertexAlloc, 0);
    624     mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
    625     mMesh->init();
    626     mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
    627     mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
    628 }
    629 
    630 // We don't want to allocate anything unless we actually draw text
    631 void FontState::checkInit() {
    632     if (mInitialized) {
    633         return;
    634     }
    635 
    636     initTextTexture();
    637     initRenderState();
    638 
    639     initVertexArrayBuffers();
    640 
    641     // We store a string with letters in a rough frequency of occurrence
    642     mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
    643                      "EISARNTOLCDUGPMHBYFVKWZXJQ"
    644                      ",.?!()-+@;:`'0123456789";
    645     mInitialized = true;
    646 }
    647 
    648 void FontState::issueDrawCommand() {
    649     Context::PushState ps(mRSC);
    650 
    651     mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
    652     mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
    653     mRSC->setProgramFragment(mFontShaderF.get());
    654     mRSC->setProgramStore(mFontProgramStore.get());
    655 
    656     if (mConstantsDirty) {
    657         mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
    658         mConstantsDirty = false;
    659     }
    660 
    661     if (!mRSC->setupCheck()) {
    662         return;
    663     }
    664 
    665     mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
    666 }
    667 
    668 void FontState::appendMeshQuad(float x1, float y1, float z1,
    669                                float u1, float v1,
    670                                float x2, float y2, float z2,
    671                                float u2, float v2,
    672                                float x3, float y3, float z3,
    673                                float u3, float v3,
    674                                float x4, float y4, float z4,
    675                                float u4, float v4) {
    676     const uint32_t vertsPerQuad = 4;
    677     const uint32_t floatsPerVert = 6;
    678     float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
    679 
    680     if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
    681         return;
    682     }
    683 
    684     /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
    685     ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
    686     ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
    687     ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
    688 
    689     (*currentPos++) = x1;
    690     (*currentPos++) = y1;
    691     (*currentPos++) = z1;
    692     (*currentPos++) = 0;
    693     (*currentPos++) = u1;
    694     (*currentPos++) = v1;
    695 
    696     (*currentPos++) = x2;
    697     (*currentPos++) = y2;
    698     (*currentPos++) = z2;
    699     (*currentPos++) = 0;
    700     (*currentPos++) = u2;
    701     (*currentPos++) = v2;
    702 
    703     (*currentPos++) = x3;
    704     (*currentPos++) = y3;
    705     (*currentPos++) = z3;
    706     (*currentPos++) = 0;
    707     (*currentPos++) = u3;
    708     (*currentPos++) = v3;
    709 
    710     (*currentPos++) = x4;
    711     (*currentPos++) = y4;
    712     (*currentPos++) = z4;
    713     (*currentPos++) = 0;
    714     (*currentPos++) = u4;
    715     (*currentPos++) = v4;
    716 
    717     mCurrentQuadIndex ++;
    718 
    719     if (mCurrentQuadIndex == mMaxNumberOfQuads) {
    720         issueDrawCommand();
    721         mCurrentQuadIndex = 0;
    722     }
    723 }
    724 
    725 uint32_t FontState::getRemainingCacheCapacity() {
    726     uint32_t remainingCapacity = 0;
    727     uint32_t totalPixels = 0;
    728     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
    729          remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
    730          totalPixels += mCacheLines[i]->mMaxWidth;
    731     }
    732     remainingCapacity = (remainingCapacity * 100) / totalPixels;
    733     return remainingCapacity;
    734 }
    735 
    736 void FontState::precacheLatin(Font *font) {
    737     // Remaining capacity is measured in %
    738     uint32_t remainingCapacity = getRemainingCacheCapacity();
    739     uint32_t precacheIdx = 0;
    740     const size_t l = strlen(mLatinPrecache);
    741     while ((remainingCapacity > 25) && (precacheIdx < l)) {
    742         font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
    743         remainingCapacity = getRemainingCacheCapacity();
    744         precacheIdx ++;
    745     }
    746 }
    747 
    748 
    749 void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
    750                            uint32_t startIndex, int32_t numGlyphs,
    751                            Font::RenderMode mode,
    752                            Font::Rect *bounds,
    753                            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
    754     checkInit();
    755 
    756     // Render code here
    757     Font *currentFont = mRSC->getFont();
    758     if (!currentFont) {
    759         if (!mDefault.get()) {
    760             char fullPath[1024];
    761             const char * root = getenv("ANDROID_ROOT");
    762             rsAssert(strlen(root) < 256);
    763             strcpy(fullPath, root);
    764             strcat(fullPath, "/fonts/Roboto-Regular.ttf");
    765             mDefault.set(Font::create(mRSC, fullPath, 8, mRSC->getDPI()));
    766         }
    767         currentFont = mDefault.get();
    768     }
    769     if (!currentFont) {
    770         ALOGE("Unable to initialize any fonts");
    771         return;
    772     }
    773 
    774     // Cull things that are off the screen
    775     mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
    776     mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
    777 
    778     currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
    779                            mode, bounds, bitmap, bitmapW, bitmapH);
    780 
    781     if (mCurrentQuadIndex != 0) {
    782         issueDrawCommand();
    783         mCurrentQuadIndex = 0;
    784     }
    785 }
    786 
    787 void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
    788     renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
    789     bounds->bottom = - bounds->bottom;
    790     bounds->top = - bounds->top;
    791 }
    792 
    793 void FontState::setFontColor(float r, float g, float b, float a) {
    794     mConstants.mFontColor[0] = r;
    795     mConstants.mFontColor[1] = g;
    796     mConstants.mFontColor[2] = b;
    797     mConstants.mFontColor[3] = a;
    798 
    799     mConstants.mGamma = 1.0f;
    800     const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
    801     if (luminance <= mBlackThreshold) {
    802         mConstants.mGamma = mBlackGamma;
    803     } else if (luminance >= mWhiteThreshold) {
    804         mConstants.mGamma = mWhiteGamma;
    805     }
    806 
    807     mConstantsDirty = true;
    808 }
    809 
    810 void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
    811     *r = mConstants.mFontColor[0];
    812     *g = mConstants.mFontColor[1];
    813     *b = mConstants.mFontColor[2];
    814     *a = mConstants.mFontColor[3];
    815 }
    816 
    817 void FontState::deinit(Context *rsc) {
    818     mInitialized = false;
    819 
    820     mFontShaderFConstant.clear();
    821 
    822     mMesh.clear();
    823 
    824     mFontShaderF.clear();
    825     mFontSampler.clear();
    826     mFontProgramStore.clear();
    827 
    828     mTextTexture.clear();
    829     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
    830         delete mCacheLines[i];
    831     }
    832     mCacheLines.clear();
    833 
    834     mDefault.clear();
    835 #ifndef ANDROID_RS_SERIALIZE
    836     if (mLibrary) {
    837         FT_Done_FreeType( mLibrary );
    838         mLibrary = NULL;
    839     }
    840 #endif //ANDROID_RS_SERIALIZE
    841 }
    842 
    843 #ifndef ANDROID_RS_SERIALIZE
    844 bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
    845     if ((uint32_t)bitmap->rows > mMaxHeight) {
    846         return false;
    847     }
    848 
    849     if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
    850         *retOriginX = mCurrentCol;
    851         *retOriginY = mCurrentRow;
    852         mCurrentCol += bitmap->width;
    853         mDirty = true;
    854        return true;
    855     }
    856 
    857     return false;
    858 }
    859 #endif //ANDROID_RS_SERIALIZE
    860 
    861 namespace android {
    862 namespace renderscript {
    863 
    864 RsFont rsi_FontCreateFromFile(Context *rsc,
    865                               char const *name, size_t name_length,
    866                               float fontSize, uint32_t dpi) {
    867     Font *newFont = Font::create(rsc, name, fontSize, dpi);
    868     if (newFont) {
    869         newFont->incUserRef();
    870     }
    871     return newFont;
    872 }
    873 
    874 RsFont rsi_FontCreateFromMemory(Context *rsc,
    875                                 char const *name, size_t name_length,
    876                                 float fontSize, uint32_t dpi,
    877                                 const void *data, size_t data_length) {
    878     Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
    879     if (newFont) {
    880         newFont->incUserRef();
    881     }
    882     return newFont;
    883 }
    884 
    885 } // renderscript
    886 } // android
    887