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