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