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