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