rsFont.cpp revision 00237f18a9d31afdca5cca8d621397fbf5b16076
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,
513                                               RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
514                                               RS_DEPTH_FUNC_ALWAYS);
515    mFontProgramStore.set(fontStore);
516    mFontProgramStore->init();
517}
518
519void FontState::initTextTexture() {
520    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
521
522    // We will allocate a texture to initially hold 32 character bitmaps
523    Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
524
525    Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
526    mTextTexture.set(cacheAlloc);
527    mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
528
529    // Split up our cache texture into lines of certain widths
530    int32_t nextLine = 0;
531    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
532    nextLine += mCacheLines.top()->mMaxHeight;
533    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
534    nextLine += mCacheLines.top()->mMaxHeight;
535    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
536    nextLine += mCacheLines.top()->mMaxHeight;
537    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
538    nextLine += mCacheLines.top()->mMaxHeight;
539    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
540    nextLine += mCacheLines.top()->mMaxHeight;
541    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
542    nextLine += mCacheLines.top()->mMaxHeight;
543    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
544}
545
546// Avoid having to reallocate memory and render quad by quad
547void FontState::initVertexArrayBuffers() {
548    // Now lets write index data
549    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
550    uint32_t numIndicies = mMaxNumberOfQuads * 6;
551    Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
552
553    Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
554    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
555
556    // Four verts, two triangles , six indices per quad
557    for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
558        int32_t i6 = i * 6;
559        int32_t i4 = i * 4;
560
561        indexPtr[i6 + 0] = i4 + 0;
562        indexPtr[i6 + 1] = i4 + 1;
563        indexPtr[i6 + 2] = i4 + 2;
564
565        indexPtr[i6 + 3] = i4 + 0;
566        indexPtr[i6 + 4] = i4 + 2;
567        indexPtr[i6 + 5] = i4 + 3;
568    }
569
570    indexAlloc->deferredUploadToBufferObject(mRSC);
571    mIndexBuffer.set(indexAlloc);
572
573    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
574    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
575
576    mRSC->mStateElement.elementBuilderBegin();
577    mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
578    mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
579    const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
580
581    Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
582                                         mMaxNumberOfQuads * 4,
583                                         0, 0, false, false);
584
585    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
586    mTextMeshPtr = (float*)vertexAlloc->getPtr();
587
588    mVertexArray.set(vertexAlloc);
589}
590
591// We don't want to allocate anything unless we actually draw text
592void FontState::checkInit() {
593    if (mInitialized) {
594        return;
595    }
596
597    initTextTexture();
598    initRenderState();
599
600    initVertexArrayBuffers();
601
602    // We store a string with letters in a rough frequency of occurrence
603    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
604    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
605    mLatinPrecache += String8(",.?!()-+@;:`'");
606    mLatinPrecache += String8("0123456789");
607
608    mInitialized = true;
609}
610
611void FontState::issueDrawCommand() {
612    Context::PushState ps(mRSC);
613
614    mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
615    mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
616    mRSC->setProgramFragment(mFontShaderF.get());
617    mRSC->setProgramStore(mFontProgramStore.get());
618
619    if (mConstantsDirty) {
620        mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
621        mConstantsDirty = false;
622    }
623
624    if (!mRSC->setupCheck()) {
625        return;
626    }
627
628    float *vtx = (float*)mVertexArray->getPtr();
629    float *tex = vtx + 3;
630
631    VertexArray::Attrib attribs[2];
632    attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
633    attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
634    VertexArray va(attribs, 2);
635    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
636
637    mIndexBuffer->uploadCheck(mRSC);
638    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
639    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
640}
641
642void FontState::appendMeshQuad(float x1, float y1, float z1,
643                               float u1, float v1,
644                               float x2, float y2, float z2,
645                               float u2, float v2,
646                               float x3, float y3, float z3,
647                               float u3, float v3,
648                               float x4, float y4, float z4,
649                               float u4, float v4) {
650    const uint32_t vertsPerQuad = 4;
651    const uint32_t floatsPerVert = 5;
652    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
653
654    // Cull things that are off the screen
655    float width = (float)mRSC->getWidth();
656    float height = (float)mRSC->getHeight();
657
658    if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
659        return;
660    }
661
662    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
663    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
664    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
665    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
666
667    (*currentPos++) = x1;
668    (*currentPos++) = y1;
669    (*currentPos++) = z1;
670    (*currentPos++) = u1;
671    (*currentPos++) = v1;
672
673    (*currentPos++) = x2;
674    (*currentPos++) = y2;
675    (*currentPos++) = z2;
676    (*currentPos++) = u2;
677    (*currentPos++) = v2;
678
679    (*currentPos++) = x3;
680    (*currentPos++) = y3;
681    (*currentPos++) = z3;
682    (*currentPos++) = u3;
683    (*currentPos++) = v3;
684
685    (*currentPos++) = x4;
686    (*currentPos++) = y4;
687    (*currentPos++) = z4;
688    (*currentPos++) = u4;
689    (*currentPos++) = v4;
690
691    mCurrentQuadIndex ++;
692
693    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
694        issueDrawCommand();
695        mCurrentQuadIndex = 0;
696    }
697}
698
699uint32_t FontState::getRemainingCacheCapacity() {
700    uint32_t remainingCapacity = 0;
701    uint32_t totalPixels = 0;
702    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
703         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
704         totalPixels += mCacheLines[i]->mMaxWidth;
705    }
706    remainingCapacity = (remainingCapacity * 100) / totalPixels;
707    return remainingCapacity;
708}
709
710void FontState::precacheLatin(Font *font) {
711    // Remaining capacity is measured in %
712    uint32_t remainingCapacity = getRemainingCacheCapacity();
713    uint32_t precacheIdx = 0;
714    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
715        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
716        remainingCapacity = getRemainingCacheCapacity();
717        precacheIdx ++;
718    }
719}
720
721
722void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
723                           uint32_t startIndex, int32_t numGlyphs,
724                           Font::RenderMode mode,
725                           Font::Rect *bounds,
726                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
727    checkInit();
728
729    // Render code here
730    Font *currentFont = mRSC->getFont();
731    if (!currentFont) {
732        if (!mDefault.get()) {
733            String8 fontsDir("/fonts/DroidSans.ttf");
734            String8 fullPath(getenv("ANDROID_ROOT"));
735            fullPath += fontsDir;
736
737            mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
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    bounds->bottom = - bounds->bottom;
758    bounds->top = - bounds->top;
759}
760
761void FontState::setFontColor(float r, float g, float b, float a) {
762    mConstants.mFontColor[0] = r;
763    mConstants.mFontColor[1] = g;
764    mConstants.mFontColor[2] = b;
765    mConstants.mFontColor[3] = a;
766
767    mConstants.mGamma = 1.0f;
768    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
769    if (luminance <= mBlackThreshold) {
770        mConstants.mGamma = mBlackGamma;
771    } else if (luminance >= mWhiteThreshold) {
772        mConstants.mGamma = mWhiteGamma;
773    }
774
775    mConstantsDirty = true;
776}
777
778void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
779    *r = mConstants.mFontColor[0];
780    *g = mConstants.mFontColor[1];
781    *b = mConstants.mFontColor[2];
782    *a = mConstants.mFontColor[3];
783}
784
785void FontState::deinit(Context *rsc) {
786    mInitialized = false;
787
788    mFontShaderFConstant.clear();
789
790    mIndexBuffer.clear();
791    mVertexArray.clear();
792
793    mFontShaderF.clear();
794    mFontSampler.clear();
795    mFontProgramStore.clear();
796
797    mTextTexture.clear();
798    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
799        delete mCacheLines[i];
800    }
801    mCacheLines.clear();
802
803    mDefault.clear();
804
805    if (mLibrary) {
806        FT_Done_FreeType( mLibrary );
807        mLibrary = NULL;
808    }
809}
810
811bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
812    if ((uint32_t)bitmap->rows > mMaxHeight) {
813        return false;
814    }
815
816    if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
817        *retOriginX = mCurrentCol;
818        *retOriginY = mCurrentRow;
819        mCurrentCol += bitmap->width;
820        mDirty = true;
821       return true;
822    }
823
824    return false;
825}
826
827namespace android {
828namespace renderscript {
829
830RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) {
831    Font *newFont = Font::create(rsc, name, fontSize, dpi);
832    if (newFont) {
833        newFont->incUserRef();
834    }
835    return newFont;
836}
837
838RsFont rsi_FontCreateFromMemory(Context *rsc, char const *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
839    Font *newFont = Font::create(rsc, name, fontSize, dpi, data, dataLen);
840    if (newFont) {
841        newFont->incUserRef();
842    }
843    return newFont;
844}
845
846} // renderscript
847} // android
848