rsFont.cpp revision 35b96445f8bb4536e29ace64417710ed90527a56
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#ifndef ANDROID_RS_BUILD_FOR_HOST 19#include "rsContext.h" 20#else 21#include "rsContextHostStub.h" 22#endif 23 24#include "rsFont.h" 25#include "rsProgramFragment.h" 26#include FT_BITMAP_H 27 28#include <GLES/gl.h> 29#include <GLES/glext.h> 30#include <GLES2/gl2.h> 31#include <GLES2/gl2ext.h> 32 33using namespace android; 34using namespace android::renderscript; 35 36Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) 37{ 38 mAllocFile = __FILE__; 39 mAllocLine = __LINE__; 40 mInitialized = false; 41 mHasKerning = false; 42 mFace = NULL; 43} 44 45bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) 46{ 47 if(mInitialized) { 48 LOGE("Reinitialization of fonts not supported"); 49 return false; 50 } 51 52 String8 fontsDir("/fonts/"); 53 String8 fullPath(getenv("ANDROID_ROOT")); 54 fullPath += fontsDir; 55 fullPath += name; 56 57 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace); 58 if(error) { 59 LOGE("Unable to initialize font %s", fullPath.string()); 60 return false; 61 } 62 63 mFontName = name; 64 mFontSize = fontSize; 65 mDpi = dpi; 66 67 error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0); 68 if(error) { 69 LOGE("Unable to set font size on %s", fullPath.string()); 70 return false; 71 } 72 73 mHasKerning = FT_HAS_KERNING(mFace); 74 75 mInitialized = true; 76 return true; 77} 78 79void Font::invalidateTextureCache() 80{ 81 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { 82 mCachedGlyphs.valueAt(i)->mIsValid = false; 83 } 84} 85 86void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y) 87{ 88 FontState *state = &mRSC->mStateFont; 89 90 int nPenX = x + glyph->mBitmapLeft; 91 int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight; 92 93 state->appendMeshQuad(nPenX, nPenY, 0, 94 glyph->mBitmapMinU, glyph->mBitmapMaxV, 95 96 nPenX + (int)glyph->mBitmapWidth, nPenY, 0, 97 glyph->mBitmapMaxU, glyph->mBitmapMaxV, 98 99 nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0, 100 glyph->mBitmapMaxU, glyph->mBitmapMinV, 101 102 nPenX, nPenY - (int)glyph->mBitmapHeight, 0, 103 glyph->mBitmapMinU, glyph->mBitmapMinV); 104} 105 106void Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y) 107{ 108 if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) { 109 return; 110 } 111 112 int penX = x, penY = y; 113 int glyphsLeft = 1; 114 if(numGlyphs > 0) { 115 glyphsLeft = numGlyphs; 116 } 117 118 size_t index = start; 119 size_t nextIndex = 0; 120 121 while (glyphsLeft > 0) { 122 123 int32_t utfChar = utf32_at(text, len, index, &nextIndex); 124 125 // Reached the end of the string or encountered 126 if(utfChar < 0) { 127 break; 128 } 129 130 // Move to the next character in the array 131 index = nextIndex; 132 133 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar); 134 135 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 136 if(cachedGlyph->mIsValid) { 137 drawCachedGlyph(cachedGlyph, penX, penY); 138 } 139 140 penX += (cachedGlyph->mAdvance.x >> 6); 141 142 // If we were given a specific number of glyphs, decrement 143 if(numGlyphs > 0) { 144 glyphsLeft --; 145 } 146 } 147} 148 149Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) { 150 151 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar); 152 if(cachedGlyph == NULL) { 153 cachedGlyph = cacheGlyph((uint32_t)utfChar); 154 } 155 // Is the glyph still in texture cache? 156 if(!cachedGlyph->mIsValid) { 157 updateGlyphCache(cachedGlyph); 158 } 159 160 return cachedGlyph; 161} 162 163void Font::updateGlyphCache(CachedGlyphInfo *glyph) 164{ 165 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER ); 166 if(error) { 167 LOGE("Couldn't load glyph."); 168 return; 169 } 170 171 glyph->mAdvance = mFace->glyph->advance; 172 glyph->mBitmapLeft = mFace->glyph->bitmap_left; 173 glyph->mBitmapTop = mFace->glyph->bitmap_top; 174 175 FT_Bitmap *bitmap = &mFace->glyph->bitmap; 176 177 // Now copy the bitmap into the cache texture 178 uint32_t startX = 0; 179 uint32_t startY = 0; 180 181 // Let the font state figure out where to put the bitmap 182 FontState *state = &mRSC->mStateFont; 183 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY); 184 185 if(!glyph->mIsValid) { 186 return; 187 } 188 189 uint32_t endX = startX + bitmap->width; 190 uint32_t endY = startY + bitmap->rows; 191 192 glyph->mBitmapMinX = startX; 193 glyph->mBitmapMinY = startY; 194 glyph->mBitmapWidth = bitmap->width; 195 glyph->mBitmapHeight = bitmap->rows; 196 197 uint32_t cacheWidth = state->getCacheTextureType()->getDimX(); 198 uint32_t cacheHeight = state->getCacheTextureType()->getDimY(); 199 200 glyph->mBitmapMinU = (float)startX / (float)cacheWidth; 201 glyph->mBitmapMinV = (float)startY / (float)cacheHeight; 202 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth; 203 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight; 204} 205 206Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) 207{ 208 CachedGlyphInfo *newGlyph = new CachedGlyphInfo(); 209 mCachedGlyphs.add(glyph, newGlyph); 210 211 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph); 212 newGlyph->mIsValid = false; 213 214 updateGlyphCache(newGlyph); 215 216 return newGlyph; 217} 218 219Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi) 220{ 221 rsc->mStateFont.checkInit(); 222 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts; 223 224 for(uint32_t i = 0; i < activeFonts.size(); i ++) { 225 Font *ithFont = activeFonts[i]; 226 if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) { 227 return ithFont; 228 } 229 } 230 231 Font *newFont = new Font(rsc); 232 bool isInitialized = newFont->init(name, fontSize, dpi); 233 if(isInitialized) { 234 activeFonts.push(newFont); 235 rsc->mStateFont.precacheLatin(newFont); 236 return newFont; 237 } 238 239 delete newFont; 240 return NULL; 241 242} 243 244Font::~Font() 245{ 246 if(mFace) { 247 FT_Done_Face(mFace); 248 } 249 250 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) { 251 if (mRSC->mStateFont.mActiveFonts[ct] == this) { 252 mRSC->mStateFont.mActiveFonts.removeAt(ct); 253 break; 254 } 255 } 256 257 for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { 258 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i); 259 delete glyph; 260 } 261} 262 263FontState::FontState() 264{ 265 mInitialized = false; 266 mMaxNumberOfQuads = 1024; 267 mCurrentQuadIndex = 0; 268 mRSC = NULL; 269 mLibrary = NULL; 270 setFontColor(0.1f, 0.1f, 0.1f, 1.0f); 271} 272 273FontState::~FontState() 274{ 275 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 276 delete mCacheLines[i]; 277 } 278 279 rsAssert(!mActiveFonts.size()); 280} 281 282FT_Library FontState::getLib() 283{ 284 if(!mLibrary) { 285 FT_Error error = FT_Init_FreeType(&mLibrary); 286 if(error) { 287 LOGE("Unable to initialize freetype"); 288 return NULL; 289 } 290 } 291 292 return mLibrary; 293} 294 295void FontState::init(Context *rsc) 296{ 297 mRSC = rsc; 298} 299 300void FontState::flushAllAndInvalidate() 301{ 302 if(mCurrentQuadIndex != 0) { 303 issueDrawCommand(); 304 mCurrentQuadIndex = 0; 305 } 306 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) { 307 mActiveFonts[i]->invalidateTextureCache(); 308 } 309 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 310 mCacheLines[i]->mCurrentCol = 0; 311 } 312} 313 314bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) 315{ 316 // If the glyph is too tall, don't cache it 317 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) { 318 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); 319 return false; 320 } 321 322 // Now copy the bitmap into the cache texture 323 uint32_t startX = 0; 324 uint32_t startY = 0; 325 326 bool bitmapFit = false; 327 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 328 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); 329 if(bitmapFit) { 330 break; 331 } 332 } 333 334 // If the new glyph didn't fit, flush the state so far and invalidate everything 335 if(!bitmapFit) { 336 flushAllAndInvalidate(); 337 338 // Try to fit it again 339 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 340 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); 341 if(bitmapFit) { 342 break; 343 } 344 } 345 346 // if we still don't fit, something is wrong and we shouldn't draw 347 if(!bitmapFit) { 348 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); 349 return false; 350 } 351 } 352 353 *retOriginX = startX; 354 *retOriginY = startY; 355 356 uint32_t endX = startX + bitmap->width; 357 uint32_t endY = startY + bitmap->rows; 358 359 uint32_t cacheWidth = getCacheTextureType()->getDimX(); 360 361 unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr(); 362 unsigned char *bitmapBuffer = bitmap->buffer; 363 364 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 365 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) { 366 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) { 367 unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX]; 368 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol; 369 } 370 } 371 372 // This will dirty the texture and the shader so next time 373 // we draw it will upload the data 374 mTextTexture->deferedUploadToTexture(mRSC, false, 0); 375 mFontShaderF->bindTexture(0, mTextTexture.get()); 376 377 // Some debug code 378 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 379 LOGE("Cache Line: H: %u Empty Space: %f", 380 mCacheLines[i]->mMaxHeight, 381 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f); 382 383 }*/ 384 385 return true; 386} 387 388void FontState::initRenderState() 389{ 390 uint32_t tmp[] = { 391 RS_TEX_ENV_MODE_REPLACE, 1, 392 RS_TEX_ENV_MODE_NONE, 0, 393 0, 0 394 }; 395 ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 6); 396 mFontShaderF.set(pf); 397 mFontShaderF->init(mRSC); 398 399 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST, 400 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP); 401 mFontSampler.set(sampler); 402 mFontShaderF->bindSampler(0, sampler); 403 404 ProgramStore *fontStore = new ProgramStore(mRSC); 405 mFontProgramStore.set(fontStore); 406 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS); 407 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA); 408 mFontProgramStore->setDitherEnable(false); 409 mFontProgramStore->setDepthMask(false); 410} 411 412void FontState::initTextTexture() 413{ 414 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1); 415 416 // We will allocate a texture to initially hold 32 character bitmaps 417 Type *texType = new Type(mRSC); 418 texType->setElement(alphaElem); 419 texType->setDimX(1024); 420 texType->setDimY(256); 421 texType->compute(); 422 423 Allocation *cacheAlloc = new Allocation(mRSC, texType); 424 mTextTexture.set(cacheAlloc); 425 mTextTexture->deferedUploadToTexture(mRSC, false, 0); 426 427 // Split up our cache texture into lines of certain widths 428 int nextLine = 0; 429 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0)); 430 nextLine += mCacheLines.top()->mMaxHeight; 431 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); 432 nextLine += mCacheLines.top()->mMaxHeight; 433 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); 434 nextLine += mCacheLines.top()->mMaxHeight; 435 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); 436 nextLine += mCacheLines.top()->mMaxHeight; 437 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); 438 nextLine += mCacheLines.top()->mMaxHeight; 439 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0)); 440 nextLine += mCacheLines.top()->mMaxHeight; 441 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0)); 442} 443 444// Avoid having to reallocate memory and render quad by quad 445void FontState::initVertexArrayBuffers() 446{ 447 // Now lets write index data 448 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1); 449 Type *indexType = new Type(mRSC); 450 uint32_t numIndicies = mMaxNumberOfQuads * 6; 451 indexType->setDimX(numIndicies); 452 indexType->setElement(indexElem); 453 indexType->compute(); 454 455 Allocation *indexAlloc = new Allocation(mRSC, indexType); 456 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr(); 457 458 // Four verts, two triangles , six indices per quad 459 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) { 460 int i6 = i * 6; 461 int i4 = i * 4; 462 463 indexPtr[i6 + 0] = i4 + 0; 464 indexPtr[i6 + 1] = i4 + 1; 465 indexPtr[i6 + 2] = i4 + 2; 466 467 indexPtr[i6 + 3] = i4 + 0; 468 indexPtr[i6 + 4] = i4 + 2; 469 indexPtr[i6 + 5] = i4 + 3; 470 } 471 472 indexAlloc->deferedUploadToBufferObject(mRSC); 473 mIndexBuffer.set(indexAlloc); 474 475 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); 476 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2); 477 478 const Element *elemArray[2]; 479 elemArray[0] = posElem; 480 elemArray[1] = texElem; 481 482 String8 posName("position"); 483 String8 texName("texture0"); 484 485 const char *nameArray[2]; 486 nameArray[0] = posName.string(); 487 nameArray[1] = texName.string(); 488 size_t lengths[2]; 489 lengths[0] = posName.size(); 490 lengths[1] = texName.size(); 491 492 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths); 493 494 Type *vertexDataType = new Type(mRSC); 495 vertexDataType->setDimX(mMaxNumberOfQuads * 4); 496 vertexDataType->setElement(vertexDataElem); 497 vertexDataType->compute(); 498 499 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType); 500 mTextMeshPtr = (float*)vertexAlloc->getPtr(); 501 502 mVertexArray.set(vertexAlloc); 503} 504 505// We don't want to allocate anything unless we actually draw text 506void FontState::checkInit() 507{ 508 if(mInitialized) { 509 return; 510 } 511 512 initTextTexture(); 513 initRenderState(); 514 515 initVertexArrayBuffers(); 516 517 // We store a string with letters in a rough frequency of occurrence 518 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq"); 519 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ"); 520 mLatinPrecache += String8(",.?!()-+@;:`'"); 521 mLatinPrecache += String8("0123456789"); 522 523 mInitialized = true; 524} 525 526void FontState::issueDrawCommand() { 527 528 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex()); 529 mRSC->setVertex(mRSC->getDefaultProgramVertex()); 530 531 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster()); 532 mRSC->setRaster(mRSC->getDefaultProgramRaster()); 533 534 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment()); 535 mRSC->setFragment(mFontShaderF.get()); 536 537 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore()); 538 mRSC->setFragmentStore(mFontProgramStore.get()); 539 540 if(mFontColorDirty) { 541 mFontShaderF->setConstantColor(mFontColor[0], mFontColor[1], mFontColor[2], mFontColor[3]); 542 mFontColorDirty = false; 543 } 544 545 if (!mRSC->setupCheck()) { 546 mRSC->setVertex((ProgramVertex *)tmpV.get()); 547 mRSC->setRaster((ProgramRaster *)tmpR.get()); 548 mRSC->setFragment((ProgramFragment *)tmpF.get()); 549 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 550 return; 551 } 552 553 float *vtx = (float*)mVertexArray->getPtr(); 554 float *tex = vtx + 3; 555 556 VertexArray va; 557 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position"); 558 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0"); 559 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache); 560 561 mIndexBuffer->uploadCheck(mRSC); 562 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); 563 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0)); 564 565 // Reset the state 566 mRSC->setVertex((ProgramVertex *)tmpV.get()); 567 mRSC->setRaster((ProgramRaster *)tmpR.get()); 568 mRSC->setFragment((ProgramFragment *)tmpF.get()); 569 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 570} 571 572void FontState::appendMeshQuad(float x1, float y1, float z1, 573 float u1, float v1, 574 float x2, float y2, float z2, 575 float u2, float v2, 576 float x3, float y3, float z3, 577 float u3, float v3, 578 float x4, float y4, float z4, 579 float u4, float v4) 580{ 581 const uint32_t vertsPerQuad = 4; 582 const uint32_t floatsPerVert = 5; 583 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 584 585 // Cull things that are off the screen 586 float width = (float)mRSC->getWidth(); 587 float height = (float)mRSC->getHeight(); 588 589 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) { 590 return; 591 } 592 593 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1); 594 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2); 595 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3); 596 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/ 597 598 (*currentPos++) = x1; 599 (*currentPos++) = y1; 600 (*currentPos++) = z1; 601 (*currentPos++) = u1; 602 (*currentPos++) = v1; 603 604 (*currentPos++) = x2; 605 (*currentPos++) = y2; 606 (*currentPos++) = z2; 607 (*currentPos++) = u2; 608 (*currentPos++) = v2; 609 610 (*currentPos++) = x3; 611 (*currentPos++) = y3; 612 (*currentPos++) = z3; 613 (*currentPos++) = u3; 614 (*currentPos++) = v3; 615 616 (*currentPos++) = x4; 617 (*currentPos++) = y4; 618 (*currentPos++) = z4; 619 (*currentPos++) = u4; 620 (*currentPos++) = v4; 621 622 mCurrentQuadIndex ++; 623 624 if(mCurrentQuadIndex == mMaxNumberOfQuads) { 625 issueDrawCommand(); 626 mCurrentQuadIndex = 0; 627 } 628} 629 630uint32_t FontState::getRemainingCacheCapacity() { 631 uint32_t remainingCapacity = 0; 632 uint32_t totalPixels = 0; 633 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 634 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 635 totalPixels += mCacheLines[i]->mMaxWidth; 636 } 637 remainingCapacity = (remainingCapacity * 100) / totalPixels; 638 return remainingCapacity; 639} 640 641void FontState::precacheLatin(Font *font) { 642 // Remaining capacity is measured in % 643 uint32_t remainingCapacity = getRemainingCacheCapacity(); 644 uint32_t precacheIdx = 0; 645 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { 646 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]); 647 remainingCapacity = getRemainingCacheCapacity(); 648 precacheIdx ++; 649 } 650} 651 652 653void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y) 654{ 655 checkInit(); 656 657 // Render code here 658 Font *currentFont = mRSC->getFont(); 659 if(!currentFont) { 660 if(!mDefault.get()) { 661 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96)); 662 } 663 currentFont = mDefault.get(); 664 } 665 if(!currentFont) { 666 LOGE("Unable to initialize any fonts"); 667 return; 668 } 669 670 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y); 671 672 if(mCurrentQuadIndex != 0) { 673 issueDrawCommand(); 674 mCurrentQuadIndex = 0; 675 } 676} 677 678void FontState::renderText(const char *text, int x, int y) 679{ 680 size_t textLen = strlen(text); 681 renderText(text, textLen, 0, -1, x, y); 682} 683 684void FontState::renderText(Allocation *alloc, int x, int y) 685{ 686 if(!alloc) { 687 return; 688 } 689 690 const char *text = (const char *)alloc->getPtr(); 691 size_t allocSize = alloc->getType()->getSizeBytes(); 692 renderText(text, allocSize, 0, -1, x, y); 693} 694 695void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y) 696{ 697 if(!alloc) { 698 return; 699 } 700 701 const char *text = (const char *)alloc->getPtr(); 702 size_t allocSize = alloc->getType()->getSizeBytes(); 703 renderText(text, allocSize, start, len, x, y); 704} 705 706void FontState::setFontColor(float r, float g, float b, float a) { 707 mFontColor[0] = r; 708 mFontColor[1] = g; 709 mFontColor[2] = b; 710 mFontColor[3] = a; 711 mFontColorDirty = true; 712} 713 714void FontState::getFontColor(float *r, float *g, float *b, float *a) const { 715 *r = mFontColor[0]; 716 *g = mFontColor[1]; 717 *b = mFontColor[2]; 718 *a = mFontColor[3]; 719} 720 721void FontState::deinit(Context *rsc) 722{ 723 mInitialized = false; 724 725 mIndexBuffer.clear(); 726 mVertexArray.clear(); 727 728 mFontShaderF.clear(); 729 mFontSampler.clear(); 730 mFontProgramStore.clear(); 731 732 mTextTexture.clear(); 733 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 734 delete mCacheLines[i]; 735 } 736 mCacheLines.clear(); 737 738 mDefault.clear(); 739 740 Vector<Font*> fontsToDereference = mActiveFonts; 741 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) { 742 fontsToDereference[i]->zeroUserRef(); 743 } 744 745 if(mLibrary) { 746 FT_Done_FreeType( mLibrary ); 747 mLibrary = NULL; 748 } 749} 750 751namespace android { 752namespace renderscript { 753 754RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) 755{ 756 Font *newFont = Font::create(rsc, name, fontSize, dpi); 757 if(newFont) { 758 newFont->incUserRef(); 759 } 760 return newFont; 761} 762 763} // renderscript 764} // android 765