• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = NULL;
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 != NULL && 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 == NULL || len == 0) {
166         return;
167     }
168 
169     if (mode == Font::MEASURE) {
170         if (bounds == NULL) {
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 == NULL) {
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 NULL;
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 = NULL;
338 #ifndef ANDROID_RS_SERIALIZE
339     mLibrary = NULL;
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, NULL) > 0) {
352         gamma = atof(property);
353     }
354 
355     // Get the black gamma threshold
356     if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
357         blackThreshold = atoi(property);
358     }
359 
360     // Get the white gamma threshold
361     if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 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 NULL;
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 
516     ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false, 0);
517 
518     uint32_t tmp[4];
519     tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
520     tmp[1] = (uint32_t)inputType.get();
521     tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
522     tmp[3] = RS_TEXTURE_2D;
523 
524     mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
525                                                           RS_ALLOCATION_USAGE_SCRIPT |
526                                                           RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
527     ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
528                                               textureNames, numTextures, textureNamesLengths,
529                                               tmp, 4);
530     mFontShaderF.set(pf);
531     mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
532 
533     mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
534                                          RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
535                                          RS_SAMPLER_CLAMP).get());
536     mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
537 
538     mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
539                                                         false, false,
540                                                         RS_BLEND_SRC_SRC_ALPHA,
541                                                         RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
542                                                         RS_DEPTH_FUNC_ALWAYS).get());
543     mFontProgramStore->init();
544 }
545 
initTextTexture()546 void FontState::initTextTexture() {
547     ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
548                                                                 RS_KIND_PIXEL_A, true, 1);
549 
550     // We will allocate a texture to initially hold 32 character bitmaps
551     mCacheHeight = 256;
552     mCacheWidth = 1024;
553     ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
554                                                    mCacheWidth, mCacheHeight, 0, false, false, 0);
555     mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
556 
557 
558     Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
559                                 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
560     mTextTexture.set(cacheAlloc);
561 
562     // Split up our cache texture into lines of certain widths
563     int32_t nextLine = 0;
564     mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
565     nextLine += mCacheLines.top()->mMaxHeight;
566     mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
567     nextLine += mCacheLines.top()->mMaxHeight;
568     mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
569     nextLine += mCacheLines.top()->mMaxHeight;
570     mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
571     nextLine += mCacheLines.top()->mMaxHeight;
572     mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
573     nextLine += mCacheLines.top()->mMaxHeight;
574     mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
575     nextLine += mCacheLines.top()->mMaxHeight;
576     mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
577 }
578 
579 // Avoid having to reallocate memory and render quad by quad
initVertexArrayBuffers()580 void FontState::initVertexArrayBuffers() {
581     // Now lets write index data
582     ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
583     uint32_t numIndicies = mMaxNumberOfQuads * 6;
584     ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false, 0);
585 
586     Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
587                                                           RS_ALLOCATION_USAGE_SCRIPT |
588                                                           RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
589     uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
590 
591     // Four verts, two triangles , six indices per quad
592     for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
593         int32_t i6 = i * 6;
594         int32_t i4 = i * 4;
595 
596         indexPtr[i6 + 0] = i4 + 0;
597         indexPtr[i6 + 1] = i4 + 1;
598         indexPtr[i6 + 2] = i4 + 2;
599 
600         indexPtr[i6 + 3] = i4 + 0;
601         indexPtr[i6 + 4] = i4 + 2;
602         indexPtr[i6 + 5] = i4 + 3;
603     }
604 
605     indexAlloc->sendDirty(mRSC);
606 
607     ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
608     ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
609 
610     const char *ebn1[] = { "position", "texture0" };
611     const Element *ebe1[] = {posElem.get(), texElem.get()};
612     ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
613 
614     ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
615                                                           mMaxNumberOfQuads * 4,
616                                                           0, 0, false, false, 0);
617 
618     Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
619                                                            RS_ALLOCATION_USAGE_SCRIPT);
620     mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
621 
622     mMesh.set(new Mesh(mRSC, 1, 1));
623     mMesh->setVertexBuffer(vertexAlloc, 0);
624     mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
625     mMesh->init();
626     mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
627     mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
628 }
629 
630 // We don't want to allocate anything unless we actually draw text
checkInit()631 void FontState::checkInit() {
632     if (mInitialized) {
633         return;
634     }
635 
636     initTextTexture();
637     initRenderState();
638 
639     initVertexArrayBuffers();
640 
641     // We store a string with letters in a rough frequency of occurrence
642     mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
643                      "EISARNTOLCDUGPMHBYFVKWZXJQ"
644                      ",.?!()-+@;:`'0123456789";
645     mInitialized = true;
646 }
647 
issueDrawCommand()648 void FontState::issueDrawCommand() {
649     Context::PushState ps(mRSC);
650 
651     mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
652     mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
653     mRSC->setProgramFragment(mFontShaderF.get());
654     mRSC->setProgramStore(mFontProgramStore.get());
655 
656     if (mConstantsDirty) {
657         mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
658         mConstantsDirty = false;
659     }
660 
661     if (!mRSC->setupCheck()) {
662         return;
663     }
664 
665     mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
666 }
667 
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)668 void FontState::appendMeshQuad(float x1, float y1, float z1,
669                                float u1, float v1,
670                                float x2, float y2, float z2,
671                                float u2, float v2,
672                                float x3, float y3, float z3,
673                                float u3, float v3,
674                                float x4, float y4, float z4,
675                                float u4, float v4) {
676     const uint32_t vertsPerQuad = 4;
677     const uint32_t floatsPerVert = 6;
678     float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
679 
680     if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
681         return;
682     }
683 
684     /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
685     ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
686     ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
687     ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
688 
689     (*currentPos++) = x1;
690     (*currentPos++) = y1;
691     (*currentPos++) = z1;
692     (*currentPos++) = 0;
693     (*currentPos++) = u1;
694     (*currentPos++) = v1;
695 
696     (*currentPos++) = x2;
697     (*currentPos++) = y2;
698     (*currentPos++) = z2;
699     (*currentPos++) = 0;
700     (*currentPos++) = u2;
701     (*currentPos++) = v2;
702 
703     (*currentPos++) = x3;
704     (*currentPos++) = y3;
705     (*currentPos++) = z3;
706     (*currentPos++) = 0;
707     (*currentPos++) = u3;
708     (*currentPos++) = v3;
709 
710     (*currentPos++) = x4;
711     (*currentPos++) = y4;
712     (*currentPos++) = z4;
713     (*currentPos++) = 0;
714     (*currentPos++) = u4;
715     (*currentPos++) = v4;
716 
717     mCurrentQuadIndex ++;
718 
719     if (mCurrentQuadIndex == mMaxNumberOfQuads) {
720         issueDrawCommand();
721         mCurrentQuadIndex = 0;
722     }
723 }
724 
getRemainingCacheCapacity()725 uint32_t FontState::getRemainingCacheCapacity() {
726     uint32_t remainingCapacity = 0;
727     uint32_t totalPixels = 0;
728     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
729          remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
730          totalPixels += mCacheLines[i]->mMaxWidth;
731     }
732     remainingCapacity = (remainingCapacity * 100) / totalPixels;
733     return remainingCapacity;
734 }
735 
precacheLatin(Font * font)736 void FontState::precacheLatin(Font *font) {
737     // Remaining capacity is measured in %
738     uint32_t remainingCapacity = getRemainingCacheCapacity();
739     uint32_t precacheIdx = 0;
740     const size_t l = strlen(mLatinPrecache);
741     while ((remainingCapacity > 25) && (precacheIdx < l)) {
742         font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
743         remainingCapacity = getRemainingCacheCapacity();
744         precacheIdx ++;
745     }
746 }
747 
748 
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)749 void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
750                            uint32_t startIndex, int32_t numGlyphs,
751                            Font::RenderMode mode,
752                            Font::Rect *bounds,
753                            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
754     checkInit();
755 
756     // Render code here
757     Font *currentFont = mRSC->getFont();
758     if (!currentFont) {
759         if (!mDefault.get()) {
760             char fullPath[1024];
761             const char * root = getenv("ANDROID_ROOT");
762             rsAssert(strlen(root) < 256);
763             strcpy(fullPath, root);
764             strcat(fullPath, "/fonts/Roboto-Regular.ttf");
765             mDefault.set(Font::create(mRSC, fullPath, 8, mRSC->getDPI()));
766         }
767         currentFont = mDefault.get();
768     }
769     if (!currentFont) {
770         ALOGE("Unable to initialize any fonts");
771         return;
772     }
773 
774     // Cull things that are off the screen
775     mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
776     mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
777 
778     currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
779                            mode, bounds, bitmap, bitmapW, bitmapH);
780 
781     if (mCurrentQuadIndex != 0) {
782         issueDrawCommand();
783         mCurrentQuadIndex = 0;
784     }
785 }
786 
measureText(const char * text,uint32_t len,Font::Rect * bounds)787 void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
788     renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
789     bounds->bottom = - bounds->bottom;
790     bounds->top = - bounds->top;
791 }
792 
setFontColor(float r,float g,float b,float a)793 void FontState::setFontColor(float r, float g, float b, float a) {
794     mConstants.mFontColor[0] = r;
795     mConstants.mFontColor[1] = g;
796     mConstants.mFontColor[2] = b;
797     mConstants.mFontColor[3] = a;
798 
799     mConstants.mGamma = 1.0f;
800     const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
801     if (luminance <= mBlackThreshold) {
802         mConstants.mGamma = mBlackGamma;
803     } else if (luminance >= mWhiteThreshold) {
804         mConstants.mGamma = mWhiteGamma;
805     }
806 
807     mConstantsDirty = true;
808 }
809 
getFontColor(float * r,float * g,float * b,float * a) const810 void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
811     *r = mConstants.mFontColor[0];
812     *g = mConstants.mFontColor[1];
813     *b = mConstants.mFontColor[2];
814     *a = mConstants.mFontColor[3];
815 }
816 
deinit(Context * rsc)817 void FontState::deinit(Context *rsc) {
818     mInitialized = false;
819 
820     mFontShaderFConstant.clear();
821 
822     mMesh.clear();
823 
824     mFontShaderF.clear();
825     mFontSampler.clear();
826     mFontProgramStore.clear();
827 
828     mTextTexture.clear();
829     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
830         delete mCacheLines[i];
831     }
832     mCacheLines.clear();
833 
834     mDefault.clear();
835 #ifndef ANDROID_RS_SERIALIZE
836     if (mLibrary) {
837         FT_Done_FreeType( mLibrary );
838         mLibrary = NULL;
839     }
840 #endif //ANDROID_RS_SERIALIZE
841 }
842 
843 #ifndef ANDROID_RS_SERIALIZE
fitBitmap(FT_Bitmap_ * bitmap,uint32_t * retOriginX,uint32_t * retOriginY)844 bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
845     if ((uint32_t)bitmap->rows > mMaxHeight) {
846         return false;
847     }
848 
849     if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
850         *retOriginX = mCurrentCol;
851         *retOriginY = mCurrentRow;
852         mCurrentCol += bitmap->width;
853         mDirty = true;
854        return true;
855     }
856 
857     return false;
858 }
859 #endif //ANDROID_RS_SERIALIZE
860 
861 namespace android {
862 namespace renderscript {
863 
rsi_FontCreateFromFile(Context * rsc,char const * name,size_t name_length,float fontSize,uint32_t dpi)864 RsFont rsi_FontCreateFromFile(Context *rsc,
865                               char const *name, size_t name_length,
866                               float fontSize, uint32_t dpi) {
867     Font *newFont = Font::create(rsc, name, fontSize, dpi);
868     if (newFont) {
869         newFont->incUserRef();
870     }
871     return newFont;
872 }
873 
rsi_FontCreateFromMemory(Context * rsc,char const * name,size_t name_length,float fontSize,uint32_t dpi,const void * data,size_t data_length)874 RsFont rsi_FontCreateFromMemory(Context *rsc,
875                                 char const *name, size_t name_length,
876                                 float fontSize, uint32_t dpi,
877                                 const void *data, size_t data_length) {
878     Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
879     if (newFont) {
880         newFont->incUserRef();
881     }
882     return newFont;
883 }
884 
885 } // renderscript
886 } // android
887