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