• 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 #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 
31 using namespace android;
32 using namespace android::renderscript;
33 
Font(Context * rsc)34 Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
35     mInitialized = false;
36     mHasKerning = false;
37     mFace = NULL;
38 }
39 
init(const char * name,float fontSize,uint32_t dpi,const void * data,uint32_t dataLen)40 bool 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 
preDestroy() const76 void 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 
invalidateTextureCache()85 void Font::invalidateTextureCache() {
86     for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
87         mCachedGlyphs.valueAt(i)->mIsValid = false;
88     }
89 }
90 
drawCachedGlyph(CachedGlyphInfo * glyph,int32_t x,int32_t y)91 void 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 
drawCachedGlyph(CachedGlyphInfo * glyph,int32_t x,int32_t y,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH)111 void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
112                            uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
113     int32_t nPenX = x + glyph->mBitmapLeft;
114     int32_t nPenY = y + glyph->mBitmapTop;
115 
116     uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
117     uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
118 
119     FontState *state = &mRSC->mStateFont;
120     uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
121     const uint8_t* cacheBuffer = state->getTextTextureData();
122 
123     uint32_t cacheX = 0, cacheY = 0;
124     int32_t bX = 0, bY = 0;
125     for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
126         for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
127             if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
128                 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 
measureCachedGlyph(CachedGlyphInfo * glyph,int32_t x,int32_t y,Rect * bounds)137 void 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 
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)159 void 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 
getCachedUTFChar(int32_t utfChar)223 Font::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 
updateGlyphCache(CachedGlyphInfo * glyph)237 void 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 
cacheGlyph(uint32_t glyph)282 Font::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 
create(Context * rsc,const char * name,float fontSize,uint32_t dpi,const void * data,uint32_t dataLen)294 Font * 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 
~Font()318 Font::~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 
FontState()331 FontState::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 
~FontState()370 FontState::~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
getLib()378 FT_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 
init(Context * rsc)392 void FontState::init(Context *rsc) {
393     mRSC = rsc;
394 }
395 
flushAllAndInvalidate()396 void 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
cacheBitmap(FT_Bitmap * bitmap,uint32_t * retOriginX,uint32_t * retOriginY)410 bool 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 = (uint8_t*)mTextTexture->getPtr();
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     mTextTexture->sendDirty(mRSC);
471     mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
472 
473     // Some debug code
474     /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
475         ALOGE("Cache Line: H: %u Empty Space: %f",
476              mCacheLines[i]->mMaxHeight,
477               (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
478 
479     }*/
480 
481     return true;
482 }
483 #endif //ANDROID_RS_SERIALIZE
484 
initRenderState()485 void FontState::initRenderState() {
486     String8 shaderString("varying vec2 varTex0;\n");
487     shaderString.append("void main() {\n");
488     shaderString.append("  lowp vec4 col = UNI_Color;\n");
489     shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
490     shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
491     shaderString.append("  gl_FragColor = col;\n");
492     shaderString.append("}\n");
493 
494     const char *textureNames[] = { "Tex0" };
495     const size_t textureNamesLengths[] = { 4 };
496     size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
497 
498     ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
499                                                                 RS_KIND_USER, false, 4);
500     ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
501                                                                 RS_KIND_USER, false, 1);
502     Element::Builder builder;
503     builder.add(colorElem.get(), "Color", 1);
504     builder.add(gammaElem.get(), "Gamma", 1);
505     ObjectBaseRef<const Element> constInput = builder.create(mRSC);
506 
507     ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false);
508 
509     uint32_t tmp[4];
510     tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
511     tmp[1] = (uint32_t)inputType.get();
512     tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
513     tmp[3] = RS_TEXTURE_2D;
514 
515     mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
516                                                           RS_ALLOCATION_USAGE_SCRIPT |
517                                                           RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
518     ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), shaderString.length(),
519                                               textureNames, numTextures, textureNamesLengths,
520                                               tmp, 4);
521     mFontShaderF.set(pf);
522     mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
523 
524     mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
525                                          RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
526                                          RS_SAMPLER_CLAMP).get());
527     mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
528 
529     mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
530                                                         false, false,
531                                                         RS_BLEND_SRC_SRC_ALPHA,
532                                                         RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
533                                                         RS_DEPTH_FUNC_ALWAYS).get());
534     mFontProgramStore->init();
535 }
536 
initTextTexture()537 void FontState::initTextTexture() {
538     ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
539                                                                 RS_KIND_PIXEL_A, true, 1);
540 
541     // We will allocate a texture to initially hold 32 character bitmaps
542     ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
543                                                    1024, 256, 0, false, false);
544 
545     Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
546                                 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
547     mTextTexture.set(cacheAlloc);
548     mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
549 
550     // Split up our cache texture into lines of certain widths
551     int32_t nextLine = 0;
552     mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
553     nextLine += mCacheLines.top()->mMaxHeight;
554     mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
555     nextLine += mCacheLines.top()->mMaxHeight;
556     mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
557     nextLine += mCacheLines.top()->mMaxHeight;
558     mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
559     nextLine += mCacheLines.top()->mMaxHeight;
560     mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
561     nextLine += mCacheLines.top()->mMaxHeight;
562     mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
563     nextLine += mCacheLines.top()->mMaxHeight;
564     mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
565 }
566 
567 // Avoid having to reallocate memory and render quad by quad
initVertexArrayBuffers()568 void FontState::initVertexArrayBuffers() {
569     // Now lets write index data
570     ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
571     uint32_t numIndicies = mMaxNumberOfQuads * 6;
572     ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false);
573 
574     Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
575                                                           RS_ALLOCATION_USAGE_SCRIPT |
576                                                           RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
577     uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
578 
579     // Four verts, two triangles , six indices per quad
580     for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
581         int32_t i6 = i * 6;
582         int32_t i4 = i * 4;
583 
584         indexPtr[i6 + 0] = i4 + 0;
585         indexPtr[i6 + 1] = i4 + 1;
586         indexPtr[i6 + 2] = i4 + 2;
587 
588         indexPtr[i6 + 3] = i4 + 0;
589         indexPtr[i6 + 4] = i4 + 2;
590         indexPtr[i6 + 5] = i4 + 3;
591     }
592 
593     indexAlloc->sendDirty(mRSC);
594 
595     ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
596     ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
597 
598     Element::Builder builder;
599     builder.add(posElem.get(), "position", 1);
600     builder.add(texElem.get(), "texture0", 1);
601     ObjectBaseRef<const Element> vertexDataElem = builder.create(mRSC);
602 
603     ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
604                                                           mMaxNumberOfQuads * 4,
605                                                           0, 0, false, false);
606 
607     Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
608                                                            RS_ALLOCATION_USAGE_SCRIPT);
609     mTextMeshPtr = (float*)vertexAlloc->getPtr();
610 
611     mMesh.set(new Mesh(mRSC, 1, 1));
612     mMesh->setVertexBuffer(vertexAlloc, 0);
613     mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
614     mMesh->init();
615 }
616 
617 // We don't want to allocate anything unless we actually draw text
checkInit()618 void FontState::checkInit() {
619     if (mInitialized) {
620         return;
621     }
622 
623     initTextTexture();
624     initRenderState();
625 
626     initVertexArrayBuffers();
627 
628     // We store a string with letters in a rough frequency of occurrence
629     mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
630     mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
631     mLatinPrecache += String8(",.?!()-+@;:`'");
632     mLatinPrecache += String8("0123456789");
633 
634     mInitialized = true;
635 }
636 
issueDrawCommand()637 void FontState::issueDrawCommand() {
638     Context::PushState ps(mRSC);
639 
640     mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
641     mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
642     mRSC->setProgramFragment(mFontShaderF.get());
643     mRSC->setProgramStore(mFontProgramStore.get());
644 
645     if (mConstantsDirty) {
646         mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
647         mConstantsDirty = false;
648     }
649 
650     if (!mRSC->setupCheck()) {
651         return;
652     }
653 
654     mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
655 }
656 
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)657 void FontState::appendMeshQuad(float x1, float y1, float z1,
658                                float u1, float v1,
659                                float x2, float y2, float z2,
660                                float u2, float v2,
661                                float x3, float y3, float z3,
662                                float u3, float v3,
663                                float x4, float y4, float z4,
664                                float u4, float v4) {
665     const uint32_t vertsPerQuad = 4;
666     const uint32_t floatsPerVert = 6;
667     float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
668 
669     if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
670         return;
671     }
672 
673     /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
674     ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
675     ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
676     ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
677 
678     (*currentPos++) = x1;
679     (*currentPos++) = y1;
680     (*currentPos++) = z1;
681     (*currentPos++) = 0;
682     (*currentPos++) = u1;
683     (*currentPos++) = v1;
684 
685     (*currentPos++) = x2;
686     (*currentPos++) = y2;
687     (*currentPos++) = z2;
688     (*currentPos++) = 0;
689     (*currentPos++) = u2;
690     (*currentPos++) = v2;
691 
692     (*currentPos++) = x3;
693     (*currentPos++) = y3;
694     (*currentPos++) = z3;
695     (*currentPos++) = 0;
696     (*currentPos++) = u3;
697     (*currentPos++) = v3;
698 
699     (*currentPos++) = x4;
700     (*currentPos++) = y4;
701     (*currentPos++) = z4;
702     (*currentPos++) = 0;
703     (*currentPos++) = u4;
704     (*currentPos++) = v4;
705 
706     mCurrentQuadIndex ++;
707 
708     if (mCurrentQuadIndex == mMaxNumberOfQuads) {
709         issueDrawCommand();
710         mCurrentQuadIndex = 0;
711     }
712 }
713 
getRemainingCacheCapacity()714 uint32_t FontState::getRemainingCacheCapacity() {
715     uint32_t remainingCapacity = 0;
716     uint32_t totalPixels = 0;
717     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
718          remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
719          totalPixels += mCacheLines[i]->mMaxWidth;
720     }
721     remainingCapacity = (remainingCapacity * 100) / totalPixels;
722     return remainingCapacity;
723 }
724 
precacheLatin(Font * font)725 void FontState::precacheLatin(Font *font) {
726     // Remaining capacity is measured in %
727     uint32_t remainingCapacity = getRemainingCacheCapacity();
728     uint32_t precacheIdx = 0;
729     while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
730         font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
731         remainingCapacity = getRemainingCacheCapacity();
732         precacheIdx ++;
733     }
734 }
735 
736 
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)737 void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
738                            uint32_t startIndex, int32_t numGlyphs,
739                            Font::RenderMode mode,
740                            Font::Rect *bounds,
741                            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
742     checkInit();
743 
744     // Render code here
745     Font *currentFont = mRSC->getFont();
746     if (!currentFont) {
747         if (!mDefault.get()) {
748             String8 fontsDir("/fonts/Roboto-Regular.ttf");
749             String8 fullPath(getenv("ANDROID_ROOT"));
750             fullPath += fontsDir;
751 
752             mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
753         }
754         currentFont = mDefault.get();
755     }
756     if (!currentFont) {
757         ALOGE("Unable to initialize any fonts");
758         return;
759     }
760 
761     // Cull things that are off the screen
762     mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
763     mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
764 
765     currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
766                            mode, bounds, bitmap, bitmapW, bitmapH);
767 
768     if (mCurrentQuadIndex != 0) {
769         issueDrawCommand();
770         mCurrentQuadIndex = 0;
771     }
772 }
773 
measureText(const char * text,uint32_t len,Font::Rect * bounds)774 void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
775     renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
776     bounds->bottom = - bounds->bottom;
777     bounds->top = - bounds->top;
778 }
779 
setFontColor(float r,float g,float b,float a)780 void FontState::setFontColor(float r, float g, float b, float a) {
781     mConstants.mFontColor[0] = r;
782     mConstants.mFontColor[1] = g;
783     mConstants.mFontColor[2] = b;
784     mConstants.mFontColor[3] = a;
785 
786     mConstants.mGamma = 1.0f;
787     const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
788     if (luminance <= mBlackThreshold) {
789         mConstants.mGamma = mBlackGamma;
790     } else if (luminance >= mWhiteThreshold) {
791         mConstants.mGamma = mWhiteGamma;
792     }
793 
794     mConstantsDirty = true;
795 }
796 
getFontColor(float * r,float * g,float * b,float * a) const797 void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
798     *r = mConstants.mFontColor[0];
799     *g = mConstants.mFontColor[1];
800     *b = mConstants.mFontColor[2];
801     *a = mConstants.mFontColor[3];
802 }
803 
deinit(Context * rsc)804 void FontState::deinit(Context *rsc) {
805     mInitialized = false;
806 
807     mFontShaderFConstant.clear();
808 
809     mMesh.clear();
810 
811     mFontShaderF.clear();
812     mFontSampler.clear();
813     mFontProgramStore.clear();
814 
815     mTextTexture.clear();
816     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
817         delete mCacheLines[i];
818     }
819     mCacheLines.clear();
820 
821     mDefault.clear();
822 #ifndef ANDROID_RS_SERIALIZE
823     if (mLibrary) {
824         FT_Done_FreeType( mLibrary );
825         mLibrary = NULL;
826     }
827 #endif //ANDROID_RS_SERIALIZE
828 }
829 
830 #ifndef ANDROID_RS_SERIALIZE
fitBitmap(FT_Bitmap_ * bitmap,uint32_t * retOriginX,uint32_t * retOriginY)831 bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
832     if ((uint32_t)bitmap->rows > mMaxHeight) {
833         return false;
834     }
835 
836     if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
837         *retOriginX = mCurrentCol;
838         *retOriginY = mCurrentRow;
839         mCurrentCol += bitmap->width;
840         mDirty = true;
841        return true;
842     }
843 
844     return false;
845 }
846 #endif //ANDROID_RS_SERIALIZE
847 
848 namespace android {
849 namespace renderscript {
850 
rsi_FontCreateFromFile(Context * rsc,char const * name,size_t name_length,float fontSize,uint32_t dpi)851 RsFont rsi_FontCreateFromFile(Context *rsc,
852                               char const *name, size_t name_length,
853                               float fontSize, uint32_t dpi) {
854     Font *newFont = Font::create(rsc, name, fontSize, dpi);
855     if (newFont) {
856         newFont->incUserRef();
857     }
858     return newFont;
859 }
860 
rsi_FontCreateFromMemory(Context * rsc,char const * name,size_t name_length,float fontSize,uint32_t dpi,const void * data,size_t data_length)861 RsFont rsi_FontCreateFromMemory(Context *rsc,
862                                 char const *name, size_t name_length,
863                                 float fontSize, uint32_t dpi,
864                                 const void *data, size_t data_length) {
865     Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
866     if (newFont) {
867         newFont->incUserRef();
868     }
869     return newFont;
870 }
871 
872 } // renderscript
873 } // android
874