rsFont.cpp revision 9fc9f0375a92fe22fecb3782b18a5c6060a07290
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.0f, 0.0f, 0.0f, 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[5] = { 383 RS_TEX_ENV_MODE_REPLACE, 1, 384 RS_TEX_ENV_MODE_NONE, 0, 385 0 386 }; 387 ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 5); 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 (!mRSC->setupCheck()) { 525 mRSC->setVertex((ProgramVertex *)tmpV.get()); 526 mRSC->setRaster((ProgramRaster *)tmpR.get()); 527 mRSC->setFragment((ProgramFragment *)tmpF.get()); 528 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 529 return; 530 } 531 532 float *vtx = (float*)mVertexArray->getPtr(); 533 float *tex = vtx + 3; 534 535 VertexArray va; 536 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position"); 537 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0"); 538 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache); 539 540 mIndexBuffer->uploadCheck(mRSC); 541 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); 542 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0)); 543 544 // Reset the state 545 mRSC->setVertex((ProgramVertex *)tmpV.get()); 546 mRSC->setRaster((ProgramRaster *)tmpR.get()); 547 mRSC->setFragment((ProgramFragment *)tmpF.get()); 548 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 549} 550 551void FontState::appendMeshQuad(float x1, float y1, float z1, 552 float u1, float v1, 553 float x2, float y2, float z2, 554 float u2, float v2, 555 float x3, float y3, float z3, 556 float u3, float v3, 557 float x4, float y4, float z4, 558 float u4, float v4) 559{ 560 const uint32_t vertsPerQuad = 4; 561 const uint32_t floatsPerVert = 5; 562 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 563 564 // Cull things that are off the screen 565 float width = (float)mRSC->getWidth(); 566 float height = (float)mRSC->getHeight(); 567 568 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) { 569 return; 570 } 571 572 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1); 573 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2); 574 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3); 575 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/ 576 577 (*currentPos++) = x1; 578 (*currentPos++) = y1; 579 (*currentPos++) = z1; 580 (*currentPos++) = u1; 581 (*currentPos++) = v1; 582 583 (*currentPos++) = x2; 584 (*currentPos++) = y2; 585 (*currentPos++) = z2; 586 (*currentPos++) = u2; 587 (*currentPos++) = v2; 588 589 (*currentPos++) = x3; 590 (*currentPos++) = y3; 591 (*currentPos++) = z3; 592 (*currentPos++) = u3; 593 (*currentPos++) = v3; 594 595 (*currentPos++) = x4; 596 (*currentPos++) = y4; 597 (*currentPos++) = z4; 598 (*currentPos++) = u4; 599 (*currentPos++) = v4; 600 601 mCurrentQuadIndex ++; 602 603 if(mCurrentQuadIndex == mMaxNumberOfQuads) { 604 issueDrawCommand(); 605 mCurrentQuadIndex = 0; 606 } 607} 608 609void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y) 610{ 611 checkInit(); 612 613 //String8 text8(text); 614 615 // Render code here 616 Font *currentFont = mRSC->getFont(); 617 if(!currentFont) { 618 if(!mDefault.get()) { 619 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96)); 620 } 621 currentFont = mDefault.get(); 622 } 623 if(!currentFont) { 624 LOGE("Unable to initialize any fonts"); 625 return; 626 } 627 628 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y); 629 630 if(mCurrentQuadIndex != 0) { 631 issueDrawCommand(); 632 mCurrentQuadIndex = 0; 633 } 634} 635 636void FontState::renderText(const char *text, int x, int y) 637{ 638 size_t textLen = strlen(text); 639 renderText(text, textLen, 0, -1, x, y); 640} 641 642void FontState::renderText(Allocation *alloc, int x, int y) 643{ 644 if(!alloc) { 645 return; 646 } 647 648 const char *text = (const char *)alloc->getPtr(); 649 size_t allocSize = alloc->getType()->getSizeBytes(); 650 renderText(text, allocSize, 0, -1, x, y); 651} 652 653void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y) 654{ 655 if(!alloc) { 656 return; 657 } 658 659 const char *text = (const char *)alloc->getPtr(); 660 size_t allocSize = alloc->getType()->getSizeBytes(); 661 renderText(text, allocSize, start, len, x, y); 662} 663 664void FontState::setFontColor(float r, float g, float b, float a) { 665 mFontColor[0] = r; 666 mFontColor[1] = g; 667 mFontColor[2] = b; 668 mFontColor[3] = a; 669 mFontColorDirty = true; 670} 671 672void FontState::deinit(Context *rsc) 673{ 674 mInitialized = false; 675 676 mIndexBuffer.clear(); 677 mVertexArray.clear(); 678 679 mFontShaderF.clear(); 680 mFontSampler.clear(); 681 mFontProgramStore.clear(); 682 683 mTextTexture.clear(); 684 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 685 delete mCacheLines[i]; 686 } 687 mCacheLines.clear(); 688 689 mDefault.clear(); 690 691 Vector<Font*> fontsToDereference = mActiveFonts; 692 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) { 693 fontsToDereference[i]->zeroUserRef(); 694 } 695 696 if(mLibrary) { 697 FT_Done_FreeType( mLibrary ); 698 mLibrary = NULL; 699 } 700} 701 702namespace android { 703namespace renderscript { 704 705RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) 706{ 707 Font *newFont = Font::create(rsc, name, fontSize, dpi); 708 if(newFont) { 709 newFont->incUserRef(); 710 } 711 return newFont; 712} 713 714} // renderscript 715} // android 716