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