rsFont.cpp revision d18c744a37441311c9b65254a35db456835adad3
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} 263 264FontState::~FontState() 265{ 266 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 267 delete mCacheLines[i]; 268 } 269 270 rsAssert(!mActiveFonts.size()); 271} 272 273FT_Library FontState::getLib() 274{ 275 if(!mLibrary) { 276 FT_Error error = FT_Init_FreeType(&mLibrary); 277 if(error) { 278 LOGE("Unable to initialize freetype"); 279 return NULL; 280 } 281 } 282 283 return mLibrary; 284} 285 286void FontState::init(Context *rsc) 287{ 288 mRSC = rsc; 289} 290 291void FontState::flushAllAndInvalidate() 292{ 293 if(mCurrentQuadIndex != 0) { 294 issueDrawCommand(); 295 mCurrentQuadIndex = 0; 296 } 297 for(uint32_t i = 0; i < mActiveFonts.size(); i ++) { 298 mActiveFonts[i]->invalidateTextureCache(); 299 } 300 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 301 mCacheLines[i]->mCurrentCol = 0; 302 } 303} 304 305bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) 306{ 307 // If the glyph is too tall, don't cache it 308 if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) { 309 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); 310 return false; 311 } 312 313 // Now copy the bitmap into the cache texture 314 uint32_t startX = 0; 315 uint32_t startY = 0; 316 317 bool bitmapFit = false; 318 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 319 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); 320 if(bitmapFit) { 321 break; 322 } 323 } 324 325 // If the new glyph didn't fit, flush the state so far and invalidate everything 326 if(!bitmapFit) { 327 flushAllAndInvalidate(); 328 329 // Try to fit it again 330 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 331 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); 332 if(bitmapFit) { 333 break; 334 } 335 } 336 337 // if we still don't fit, something is wrong and we shouldn't draw 338 if(!bitmapFit) { 339 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); 340 return false; 341 } 342 } 343 344 *retOriginX = startX; 345 *retOriginY = startY; 346 347 uint32_t endX = startX + bitmap->width; 348 uint32_t endY = startY + bitmap->rows; 349 350 uint32_t cacheWidth = getCacheTextureType()->getDimX(); 351 352 unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr(); 353 unsigned char *bitmapBuffer = bitmap->buffer; 354 355 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 356 for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) { 357 for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) { 358 unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX]; 359 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol; 360 } 361 } 362 363 // This will dirty the texture and the shader so next time 364 // we draw it will upload the data 365 mTextTexture->deferedUploadToTexture(mRSC, false, 0); 366 mFontShaderF->bindTexture(0, mTextTexture.get()); 367 368 // Some debug code 369 /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 370 LOGE("Cache Line: H: %u Empty Space: %f", 371 mCacheLines[i]->mMaxHeight, 372 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f); 373 374 }*/ 375 376 return true; 377} 378 379void FontState::initRenderState() 380{ 381 uint32_t tmp[5] = { 382 RS_TEX_ENV_MODE_REPLACE, 1, 383 RS_TEX_ENV_MODE_NONE, 0, 384 0 385 }; 386 ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 5); 387 mFontShaderF.set(pf); 388 mFontShaderF->init(mRSC); 389 390 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST, 391 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP); 392 mFontSampler.set(sampler); 393 mFontShaderF->bindSampler(0, sampler); 394 395 ProgramStore *fontStore = new ProgramStore(mRSC); 396 mFontProgramStore.set(fontStore); 397 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS); 398 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA); 399 mFontProgramStore->setDitherEnable(false); 400 mFontProgramStore->setDepthMask(false); 401} 402 403void FontState::initTextTexture() 404{ 405 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1); 406 407 // We will allocate a texture to initially hold 32 character bitmaps 408 Type *texType = new Type(mRSC); 409 texType->setElement(alphaElem); 410 texType->setDimX(1024); 411 texType->setDimY(256); 412 texType->compute(); 413 414 Allocation *cacheAlloc = new Allocation(mRSC, texType); 415 mTextTexture.set(cacheAlloc); 416 mTextTexture->deferedUploadToTexture(mRSC, false, 0); 417 418 // Split up our cache texture into lines of certain widths 419 int nextLine = 0; 420 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0)); 421 nextLine += mCacheLines.top()->mMaxHeight; 422 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); 423 nextLine += mCacheLines.top()->mMaxHeight; 424 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); 425 nextLine += mCacheLines.top()->mMaxHeight; 426 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); 427 nextLine += mCacheLines.top()->mMaxHeight; 428 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0)); 429 nextLine += mCacheLines.top()->mMaxHeight; 430 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0)); 431} 432 433// Avoid having to reallocate memory and render quad by quad 434void FontState::initVertexArrayBuffers() 435{ 436 // Now lets write index data 437 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1); 438 Type *indexType = new Type(mRSC); 439 uint32_t numIndicies = mMaxNumberOfQuads * 6; 440 indexType->setDimX(numIndicies); 441 indexType->setElement(indexElem); 442 indexType->compute(); 443 444 Allocation *indexAlloc = new Allocation(mRSC, indexType); 445 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr(); 446 447 // Four verts, two triangles , six indices per quad 448 for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) { 449 int i6 = i * 6; 450 int i4 = i * 4; 451 452 indexPtr[i6 + 0] = i4 + 0; 453 indexPtr[i6 + 1] = i4 + 1; 454 indexPtr[i6 + 2] = i4 + 2; 455 456 indexPtr[i6 + 3] = i4 + 0; 457 indexPtr[i6 + 4] = i4 + 2; 458 indexPtr[i6 + 5] = i4 + 3; 459 } 460 461 indexAlloc->deferedUploadToBufferObject(mRSC); 462 mIndexBuffer.set(indexAlloc); 463 464 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); 465 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2); 466 467 const Element *elemArray[2]; 468 elemArray[0] = posElem; 469 elemArray[1] = texElem; 470 471 String8 posName("position"); 472 String8 texName("texture0"); 473 474 const char *nameArray[2]; 475 nameArray[0] = posName.string(); 476 nameArray[1] = texName.string(); 477 size_t lengths[2]; 478 lengths[0] = posName.size(); 479 lengths[1] = texName.size(); 480 481 const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths); 482 483 Type *vertexDataType = new Type(mRSC); 484 vertexDataType->setDimX(mMaxNumberOfQuads * 4); 485 vertexDataType->setElement(vertexDataElem); 486 vertexDataType->compute(); 487 488 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType); 489 mTextMeshPtr = (float*)vertexAlloc->getPtr(); 490 491 mVertexArray.set(vertexAlloc); 492} 493 494// We don't want to allocate anything unless we actually draw text 495void FontState::checkInit() 496{ 497 if(mInitialized) { 498 return; 499 } 500 501 initTextTexture(); 502 initRenderState(); 503 504 initVertexArrayBuffers(); 505 506 mInitialized = true; 507} 508 509void FontState::issueDrawCommand() { 510 511 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex()); 512 mRSC->setVertex(mRSC->getDefaultProgramVertex()); 513 514 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster()); 515 mRSC->setRaster(mRSC->getDefaultProgramRaster()); 516 517 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment()); 518 mRSC->setFragment(mFontShaderF.get()); 519 520 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore()); 521 mRSC->setFragmentStore(mFontProgramStore.get()); 522 523 if (!mRSC->setupCheck()) { 524 mRSC->setVertex((ProgramVertex *)tmpV.get()); 525 mRSC->setRaster((ProgramRaster *)tmpR.get()); 526 mRSC->setFragment((ProgramFragment *)tmpF.get()); 527 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 528 return; 529 } 530 531 float *vtx = (float*)mVertexArray->getPtr(); 532 float *tex = vtx + 3; 533 534 VertexArray va; 535 va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position"); 536 va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0"); 537 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache); 538 539 mIndexBuffer->uploadCheck(mRSC); 540 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); 541 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0)); 542 543 // Reset the state 544 mRSC->setVertex((ProgramVertex *)tmpV.get()); 545 mRSC->setRaster((ProgramRaster *)tmpR.get()); 546 mRSC->setFragment((ProgramFragment *)tmpF.get()); 547 mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); 548} 549 550void FontState::appendMeshQuad(float x1, float y1, float z1, 551 float u1, float v1, 552 float x2, float y2, float z2, 553 float u2, float v2, 554 float x3, float y3, float z3, 555 float u3, float v3, 556 float x4, float y4, float z4, 557 float u4, float v4) 558{ 559 const uint32_t vertsPerQuad = 4; 560 const uint32_t floatsPerVert = 5; 561 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 562 563 // Cull things that are off the screen 564 float width = (float)mRSC->getWidth(); 565 float height = (float)mRSC->getHeight(); 566 567 if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) { 568 return; 569 } 570 571 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1); 572 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2); 573 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3); 574 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/ 575 576 (*currentPos++) = x1; 577 (*currentPos++) = y1; 578 (*currentPos++) = z1; 579 (*currentPos++) = u1; 580 (*currentPos++) = v1; 581 582 (*currentPos++) = x2; 583 (*currentPos++) = y2; 584 (*currentPos++) = z2; 585 (*currentPos++) = u2; 586 (*currentPos++) = v2; 587 588 (*currentPos++) = x3; 589 (*currentPos++) = y3; 590 (*currentPos++) = z3; 591 (*currentPos++) = u3; 592 (*currentPos++) = v3; 593 594 (*currentPos++) = x4; 595 (*currentPos++) = y4; 596 (*currentPos++) = z4; 597 (*currentPos++) = u4; 598 (*currentPos++) = v4; 599 600 mCurrentQuadIndex ++; 601 602 if(mCurrentQuadIndex == mMaxNumberOfQuads) { 603 issueDrawCommand(); 604 mCurrentQuadIndex = 0; 605 } 606} 607 608void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y) 609{ 610 checkInit(); 611 612 //String8 text8(text); 613 614 // Render code here 615 Font *currentFont = mRSC->getFont(); 616 if(!currentFont) { 617 if(!mDefault.get()) { 618 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96)); 619 } 620 currentFont = mDefault.get(); 621 } 622 if(!currentFont) { 623 LOGE("Unable to initialize any fonts"); 624 return; 625 } 626 627 currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y); 628 629 if(mCurrentQuadIndex != 0) { 630 issueDrawCommand(); 631 mCurrentQuadIndex = 0; 632 } 633} 634 635void FontState::renderText(const char *text, int x, int y) 636{ 637 size_t textLen = strlen(text); 638 renderText(text, textLen, 0, -1, x, y); 639} 640 641void FontState::renderText(Allocation *alloc, int x, int y) 642{ 643 if(!alloc) { 644 return; 645 } 646 647 const char *text = (const char *)alloc->getPtr(); 648 size_t allocSize = alloc->getType()->getSizeBytes(); 649 renderText(text, allocSize, 0, -1, x, y); 650} 651 652void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y) 653{ 654 if(!alloc) { 655 return; 656 } 657 658 const char *text = (const char *)alloc->getPtr(); 659 size_t allocSize = alloc->getType()->getSizeBytes(); 660 renderText(text, allocSize, start, len, x, y); 661} 662 663void FontState::deinit(Context *rsc) 664{ 665 mInitialized = false; 666 667 mIndexBuffer.clear(); 668 mVertexArray.clear(); 669 670 mFontShaderF.clear(); 671 mFontSampler.clear(); 672 mFontProgramStore.clear(); 673 674 mTextTexture.clear(); 675 for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 676 delete mCacheLines[i]; 677 } 678 mCacheLines.clear(); 679 680 mDefault.clear(); 681 682 Vector<Font*> fontsToDereference = mActiveFonts; 683 for(uint32_t i = 0; i < fontsToDereference.size(); i ++) { 684 fontsToDereference[i]->zeroUserRef(); 685 } 686 687 if(mLibrary) { 688 FT_Done_FreeType( mLibrary ); 689 mLibrary = NULL; 690 } 691} 692 693namespace android { 694namespace renderscript { 695 696RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) 697{ 698 Font *newFont = Font::create(rsc, name, fontSize, dpi); 699 if(newFont) { 700 newFont->incUserRef(); 701 } 702 return newFont; 703} 704 705} // renderscript 706} // android 707