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