rsFont.cpp revision 46e45548dc80e801139c9ccc2f2aa927e7f35027
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 uint32_t arraySizes[2] = {1, 1}; 492 493 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes); 494 495 Type *vertexDataType = new Type(mRSC); 496 vertexDataType->setDimX(mMaxNumberOfQuads * 4); 497 vertexDataType->setElement(vertexDataElem); 498 vertexDataType->compute(); 499 500 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType); 501 mTextMeshPtr = (float*)vertexAlloc->getPtr(); 502 503 mVertexArray.set(vertexAlloc); 504} 505 506// We don't want to allocate anything unless we actually draw text 507void FontState::checkInit() 508{ 509 if(mInitialized) { 510 return; 511 } 512 513 initTextTexture(); 514 initRenderState(); 515 516 initVertexArrayBuffers(); 517 518 // We store a string with letters in a rough frequency of occurrence 519 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq"); 520 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ"); 521 mLatinPrecache += String8(",.?!()-+@;:`'"); 522 mLatinPrecache += String8("0123456789"); 523 524 mInitialized = true; 525} 526 527void FontState::issueDrawCommand() { 528 529 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex()); 530 mRSC->setVertex(mRSC->getDefaultProgramVertex()); 531 532 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster()); 533 mRSC->setRaster(mRSC->getDefaultProgramRaster()); 534 535 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment()); 536 mRSC->setFragment(mFontShaderF.get()); 537 538 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore()); 539 mRSC->setFragmentStore(mFontProgramStore.get()); 540 541 if(mFontColorDirty) { 542 mFontShaderF->setConstantColor(mFontColor[0], mFontColor[1], mFontColor[2], mFontColor[3]); 543 mFontColorDirty = false; 544 } 545 546 if (!mRSC->setupCheck()) { 547 mRSC->setVertex((ProgramVertex *)tmpV.get()); 548 mRSC->setRaster((ProgramRaster *)tmpR.get()); 549 mRSC->setFragment((ProgramFragment *)tmpF.get()); 550 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 551 return; 552 } 553 554 float *vtx = (float*)mVertexArray->getPtr(); 555 float *tex = vtx + 3; 556 557 VertexArray va; 558 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position"); 559 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0"); 560 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache); 561 562 mIndexBuffer->uploadCheck(mRSC); 563 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); 564 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0)); 565 566 // Reset the state 567 mRSC->setVertex((ProgramVertex *)tmpV.get()); 568 mRSC->setRaster((ProgramRaster *)tmpR.get()); 569 mRSC->setFragment((ProgramFragment *)tmpF.get()); 570 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 571} 572 573void FontState::appendMeshQuad(float x1, float y1, float z1, 574 float u1, float v1, 575 float x2, float y2, float z2, 576 float u2, float v2, 577 float x3, float y3, float z3, 578 float u3, float v3, 579 float x4, float y4, float z4, 580 float u4, float v4) 581{ 582 const uint32_t vertsPerQuad = 4; 583 const uint32_t floatsPerVert = 5; 584 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 585 586 // Cull things that are off the screen 587 float width = (float)mRSC->getWidth(); 588 float height = (float)mRSC->getHeight(); 589 590 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) { 591 return; 592 } 593 594 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1); 595 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2); 596 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3); 597 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/ 598 599 (*currentPos++) = x1; 600 (*currentPos++) = y1; 601 (*currentPos++) = z1; 602 (*currentPos++) = u1; 603 (*currentPos++) = v1; 604 605 (*currentPos++) = x2; 606 (*currentPos++) = y2; 607 (*currentPos++) = z2; 608 (*currentPos++) = u2; 609 (*currentPos++) = v2; 610 611 (*currentPos++) = x3; 612 (*currentPos++) = y3; 613 (*currentPos++) = z3; 614 (*currentPos++) = u3; 615 (*currentPos++) = v3; 616 617 (*currentPos++) = x4; 618 (*currentPos++) = y4; 619 (*currentPos++) = z4; 620 (*currentPos++) = u4; 621 (*currentPos++) = v4; 622 623 mCurrentQuadIndex ++; 624 625 if(mCurrentQuadIndex == mMaxNumberOfQuads) { 626 issueDrawCommand(); 627 mCurrentQuadIndex = 0; 628 } 629} 630 631uint32_t FontState::getRemainingCacheCapacity() { 632 uint32_t remainingCapacity = 0; 633 uint32_t totalPixels = 0; 634 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 635 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 636 totalPixels += mCacheLines[i]->mMaxWidth; 637 } 638 remainingCapacity = (remainingCapacity * 100) / totalPixels; 639 return remainingCapacity; 640} 641 642void FontState::precacheLatin(Font *font) { 643 // Remaining capacity is measured in % 644 uint32_t remainingCapacity = getRemainingCacheCapacity(); 645 uint32_t precacheIdx = 0; 646 while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { 647 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]); 648 remainingCapacity = getRemainingCacheCapacity(); 649 precacheIdx ++; 650 } 651} 652 653 654void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y) 655{ 656 checkInit(); 657 658 // Render code here 659 Font *currentFont = mRSC->getFont(); 660 if(!currentFont) { 661 if(!mDefault.get()) { 662 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96)); 663 } 664 currentFont = mDefault.get(); 665 } 666 if(!currentFont) { 667 LOGE("Unable to initialize any fonts"); 668 return; 669 } 670 671 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y); 672 673 if(mCurrentQuadIndex != 0) { 674 issueDrawCommand(); 675 mCurrentQuadIndex = 0; 676 } 677} 678 679void FontState::renderText(const char *text, int x, int y) 680{ 681 size_t textLen = strlen(text); 682 renderText(text, textLen, 0, -1, x, y); 683} 684 685void FontState::renderText(Allocation *alloc, int x, int y) 686{ 687 if(!alloc) { 688 return; 689 } 690 691 const char *text = (const char *)alloc->getPtr(); 692 size_t allocSize = alloc->getType()->getSizeBytes(); 693 renderText(text, allocSize, 0, -1, x, y); 694} 695 696void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y) 697{ 698 if(!alloc) { 699 return; 700 } 701 702 const char *text = (const char *)alloc->getPtr(); 703 size_t allocSize = alloc->getType()->getSizeBytes(); 704 renderText(text, allocSize, start, len, x, y); 705} 706 707void FontState::setFontColor(float r, float g, float b, float a) { 708 mFontColor[0] = r; 709 mFontColor[1] = g; 710 mFontColor[2] = b; 711 mFontColor[3] = a; 712 mFontColorDirty = true; 713} 714 715void FontState::getFontColor(float *r, float *g, float *b, float *a) const { 716 *r = mFontColor[0]; 717 *g = mFontColor[1]; 718 *b = mFontColor[2]; 719 *a = mFontColor[3]; 720} 721 722void FontState::deinit(Context *rsc) 723{ 724 mInitialized = false; 725 726 mIndexBuffer.clear(); 727 mVertexArray.clear(); 728 729 mFontShaderF.clear(); 730 mFontSampler.clear(); 731 mFontProgramStore.clear(); 732 733 mTextTexture.clear(); 734 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 735 delete mCacheLines[i]; 736 } 737 mCacheLines.clear(); 738 739 mDefault.clear(); 740 741 Vector<Font*> fontsToDereference = mActiveFonts; 742 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) { 743 fontsToDereference[i]->zeroUserRef(); 744 } 745 746 if(mLibrary) { 747 FT_Done_FreeType( mLibrary ); 748 mLibrary = NULL; 749 } 750} 751 752namespace android { 753namespace renderscript { 754 755RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) 756{ 757 Font *newFont = Font::create(rsc, name, fontSize, dpi); 758 if(newFont) { 759 newFont->incUserRef(); 760 } 761 return newFont; 762} 763 764} // renderscript 765} // android 766