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