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