rsFont.cpp revision 60709257bbdeb0c50f39b9c8969dc76264d6e142
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_from_utf8_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    Context::PushState ps(mRSC);
617
618    mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
619    mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
620    mRSC->setProgramFragment(mFontShaderF.get());
621    mRSC->setProgramStore(mFontProgramStore.get());
622
623    if (mConstantsDirty) {
624        mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
625        mConstantsDirty = false;
626    }
627
628    if (!mRSC->setupCheck()) {
629        return;
630    }
631
632    float *vtx = (float*)mVertexArray->getPtr();
633    float *tex = vtx + 3;
634
635    VertexArray::Attrib attribs[2];
636    attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
637    attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
638    VertexArray va(attribs, 2);
639    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
640
641    mIndexBuffer->uploadCheck(mRSC);
642    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
643    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
644}
645
646void FontState::appendMeshQuad(float x1, float y1, float z1,
647                               float u1, float v1,
648                               float x2, float y2, float z2,
649                               float u2, float v2,
650                               float x3, float y3, float z3,
651                               float u3, float v3,
652                               float x4, float y4, float z4,
653                               float u4, float v4) {
654    const uint32_t vertsPerQuad = 4;
655    const uint32_t floatsPerVert = 5;
656    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
657
658    // Cull things that are off the screen
659    float width = (float)mRSC->getWidth();
660    float height = (float)mRSC->getHeight();
661
662    if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
663        return;
664    }
665
666    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
667    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
668    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
669    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
670
671    (*currentPos++) = x1;
672    (*currentPos++) = y1;
673    (*currentPos++) = z1;
674    (*currentPos++) = u1;
675    (*currentPos++) = v1;
676
677    (*currentPos++) = x2;
678    (*currentPos++) = y2;
679    (*currentPos++) = z2;
680    (*currentPos++) = u2;
681    (*currentPos++) = v2;
682
683    (*currentPos++) = x3;
684    (*currentPos++) = y3;
685    (*currentPos++) = z3;
686    (*currentPos++) = u3;
687    (*currentPos++) = v3;
688
689    (*currentPos++) = x4;
690    (*currentPos++) = y4;
691    (*currentPos++) = z4;
692    (*currentPos++) = u4;
693    (*currentPos++) = v4;
694
695    mCurrentQuadIndex ++;
696
697    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
698        issueDrawCommand();
699        mCurrentQuadIndex = 0;
700    }
701}
702
703uint32_t FontState::getRemainingCacheCapacity() {
704    uint32_t remainingCapacity = 0;
705    uint32_t totalPixels = 0;
706    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
707         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
708         totalPixels += mCacheLines[i]->mMaxWidth;
709    }
710    remainingCapacity = (remainingCapacity * 100) / totalPixels;
711    return remainingCapacity;
712}
713
714void FontState::precacheLatin(Font *font) {
715    // Remaining capacity is measured in %
716    uint32_t remainingCapacity = getRemainingCacheCapacity();
717    uint32_t precacheIdx = 0;
718    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
719        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
720        remainingCapacity = getRemainingCacheCapacity();
721        precacheIdx ++;
722    }
723}
724
725
726void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
727                           uint32_t startIndex, int32_t numGlyphs,
728                           Font::RenderMode mode,
729                           Font::Rect *bounds,
730                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
731    checkInit();
732
733    // Render code here
734    Font *currentFont = mRSC->getFont();
735    if (!currentFont) {
736        if (!mDefault.get()) {
737            mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
738        }
739        currentFont = mDefault.get();
740    }
741    if (!currentFont) {
742        LOGE("Unable to initialize any fonts");
743        return;
744    }
745
746    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
747                           mode, bounds, bitmap, bitmapW, bitmapH);
748
749    if (mCurrentQuadIndex != 0) {
750        issueDrawCommand();
751        mCurrentQuadIndex = 0;
752    }
753}
754
755void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
756    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
757}
758
759void FontState::setFontColor(float r, float g, float b, float a) {
760    mConstants.mFontColor[0] = r;
761    mConstants.mFontColor[1] = g;
762    mConstants.mFontColor[2] = b;
763    mConstants.mFontColor[3] = a;
764
765    mConstants.mGamma = 1.0f;
766    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
767    if (luminance <= mBlackThreshold) {
768        mConstants.mGamma = mBlackGamma;
769    } else if (luminance >= mWhiteThreshold) {
770        mConstants.mGamma = mWhiteGamma;
771    }
772
773    mConstantsDirty = true;
774}
775
776void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
777    *r = mConstants.mFontColor[0];
778    *g = mConstants.mFontColor[1];
779    *b = mConstants.mFontColor[2];
780    *a = mConstants.mFontColor[3];
781}
782
783void FontState::deinit(Context *rsc) {
784    mInitialized = false;
785
786    mFontShaderFConstant.clear();
787
788    mIndexBuffer.clear();
789    mVertexArray.clear();
790
791    mFontShaderF.clear();
792    mFontSampler.clear();
793    mFontProgramStore.clear();
794
795    mTextTexture.clear();
796    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
797        delete mCacheLines[i];
798    }
799    mCacheLines.clear();
800
801    mDefault.clear();
802
803    Vector<Font*> fontsToDereference = mActiveFonts;
804    for (uint32_t i = 0; i < fontsToDereference.size(); i ++) {
805        fontsToDereference[i]->zeroUserRef();
806    }
807
808    if (mLibrary) {
809        FT_Done_FreeType( mLibrary );
810        mLibrary = NULL;
811    }
812}
813
814namespace android {
815namespace renderscript {
816
817RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) {
818    Font *newFont = Font::create(rsc, name, fontSize, dpi);
819    if (newFont) {
820        newFont->incUserRef();
821    }
822    return newFont;
823}
824
825} // renderscript
826} // android
827