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