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 = nullptr;
     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 != nullptr && 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 == nullptr || len == 0) {
    166         return;
    167     }
    168 
    169     if (mode == Font::MEASURE) {
    170         if (bounds == nullptr) {
    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 == nullptr) {
    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 nullptr;
    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 = nullptr;
    338 #ifndef ANDROID_RS_SERIALIZE
    339     mLibrary = nullptr;
    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, nullptr) > 0) {
    352         gamma = atof(property);
    353     }
    354 
    355     // Get the black gamma threshold
    356     if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) {
    357         blackThreshold = atoi(property);
    358     }
    359 
    360     // Get the white gamma threshold
    361     if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 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 nullptr;
    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     ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1);
    516 
    517     uintptr_t tmp[4];
    518     tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
    519     tmp[1] = (uintptr_t)inputType.get();
    520     tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
    521     tmp[3] = RS_TEXTURE_2D;
    522 
    523     mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
    524                                                           RS_ALLOCATION_USAGE_SCRIPT |
    525                                                           RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
    526     ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
    527                                               textureNames, numTextures, textureNamesLengths,
    528                                               tmp, 4);
    529     mFontShaderF.set(pf);
    530     mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
    531 
    532     mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
    533                                          RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
    534                                          RS_SAMPLER_CLAMP).get());
    535     mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
    536 
    537     mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
    538                                                         false, false,
    539                                                         RS_BLEND_SRC_SRC_ALPHA,
    540                                                         RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
    541                                                         RS_DEPTH_FUNC_ALWAYS).get());
    542     mFontProgramStore->init();
    543 }
    544 
    545 void FontState::initTextTexture() {
    546     ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
    547                                                                 RS_KIND_PIXEL_A, true, 1);
    548 
    549     // We will allocate a texture to initially hold 32 character bitmaps
    550     mCacheHeight = 256;
    551     mCacheWidth = 1024;
    552     ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), mCacheWidth, mCacheHeight);
    553 
    554     mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
    555 
    556 
    557     Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
    558                                 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
    559     mTextTexture.set(cacheAlloc);
    560 
    561     // Split up our cache texture into lines of certain widths
    562     int32_t nextLine = 0;
    563     mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
    564     nextLine += mCacheLines.top()->mMaxHeight;
    565     mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
    566     nextLine += mCacheLines.top()->mMaxHeight;
    567     mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
    568     nextLine += mCacheLines.top()->mMaxHeight;
    569     mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
    570     nextLine += mCacheLines.top()->mMaxHeight;
    571     mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
    572     nextLine += mCacheLines.top()->mMaxHeight;
    573     mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
    574     nextLine += mCacheLines.top()->mMaxHeight;
    575     mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
    576 }
    577 
    578 // Avoid having to reallocate memory and render quad by quad
    579 void FontState::initVertexArrayBuffers() {
    580     // Now lets write index data
    581     ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
    582     ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), mMaxNumberOfQuads * 6);
    583 
    584     Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
    585                                                           RS_ALLOCATION_USAGE_SCRIPT |
    586                                                           RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
    587     uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
    588 
    589     // Four verts, two triangles , six indices per quad
    590     for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
    591         int32_t i6 = i * 6;
    592         int32_t i4 = i * 4;
    593 
    594         indexPtr[i6 + 0] = i4 + 0;
    595         indexPtr[i6 + 1] = i4 + 1;
    596         indexPtr[i6 + 2] = i4 + 2;
    597 
    598         indexPtr[i6 + 3] = i4 + 0;
    599         indexPtr[i6 + 4] = i4 + 2;
    600         indexPtr[i6 + 5] = i4 + 3;
    601     }
    602 
    603     indexAlloc->sendDirty(mRSC);
    604 
    605     ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
    606     ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
    607 
    608     const char *ebn1[] = { "position", "texture0" };
    609     const Element *ebe1[] = {posElem.get(), texElem.get()};
    610     ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
    611 
    612     ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(), mMaxNumberOfQuads * 4);
    613 
    614     Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
    615                                                            RS_ALLOCATION_USAGE_SCRIPT);
    616     mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
    617 
    618     mMesh.set(new Mesh(mRSC, 1, 1));
    619     mMesh->setVertexBuffer(vertexAlloc, 0);
    620     mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
    621     mMesh->init();
    622     mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
    623     mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
    624 }
    625 
    626 // We don't want to allocate anything unless we actually draw text
    627 void FontState::checkInit() {
    628     if (mInitialized) {
    629         return;
    630     }
    631 
    632     initTextTexture();
    633     initRenderState();
    634 
    635     initVertexArrayBuffers();
    636 
    637     // We store a string with letters in a rough frequency of occurrence
    638     mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
    639                      "EISARNTOLCDUGPMHBYFVKWZXJQ"
    640                      ",.?!()-+@;:`'0123456789";
    641     mInitialized = true;
    642 }
    643 
    644 void FontState::issueDrawCommand() {
    645     Context::PushState ps(mRSC);
    646 
    647     mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
    648     mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
    649     mRSC->setProgramFragment(mFontShaderF.get());
    650     mRSC->setProgramStore(mFontProgramStore.get());
    651 
    652     if (mConstantsDirty) {
    653         mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
    654         mConstantsDirty = false;
    655     }
    656 
    657     if (!mRSC->setupCheck()) {
    658         return;
    659     }
    660 
    661     mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
    662 }
    663 
    664 void FontState::appendMeshQuad(float x1, float y1, float z1,
    665                                float u1, float v1,
    666                                float x2, float y2, float z2,
    667                                float u2, float v2,
    668                                float x3, float y3, float z3,
    669                                float u3, float v3,
    670                                float x4, float y4, float z4,
    671                                float u4, float v4) {
    672     const uint32_t vertsPerQuad = 4;
    673     const uint32_t floatsPerVert = 6;
    674     float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
    675 
    676     if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
    677         return;
    678     }
    679 
    680     /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
    681     ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
    682     ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
    683     ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
    684 
    685     (*currentPos++) = x1;
    686     (*currentPos++) = y1;
    687     (*currentPos++) = z1;
    688     (*currentPos++) = 0;
    689     (*currentPos++) = u1;
    690     (*currentPos++) = v1;
    691 
    692     (*currentPos++) = x2;
    693     (*currentPos++) = y2;
    694     (*currentPos++) = z2;
    695     (*currentPos++) = 0;
    696     (*currentPos++) = u2;
    697     (*currentPos++) = v2;
    698 
    699     (*currentPos++) = x3;
    700     (*currentPos++) = y3;
    701     (*currentPos++) = z3;
    702     (*currentPos++) = 0;
    703     (*currentPos++) = u3;
    704     (*currentPos++) = v3;
    705 
    706     (*currentPos++) = x4;
    707     (*currentPos++) = y4;
    708     (*currentPos++) = z4;
    709     (*currentPos++) = 0;
    710     (*currentPos++) = u4;
    711     (*currentPos++) = v4;
    712 
    713     mCurrentQuadIndex ++;
    714 
    715     if (mCurrentQuadIndex == mMaxNumberOfQuads) {
    716         issueDrawCommand();
    717         mCurrentQuadIndex = 0;
    718     }
    719 }
    720 
    721 uint32_t FontState::getRemainingCacheCapacity() {
    722     uint32_t remainingCapacity = 0;
    723     uint32_t totalPixels = 0;
    724     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
    725          remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
    726          totalPixels += mCacheLines[i]->mMaxWidth;
    727     }
    728     remainingCapacity = (remainingCapacity * 100) / totalPixels;
    729     return remainingCapacity;
    730 }
    731 
    732 void FontState::precacheLatin(Font *font) {
    733     // Remaining capacity is measured in %
    734     uint32_t remainingCapacity = getRemainingCacheCapacity();
    735     uint32_t precacheIdx = 0;
    736     const size_t l = strlen(mLatinPrecache);
    737     while ((remainingCapacity > 25) && (precacheIdx < l)) {
    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             char fullPath[1024];
    757             const char * root = getenv("ANDROID_ROOT");
    758             rsAssert(strlen(root) < 256);
    759             strcpy(fullPath, root);
    760             strcat(fullPath, "/fonts/Roboto-Regular.ttf");
    761             mDefault.set(Font::create(mRSC, fullPath, 8, mRSC->getDPI()));
    762         }
    763         currentFont = mDefault.get();
    764     }
    765     if (!currentFont) {
    766         ALOGE("Unable to initialize any fonts");
    767         return;
    768     }
    769 
    770     // Cull things that are off the screen
    771     mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
    772     mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
    773 
    774     currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
    775                            mode, bounds, bitmap, bitmapW, bitmapH);
    776 
    777     if (mCurrentQuadIndex != 0) {
    778         issueDrawCommand();
    779         mCurrentQuadIndex = 0;
    780     }
    781 }
    782 
    783 void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
    784     renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
    785     bounds->bottom = - bounds->bottom;
    786     bounds->top = - bounds->top;
    787 }
    788 
    789 void FontState::setFontColor(float r, float g, float b, float a) {
    790     mConstants.mFontColor[0] = r;
    791     mConstants.mFontColor[1] = g;
    792     mConstants.mFontColor[2] = b;
    793     mConstants.mFontColor[3] = a;
    794 
    795     mConstants.mGamma = 1.0f;
    796     const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
    797     if (luminance <= mBlackThreshold) {
    798         mConstants.mGamma = mBlackGamma;
    799     } else if (luminance >= mWhiteThreshold) {
    800         mConstants.mGamma = mWhiteGamma;
    801     }
    802 
    803     mConstantsDirty = true;
    804 }
    805 
    806 void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
    807     *r = mConstants.mFontColor[0];
    808     *g = mConstants.mFontColor[1];
    809     *b = mConstants.mFontColor[2];
    810     *a = mConstants.mFontColor[3];
    811 }
    812 
    813 void FontState::deinit(Context *rsc) {
    814     mInitialized = false;
    815 
    816     mFontShaderFConstant.clear();
    817 
    818     mMesh.clear();
    819 
    820     mFontShaderF.clear();
    821     mFontSampler.clear();
    822     mFontProgramStore.clear();
    823 
    824     mTextTexture.clear();
    825     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
    826         delete mCacheLines[i];
    827     }
    828     mCacheLines.clear();
    829 
    830     mDefault.clear();
    831 #ifndef ANDROID_RS_SERIALIZE
    832     if (mLibrary) {
    833         FT_Done_FreeType( mLibrary );
    834         mLibrary = nullptr;
    835     }
    836 #endif //ANDROID_RS_SERIALIZE
    837 }
    838 
    839 #ifndef ANDROID_RS_SERIALIZE
    840 bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
    841     if ((uint32_t)bitmap->rows > mMaxHeight) {
    842         return false;
    843     }
    844 
    845     if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
    846         *retOriginX = mCurrentCol;
    847         *retOriginY = mCurrentRow;
    848         mCurrentCol += bitmap->width;
    849         mDirty = true;
    850        return true;
    851     }
    852 
    853     return false;
    854 }
    855 #endif //ANDROID_RS_SERIALIZE
    856 
    857 namespace android {
    858 namespace renderscript {
    859 
    860 RsFont rsi_FontCreateFromFile(Context *rsc,
    861                               char const *name, size_t name_length,
    862                               float fontSize, uint32_t dpi) {
    863     Font *newFont = Font::create(rsc, name, fontSize, dpi);
    864     if (newFont) {
    865         newFont->incUserRef();
    866     }
    867     return newFont;
    868 }
    869 
    870 RsFont rsi_FontCreateFromMemory(Context *rsc,
    871                                 char const *name, size_t name_length,
    872                                 float fontSize, uint32_t dpi,
    873                                 const void *data, size_t data_length) {
    874     Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
    875     if (newFont) {
    876         newFont->incUserRef();
    877     }
    878     return newFont;
    879 }
    880 
    881 } // renderscript
    882 } // android
    883