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