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