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