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