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 36 Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) { 37 mInitialized = false; 38 mHasKerning = false; 39 mFace = NULL; 40 } 41 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 78 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 87 void Font::invalidateTextureCache() { 88 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { 89 mCachedGlyphs.valueAt(i)->mIsValid = false; 90 } 91 } 92 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 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 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 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 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 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 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 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 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 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 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 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 398 void FontState::init(Context *rsc) { 399 mRSC = rsc; 400 } 401 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 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 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 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 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 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 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 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 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 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 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 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 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 810 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 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 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 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 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