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