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