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 HAVE_ANDROID_OS
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 
33 using namespace android;
34 using namespace android::renderscript;
35 
Font(Context * rsc)36 Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
37     mInitialized = false;
38     mHasKerning = false;
39     mFace = nullptr;
40 }
41 
init(const char * name,float fontSize,uint32_t dpi,const void * data,uint32_t dataLen)42 bool 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 
preDestroy() const78 void 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 
invalidateTextureCache()87 void Font::invalidateTextureCache() {
88     for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
89         mCachedGlyphs.valueAt(i)->mIsValid = false;
90     }
91 }
92 
drawCachedGlyph(CachedGlyphInfo * glyph,int32_t x,int32_t y)93 void 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 
drawCachedGlyph(CachedGlyphInfo * glyph,int32_t x,int32_t y,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH)113 void 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 
measureCachedGlyph(CachedGlyphInfo * glyph,int32_t x,int32_t y,Rect * bounds)139 void 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 
renderUTF(const char * text,uint32_t len,int32_t x,int32_t y,uint32_t start,int32_t numGlyphs,RenderMode mode,Rect * bounds,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH)161 void 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 
getCachedUTFChar(int32_t utfChar)225 Font::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 
updateGlyphCache(CachedGlyphInfo * glyph)239 void 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 
cacheGlyph(uint32_t glyph)284 Font::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 
create(Context * rsc,const char * name,float fontSize,uint32_t dpi,const void * data,uint32_t dataLen)296 Font * 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 
~Font()320 Font::~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 
FontState()333 FontState::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 HAVE_ANDROID_OS
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 
~FontState()376 FontState::~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
getLib()384 FT_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 
init(Context * rsc)398 void FontState::init(Context *rsc) {
399     mRSC = rsc;
400 }
401 
flushAllAndInvalidate()402 void 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
cacheBitmap(FT_Bitmap * bitmap,uint32_t * retOriginX,uint32_t * retOriginY)416 bool 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 
initRenderState()494 void 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 
initTextTexture()545 void 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
initVertexArrayBuffers()579 void 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
checkInit()627 void 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 
issueDrawCommand()644 void 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 
appendMeshQuad(float x1,float y1,float z1,float u1,float v1,float x2,float y2,float z2,float u2,float v2,float x3,float y3,float z3,float u3,float v3,float x4,float y4,float z4,float u4,float v4)664 void 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 
getRemainingCacheCapacity()721 uint32_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 
precacheLatin(Font * font)732 void 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 
renderText(const char * text,uint32_t len,int32_t x,int32_t y,uint32_t startIndex,int32_t numGlyphs,Font::RenderMode mode,Font::Rect * bounds,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH)745 void 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 
measureText(const char * text,uint32_t len,Font::Rect * bounds)783 void 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 
setFontColor(float r,float g,float b,float a)789 void 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 
getFontColor(float * r,float * g,float * b,float * a) const806 void 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 
deinit(Context * rsc)813 void 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
fitBitmap(FT_Bitmap_ * bitmap,uint32_t * retOriginX,uint32_t * retOriginY)840 bool 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 
857 namespace android {
858 namespace renderscript {
859 
rsi_FontCreateFromFile(Context * rsc,char const * name,size_t name_length,float fontSize,uint32_t dpi)860 RsFont 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 
rsi_FontCreateFromMemory(Context * rsc,char const * name,size_t name_length,float fontSize,uint32_t dpi,const void * data,size_t data_length)870 RsFont 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