rsFont.cpp revision 09c67356bbeee0a97a20a06c95b66756838cb541
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    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
343
344    // Get the renderer properties
345    char property[PROPERTY_VALUE_MAX];
346
347    // Get the gamma
348    float gamma = DEFAULT_TEXT_GAMMA;
349    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
350        LOGD("  Setting text gamma to %s", property);
351        gamma = atof(property);
352    } else {
353        LOGD("  Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
354    }
355
356    // Get the black gamma threshold
357    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
358    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
359        LOGD("  Setting text black gamma threshold to %s", property);
360        blackThreshold = atoi(property);
361    } else {
362        LOGD("  Using default text black gamma threshold of %d",
363                DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
364    }
365    mBlackThreshold = (float)(blackThreshold) / 255.0f;
366
367    // Get the white gamma threshold
368    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
369    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
370        LOGD("  Setting text white gamma threshold to %s", property);
371        whiteThreshold = atoi(property);
372    } else {
373        LOGD("  Using default white black gamma threshold of %d",
374                DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
375    }
376    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
377
378    // Compute the gamma tables
379    mBlackGamma = gamma;
380    mWhiteGamma = 1.0f / gamma;
381}
382
383FontState::~FontState()
384{
385    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
386        delete mCacheLines[i];
387    }
388
389    rsAssert(!mActiveFonts.size());
390}
391
392FT_Library FontState::getLib()
393{
394    if(!mLibrary) {
395        FT_Error error = FT_Init_FreeType(&mLibrary);
396        if(error) {
397            LOGE("Unable to initialize freetype");
398            return NULL;
399        }
400    }
401
402    return mLibrary;
403}
404
405void FontState::init(Context *rsc)
406{
407    mRSC = rsc;
408}
409
410void FontState::flushAllAndInvalidate()
411{
412    if(mCurrentQuadIndex != 0) {
413        issueDrawCommand();
414        mCurrentQuadIndex = 0;
415    }
416    for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
417        mActiveFonts[i]->invalidateTextureCache();
418    }
419    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
420        mCacheLines[i]->mCurrentCol = 0;
421    }
422}
423
424bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
425{
426    // If the glyph is too tall, don't cache it
427    if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
428        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
429        return false;
430    }
431
432    // Now copy the bitmap into the cache texture
433    uint32_t startX = 0;
434    uint32_t startY = 0;
435
436    bool bitmapFit = false;
437    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
438        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
439        if(bitmapFit) {
440            break;
441        }
442    }
443
444    // If the new glyph didn't fit, flush the state so far and invalidate everything
445    if(!bitmapFit) {
446        flushAllAndInvalidate();
447
448        // Try to fit it again
449        for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
450            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
451            if(bitmapFit) {
452                break;
453            }
454        }
455
456        // if we still don't fit, something is wrong and we shouldn't draw
457        if(!bitmapFit) {
458            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
459            return false;
460        }
461    }
462
463    *retOriginX = startX;
464    *retOriginY = startY;
465
466    uint32_t endX = startX + bitmap->width;
467    uint32_t endY = startY + bitmap->rows;
468
469    uint32_t cacheWidth = getCacheTextureType()->getDimX();
470
471    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
472    uint8_t *bitmapBuffer = bitmap->buffer;
473
474    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
475    for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
476        for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
477            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
478            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
479        }
480    }
481
482    // This will dirty the texture and the shader so next time
483    // we draw it will upload the data
484    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
485    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
486
487    // Some debug code
488    /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
489        LOGE("Cache Line: H: %u Empty Space: %f",
490             mCacheLines[i]->mMaxHeight,
491              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
492
493    }*/
494
495    return true;
496}
497
498void FontState::initRenderState()
499{
500    String8 shaderString("varying vec4 varTex0;\n");
501    shaderString.append("void main() {\n");
502    shaderString.append("  lowp vec4 col = UNI_Color;\n");
503    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
504    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
505    shaderString.append("  gl_FragColor = col;\n");
506    shaderString.append("}\n");
507
508    const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
509    const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
510    mRSC->mStateElement.elementBuilderBegin();
511    mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
512    mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
513    const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
514
515    Type *inputType = new Type(mRSC);
516    inputType->setElement(constInput);
517    inputType->setDimX(1);
518    inputType->compute();
519
520    uint32_t tmp[4];
521    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
522    tmp[1] = (uint32_t)inputType;
523    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
524    tmp[3] = 1;
525
526    mFontShaderFConstant.set(new Allocation(mRSC, inputType));
527    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
528                                              shaderString.length(), tmp, 4);
529    mFontShaderF.set(pf);
530    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
531
532    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
533                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
534    mFontSampler.set(sampler);
535    mFontShaderF->bindSampler(mRSC, 0, sampler);
536
537    ProgramStore *fontStore = new ProgramStore(mRSC);
538    mFontProgramStore.set(fontStore);
539    mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
540    mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
541    mFontProgramStore->setDitherEnable(false);
542    mFontProgramStore->setDepthMask(false);
543}
544
545void FontState::initTextTexture()
546{
547    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
548
549    // We will allocate a texture to initially hold 32 character bitmaps
550    Type *texType = new Type(mRSC);
551    texType->setElement(alphaElem);
552    texType->setDimX(1024);
553    texType->setDimY(256);
554    texType->compute();
555
556    Allocation *cacheAlloc = new Allocation(mRSC, texType);
557    mTextTexture.set(cacheAlloc);
558    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
559
560    // Split up our cache texture into lines of certain widths
561    int32_t nextLine = 0;
562    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
563    nextLine += mCacheLines.top()->mMaxHeight;
564    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
565    nextLine += mCacheLines.top()->mMaxHeight;
566    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
567    nextLine += mCacheLines.top()->mMaxHeight;
568    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
569    nextLine += mCacheLines.top()->mMaxHeight;
570    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
571    nextLine += mCacheLines.top()->mMaxHeight;
572    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
573    nextLine += mCacheLines.top()->mMaxHeight;
574    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
575}
576
577// Avoid having to reallocate memory and render quad by quad
578void FontState::initVertexArrayBuffers()
579{
580    // Now lets write index data
581    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
582    Type *indexType = new Type(mRSC);
583    uint32_t numIndicies = mMaxNumberOfQuads * 6;
584    indexType->setDimX(numIndicies);
585    indexType->setElement(indexElem);
586    indexType->compute();
587
588    Allocation *indexAlloc = new Allocation(mRSC, indexType);
589    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
590
591    // Four verts, two triangles , six indices per quad
592    for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
593        int32_t i6 = i * 6;
594        int32_t i4 = i * 4;
595
596        indexPtr[i6 + 0] = i4 + 0;
597        indexPtr[i6 + 1] = i4 + 1;
598        indexPtr[i6 + 2] = i4 + 2;
599
600        indexPtr[i6 + 3] = i4 + 0;
601        indexPtr[i6 + 4] = i4 + 2;
602        indexPtr[i6 + 5] = i4 + 3;
603    }
604
605    indexAlloc->deferedUploadToBufferObject(mRSC);
606    mIndexBuffer.set(indexAlloc);
607
608    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
609    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
610
611    const Element *elemArray[2];
612    elemArray[0] = posElem;
613    elemArray[1] = texElem;
614
615    String8 posName("position");
616    String8 texName("texture0");
617
618    const char *nameArray[2];
619    nameArray[0] = posName.string();
620    nameArray[1] = texName.string();
621    size_t lengths[2];
622    lengths[0] = posName.size();
623    lengths[1] = texName.size();
624    uint32_t arraySizes[2] = {1, 1};
625
626    const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
627
628    Type *vertexDataType = new Type(mRSC);
629    vertexDataType->setDimX(mMaxNumberOfQuads * 4);
630    vertexDataType->setElement(vertexDataElem);
631    vertexDataType->compute();
632
633    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
634    mTextMeshPtr = (float*)vertexAlloc->getPtr();
635
636    mVertexArray.set(vertexAlloc);
637}
638
639// We don't want to allocate anything unless we actually draw text
640void FontState::checkInit()
641{
642    if(mInitialized) {
643        return;
644    }
645
646    initTextTexture();
647    initRenderState();
648
649    initVertexArrayBuffers();
650
651    // We store a string with letters in a rough frequency of occurrence
652    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
653    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
654    mLatinPrecache += String8(",.?!()-+@;:`'");
655    mLatinPrecache += String8("0123456789");
656
657    mInitialized = true;
658}
659
660void FontState::issueDrawCommand() {
661
662    ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
663    mRSC->setVertex(mRSC->getDefaultProgramVertex());
664
665    ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
666    mRSC->setRaster(mRSC->getDefaultProgramRaster());
667
668    ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
669    mRSC->setFragment(mFontShaderF.get());
670
671    ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
672    mRSC->setFragmentStore(mFontProgramStore.get());
673
674    if(mConstantsDirty) {
675        mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
676        mConstantsDirty = false;
677    }
678
679    if (!mRSC->setupCheck()) {
680        mRSC->setVertex((ProgramVertex *)tmpV.get());
681        mRSC->setRaster((ProgramRaster *)tmpR.get());
682        mRSC->setFragment((ProgramFragment *)tmpF.get());
683        mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
684        return;
685    }
686
687    float *vtx = (float*)mVertexArray->getPtr();
688    float *tex = vtx + 3;
689
690    VertexArray va;
691    va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
692    va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
693    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
694
695    mIndexBuffer->uploadCheck(mRSC);
696    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
697    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
698
699    // Reset the state
700    mRSC->setVertex((ProgramVertex *)tmpV.get());
701    mRSC->setRaster((ProgramRaster *)tmpR.get());
702    mRSC->setFragment((ProgramFragment *)tmpF.get());
703    mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
704}
705
706void FontState::appendMeshQuad(float x1, float y1, float z1,
707                                  float u1, float v1,
708                                  float x2, float y2, float z2,
709                                  float u2, float v2,
710                                  float x3, float y3, float z3,
711                                  float u3, float v3,
712                                  float x4, float y4, float z4,
713                                  float u4, float v4)
714{
715    const uint32_t vertsPerQuad = 4;
716    const uint32_t floatsPerVert = 5;
717    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
718
719    // Cull things that are off the screen
720    float width = (float)mRSC->getWidth();
721    float height = (float)mRSC->getHeight();
722
723    if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
724        return;
725    }
726
727    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
728    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
729    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
730    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
731
732    (*currentPos++) = x1;
733    (*currentPos++) = y1;
734    (*currentPos++) = z1;
735    (*currentPos++) = u1;
736    (*currentPos++) = v1;
737
738    (*currentPos++) = x2;
739    (*currentPos++) = y2;
740    (*currentPos++) = z2;
741    (*currentPos++) = u2;
742    (*currentPos++) = v2;
743
744    (*currentPos++) = x3;
745    (*currentPos++) = y3;
746    (*currentPos++) = z3;
747    (*currentPos++) = u3;
748    (*currentPos++) = v3;
749
750    (*currentPos++) = x4;
751    (*currentPos++) = y4;
752    (*currentPos++) = z4;
753    (*currentPos++) = u4;
754    (*currentPos++) = v4;
755
756    mCurrentQuadIndex ++;
757
758    if(mCurrentQuadIndex == mMaxNumberOfQuads) {
759        issueDrawCommand();
760        mCurrentQuadIndex = 0;
761    }
762}
763
764uint32_t FontState::getRemainingCacheCapacity() {
765    uint32_t remainingCapacity = 0;
766    uint32_t totalPixels = 0;
767    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
768         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
769         totalPixels += mCacheLines[i]->mMaxWidth;
770    }
771    remainingCapacity = (remainingCapacity * 100) / totalPixels;
772    return remainingCapacity;
773}
774
775void FontState::precacheLatin(Font *font) {
776    // Remaining capacity is measured in %
777    uint32_t remainingCapacity = getRemainingCacheCapacity();
778    uint32_t precacheIdx = 0;
779    while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
780        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
781        remainingCapacity = getRemainingCacheCapacity();
782        precacheIdx ++;
783    }
784}
785
786
787void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
788                           uint32_t startIndex, int32_t numGlyphs,
789                           Font::RenderMode mode,
790                           Font::Rect *bounds,
791                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
792{
793    checkInit();
794
795    // Render code here
796    Font *currentFont = mRSC->getFont();
797    if(!currentFont) {
798        if(!mDefault.get()) {
799            mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
800        }
801        currentFont = mDefault.get();
802    }
803    if(!currentFont) {
804        LOGE("Unable to initialize any fonts");
805        return;
806    }
807
808    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
809                           mode, bounds, bitmap, bitmapW, bitmapH);
810
811    if(mCurrentQuadIndex != 0) {
812        issueDrawCommand();
813        mCurrentQuadIndex = 0;
814    }
815}
816
817void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
818    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
819}
820
821void FontState::setFontColor(float r, float g, float b, float a) {
822    mConstants.mFontColor[0] = r;
823    mConstants.mFontColor[1] = g;
824    mConstants.mFontColor[2] = b;
825    mConstants.mFontColor[3] = a;
826
827    mConstants.mGamma = 1.0f;
828    const int32_t luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
829    if (luminance <= mBlackThreshold) {
830        mConstants.mGamma = mBlackGamma;
831    } else if (luminance >= mWhiteThreshold) {
832        mConstants.mGamma = mWhiteGamma;
833    }
834    mConstantsDirty = true;
835}
836
837void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
838    *r = mConstants.mFontColor[0];
839    *g = mConstants.mFontColor[1];
840    *b = mConstants.mFontColor[2];
841    *a = mConstants.mFontColor[3];
842}
843
844void FontState::deinit(Context *rsc)
845{
846    mInitialized = false;
847
848    mFontShaderFConstant.clear();
849
850    mIndexBuffer.clear();
851    mVertexArray.clear();
852
853    mFontShaderF.clear();
854    mFontSampler.clear();
855    mFontProgramStore.clear();
856
857    mTextTexture.clear();
858    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
859        delete mCacheLines[i];
860    }
861    mCacheLines.clear();
862
863    mDefault.clear();
864
865    Vector<Font*> fontsToDereference = mActiveFonts;
866    for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
867        fontsToDereference[i]->zeroUserRef();
868    }
869
870    if(mLibrary) {
871        FT_Done_FreeType( mLibrary );
872        mLibrary = NULL;
873    }
874}
875
876namespace android {
877namespace renderscript {
878
879RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
880{
881    Font *newFont = Font::create(rsc, name, fontSize, dpi);
882    if(newFont) {
883        newFont->incUserRef();
884    }
885    return newFont;
886}
887
888} // renderscript
889} // android
890