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