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