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