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