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