diff options
Diffstat (limited to 'libs/rs/rsFont.cpp')
-rw-r--r-- | libs/rs/rsFont.cpp | 764 |
1 files changed, 764 insertions, 0 deletions
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp new file mode 100644 index 0000000..7661d49 --- /dev/null +++ b/libs/rs/rsFont.cpp @@ -0,0 +1,764 @@ + +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RS_BUILD_FOR_HOST +#include "rsContext.h" +#else +#include "rsContextHostStub.h" +#endif + +#include "rsFont.h" +#include "rsProgramFragment.h" +#include FT_BITMAP_H + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +using namespace android; +using namespace android::renderscript; + +Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) +{ + mAllocFile = __FILE__; + mAllocLine = __LINE__; + mInitialized = false; + mHasKerning = false; + mFace = NULL; +} + +bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) +{ + if(mInitialized) { + LOGE("Reinitialization of fonts not supported"); + return false; + } + + String8 fontsDir("/fonts/"); + String8 fullPath(getenv("ANDROID_ROOT")); + fullPath += fontsDir; + fullPath += name; + + FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace); + if(error) { + LOGE("Unable to initialize font %s", fullPath.string()); + return false; + } + + mFontName = name; + mFontSize = fontSize; + mDpi = dpi; + + error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0); + if(error) { + LOGE("Unable to set font size on %s", fullPath.string()); + return false; + } + + mHasKerning = FT_HAS_KERNING(mFace); + + mInitialized = true; + return true; +} + +void Font::invalidateTextureCache() +{ + for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { + mCachedGlyphs.valueAt(i)->mIsValid = false; + } +} + +void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y) +{ + FontState *state = &mRSC->mStateFont; + + int nPenX = x + glyph->mBitmapLeft; + int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight; + + state->appendMeshQuad(nPenX, nPenY, 0, + glyph->mBitmapMinU, glyph->mBitmapMaxV, + + nPenX + (int)glyph->mBitmapWidth, nPenY, 0, + glyph->mBitmapMaxU, glyph->mBitmapMaxV, + + nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0, + glyph->mBitmapMaxU, glyph->mBitmapMinV, + + nPenX, nPenY - (int)glyph->mBitmapHeight, 0, + glyph->mBitmapMinU, glyph->mBitmapMinV); +} + +void Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y) +{ + if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) { + return; + } + + int penX = x, penY = y; + int glyphsLeft = 1; + if(numGlyphs > 0) { + glyphsLeft = numGlyphs; + } + + size_t index = start; + size_t nextIndex = 0; + + while (glyphsLeft > 0) { + + int32_t utfChar = utf32_at(text, len, index, &nextIndex); + + // Reached the end of the string or encountered + if(utfChar < 0) { + break; + } + + // Move to the next character in the array + index = nextIndex; + + CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar); + + // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage + if(cachedGlyph->mIsValid) { + drawCachedGlyph(cachedGlyph, penX, penY); + } + + penX += (cachedGlyph->mAdvance.x >> 6); + + // If we were given a specific number of glyphs, decrement + if(numGlyphs > 0) { + glyphsLeft --; + } + } +} + +Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) { + + CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar); + if(cachedGlyph == NULL) { + cachedGlyph = cacheGlyph((uint32_t)utfChar); + } + // Is the glyph still in texture cache? + if(!cachedGlyph->mIsValid) { + updateGlyphCache(cachedGlyph); + } + + return cachedGlyph; +} + +void Font::updateGlyphCache(CachedGlyphInfo *glyph) +{ + FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER ); + if(error) { + LOGE("Couldn't load glyph."); + return; + } + + glyph->mAdvance = mFace->glyph->advance; + glyph->mBitmapLeft = mFace->glyph->bitmap_left; + glyph->mBitmapTop = mFace->glyph->bitmap_top; + + FT_Bitmap *bitmap = &mFace->glyph->bitmap; + + // Now copy the bitmap into the cache texture + uint32_t startX = 0; + uint32_t startY = 0; + + // Let the font state figure out where to put the bitmap + FontState *state = &mRSC->mStateFont; + glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY); + + if(!glyph->mIsValid) { + return; + } + + uint32_t endX = startX + bitmap->width; + uint32_t endY = startY + bitmap->rows; + + glyph->mBitmapMinX = startX; + glyph->mBitmapMinY = startY; + glyph->mBitmapWidth = bitmap->width; + glyph->mBitmapHeight = bitmap->rows; + + uint32_t cacheWidth = state->getCacheTextureType()->getDimX(); + uint32_t cacheHeight = state->getCacheTextureType()->getDimY(); + + glyph->mBitmapMinU = (float)startX / (float)cacheWidth; + glyph->mBitmapMinV = (float)startY / (float)cacheHeight; + glyph->mBitmapMaxU = (float)endX / (float)cacheWidth; + glyph->mBitmapMaxV = (float)endY / (float)cacheHeight; +} + +Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) +{ + CachedGlyphInfo *newGlyph = new CachedGlyphInfo(); + mCachedGlyphs.add(glyph, newGlyph); + + newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph); + newGlyph->mIsValid = false; + + updateGlyphCache(newGlyph); + + return newGlyph; +} + +Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi) +{ + rsc->mStateFont.checkInit(); + Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts; + + for(uint32_t i = 0; i < activeFonts.size(); i ++) { + Font *ithFont = activeFonts[i]; + if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) { + return ithFont; + } + } + + Font *newFont = new Font(rsc); + bool isInitialized = newFont->init(name, fontSize, dpi); + if(isInitialized) { + activeFonts.push(newFont); + rsc->mStateFont.precacheLatin(newFont); + return newFont; + } + + delete newFont; + return NULL; + +} + +Font::~Font() +{ + if(mFace) { + FT_Done_Face(mFace); + } + + for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) { + if (mRSC->mStateFont.mActiveFonts[ct] == this) { + mRSC->mStateFont.mActiveFonts.removeAt(ct); + break; + } + } + + for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) { + CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i); + delete glyph; + } +} + +FontState::FontState() +{ + mInitialized = false; + mMaxNumberOfQuads = 1024; + mCurrentQuadIndex = 0; + mRSC = NULL; + mLibrary = NULL; + setFontColor(0.1f, 0.1f, 0.1f, 1.0f); +} + +FontState::~FontState() +{ + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + delete mCacheLines[i]; + } + + rsAssert(!mActiveFonts.size()); +} + +FT_Library FontState::getLib() +{ + if(!mLibrary) { + FT_Error error = FT_Init_FreeType(&mLibrary); + if(error) { + LOGE("Unable to initialize freetype"); + return NULL; + } + } + + return mLibrary; +} + +void FontState::init(Context *rsc) +{ + mRSC = rsc; +} + +void FontState::flushAllAndInvalidate() +{ + if(mCurrentQuadIndex != 0) { + issueDrawCommand(); + mCurrentQuadIndex = 0; + } + for(uint32_t i = 0; i < mActiveFonts.size(); i ++) { + mActiveFonts[i]->invalidateTextureCache(); + } + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + mCacheLines[i]->mCurrentCol = 0; + } +} + +bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) +{ + // If the glyph is too tall, don't cache it + if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) { + LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); + return false; + } + + // Now copy the bitmap into the cache texture + uint32_t startX = 0; + uint32_t startY = 0; + + bool bitmapFit = false; + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); + if(bitmapFit) { + break; + } + } + + // If the new glyph didn't fit, flush the state so far and invalidate everything + if(!bitmapFit) { + flushAllAndInvalidate(); + + // Try to fit it again + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY); + if(bitmapFit) { + break; + } + } + + // if we still don't fit, something is wrong and we shouldn't draw + if(!bitmapFit) { + LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows); + return false; + } + } + + *retOriginX = startX; + *retOriginY = startY; + + uint32_t endX = startX + bitmap->width; + uint32_t endY = startY + bitmap->rows; + + uint32_t cacheWidth = getCacheTextureType()->getDimX(); + + unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr(); + unsigned char *bitmapBuffer = bitmap->buffer; + + uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; + for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) { + for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) { + unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX]; + cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol; + } + } + + // This will dirty the texture and the shader so next time + // we draw it will upload the data + mTextTexture->deferedUploadToTexture(mRSC, false, 0); + mFontShaderF->bindTexture(0, mTextTexture.get()); + + // Some debug code + /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + LOGE("Cache Line: H: %u Empty Space: %f", + mCacheLines[i]->mMaxHeight, + (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f); + + }*/ + + return true; +} + +void FontState::initRenderState() +{ + uint32_t tmp[] = { + RS_TEX_ENV_MODE_REPLACE, 1, + RS_TEX_ENV_MODE_NONE, 0, + 0, 0 + }; + ProgramFragment *pf = new ProgramFragment(mRSC, tmp, 6); + mFontShaderF.set(pf); + mFontShaderF->init(mRSC); + + Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST, + RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP); + mFontSampler.set(sampler); + mFontShaderF->bindSampler(0, sampler); + + ProgramStore *fontStore = new ProgramStore(mRSC); + mFontProgramStore.set(fontStore); + mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS); + mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA); + mFontProgramStore->setDitherEnable(false); + mFontProgramStore->setDepthMask(false); +} + +void FontState::initTextTexture() +{ + const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1); + + // We will allocate a texture to initially hold 32 character bitmaps + Type *texType = new Type(mRSC); + texType->setElement(alphaElem); + texType->setDimX(1024); + texType->setDimY(256); + texType->compute(); + + Allocation *cacheAlloc = new Allocation(mRSC, texType); + mTextTexture.set(cacheAlloc); + mTextTexture->deferedUploadToTexture(mRSC, false, 0); + + // Split up our cache texture into lines of certain widths + int nextLine = 0; + mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0)); + nextLine += mCacheLines.top()->mMaxHeight; + mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0)); +} + +// Avoid having to reallocate memory and render quad by quad +void FontState::initVertexArrayBuffers() +{ + // Now lets write index data + const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1); + Type *indexType = new Type(mRSC); + uint32_t numIndicies = mMaxNumberOfQuads * 6; + indexType->setDimX(numIndicies); + indexType->setElement(indexElem); + indexType->compute(); + + Allocation *indexAlloc = new Allocation(mRSC, indexType); + uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr(); + + // Four verts, two triangles , six indices per quad + for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) { + int i6 = i * 6; + int i4 = i * 4; + + indexPtr[i6 + 0] = i4 + 0; + indexPtr[i6 + 1] = i4 + 1; + indexPtr[i6 + 2] = i4 + 2; + + indexPtr[i6 + 3] = i4 + 0; + indexPtr[i6 + 4] = i4 + 2; + indexPtr[i6 + 5] = i4 + 3; + } + + indexAlloc->deferedUploadToBufferObject(mRSC); + mIndexBuffer.set(indexAlloc); + + const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3); + const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2); + + const Element *elemArray[2]; + elemArray[0] = posElem; + elemArray[1] = texElem; + + String8 posName("position"); + String8 texName("texture0"); + + const char *nameArray[2]; + nameArray[0] = posName.string(); + nameArray[1] = texName.string(); + size_t lengths[2]; + lengths[0] = posName.size(); + lengths[1] = texName.size(); + + const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths); + + Type *vertexDataType = new Type(mRSC); + vertexDataType->setDimX(mMaxNumberOfQuads * 4); + vertexDataType->setElement(vertexDataElem); + vertexDataType->compute(); + + Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType); + mTextMeshPtr = (float*)vertexAlloc->getPtr(); + + mVertexArray.set(vertexAlloc); +} + +// We don't want to allocate anything unless we actually draw text +void FontState::checkInit() +{ + if(mInitialized) { + return; + } + + initTextTexture(); + initRenderState(); + + initVertexArrayBuffers(); + + // We store a string with letters in a rough frequency of occurrence + mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq"); + mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ"); + mLatinPrecache += String8(",.?!()-+@;:`'"); + mLatinPrecache += String8("0123456789"); + + mInitialized = true; +} + +void FontState::issueDrawCommand() { + + ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex()); + mRSC->setVertex(mRSC->getDefaultProgramVertex()); + + ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster()); + mRSC->setRaster(mRSC->getDefaultProgramRaster()); + + ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment()); + mRSC->setFragment(mFontShaderF.get()); + + ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore()); + mRSC->setFragmentStore(mFontProgramStore.get()); + + if(mFontColorDirty) { + mFontShaderF->setConstantColor(mFontColor[0], mFontColor[1], mFontColor[2], mFontColor[3]); + mFontColorDirty = false; + } + + if (!mRSC->setupCheck()) { + mRSC->setVertex((ProgramVertex *)tmpV.get()); + mRSC->setRaster((ProgramRaster *)tmpR.get()); + mRSC->setFragment((ProgramFragment *)tmpF.get()); + mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); + return; + } + + float *vtx = (float*)mVertexArray->getPtr(); + float *tex = vtx + 3; + + VertexArray va; + va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position"); + va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0"); + va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache); + + mIndexBuffer->uploadCheck(mRSC); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); + glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0)); + + // Reset the state + mRSC->setVertex((ProgramVertex *)tmpV.get()); + mRSC->setRaster((ProgramRaster *)tmpR.get()); + mRSC->setFragment((ProgramFragment *)tmpF.get()); + mRSC->setFragmentStore((ProgramStore *)tmpPS.get()); +} + +void FontState::appendMeshQuad(float x1, float y1, float z1, + float u1, float v1, + float x2, float y2, float z2, + float u2, float v2, + float x3, float y3, float z3, + float u3, float v3, + float x4, float y4, float z4, + float u4, float v4) +{ + const uint32_t vertsPerQuad = 4; + const uint32_t floatsPerVert = 5; + float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; + + // Cull things that are off the screen + float width = (float)mRSC->getWidth(); + float height = (float)mRSC->getHeight(); + + if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) { + return; + } + + /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1); + LOGE("V1 x: %f y: %f z: %f", x2, y2, z2); + LOGE("V2 x: %f y: %f z: %f", x3, y3, z3); + LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/ + + (*currentPos++) = x1; + (*currentPos++) = y1; + (*currentPos++) = z1; + (*currentPos++) = u1; + (*currentPos++) = v1; + + (*currentPos++) = x2; + (*currentPos++) = y2; + (*currentPos++) = z2; + (*currentPos++) = u2; + (*currentPos++) = v2; + + (*currentPos++) = x3; + (*currentPos++) = y3; + (*currentPos++) = z3; + (*currentPos++) = u3; + (*currentPos++) = v3; + + (*currentPos++) = x4; + (*currentPos++) = y4; + (*currentPos++) = z4; + (*currentPos++) = u4; + (*currentPos++) = v4; + + mCurrentQuadIndex ++; + + if(mCurrentQuadIndex == mMaxNumberOfQuads) { + issueDrawCommand(); + mCurrentQuadIndex = 0; + } +} + +uint32_t FontState::getRemainingCacheCapacity() { + uint32_t remainingCapacity = 0; + uint32_t totalPixels = 0; + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); + totalPixels += mCacheLines[i]->mMaxWidth; + } + remainingCapacity = (remainingCapacity * 100) / totalPixels; + return remainingCapacity; +} + +void FontState::precacheLatin(Font *font) { + // Remaining capacity is measured in % + uint32_t remainingCapacity = getRemainingCacheCapacity(); + uint32_t precacheIdx = 0; + while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { + font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]); + remainingCapacity = getRemainingCacheCapacity(); + precacheIdx ++; + } +} + + +void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y) +{ + checkInit(); + + // Render code here + Font *currentFont = mRSC->getFont(); + if(!currentFont) { + if(!mDefault.get()) { + mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96)); + } + currentFont = mDefault.get(); + } + if(!currentFont) { + LOGE("Unable to initialize any fonts"); + return; + } + + currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y); + + if(mCurrentQuadIndex != 0) { + issueDrawCommand(); + mCurrentQuadIndex = 0; + } +} + +void FontState::renderText(const char *text, int x, int y) +{ + size_t textLen = strlen(text); + renderText(text, textLen, 0, -1, x, y); +} + +void FontState::renderText(Allocation *alloc, int x, int y) +{ + if(!alloc) { + return; + } + + const char *text = (const char *)alloc->getPtr(); + size_t allocSize = alloc->getType()->getSizeBytes(); + renderText(text, allocSize, 0, -1, x, y); +} + +void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y) +{ + if(!alloc) { + return; + } + + const char *text = (const char *)alloc->getPtr(); + size_t allocSize = alloc->getType()->getSizeBytes(); + renderText(text, allocSize, start, len, x, y); +} + +void FontState::setFontColor(float r, float g, float b, float a) { + mFontColor[0] = r; + mFontColor[1] = g; + mFontColor[2] = b; + mFontColor[3] = a; + mFontColorDirty = true; +} + +void FontState::getFontColor(float *r, float *g, float *b, float *a) const { + *r = mFontColor[0]; + *g = mFontColor[1]; + *b = mFontColor[2]; + *a = mFontColor[3]; +} + +void FontState::deinit(Context *rsc) +{ + mInitialized = false; + + mIndexBuffer.clear(); + mVertexArray.clear(); + + mFontShaderF.clear(); + mFontSampler.clear(); + mFontProgramStore.clear(); + + mTextTexture.clear(); + for(uint32_t i = 0; i < mCacheLines.size(); i ++) { + delete mCacheLines[i]; + } + mCacheLines.clear(); + + mDefault.clear(); + + Vector<Font*> fontsToDereference = mActiveFonts; + for(uint32_t i = 0; i < fontsToDereference.size(); i ++) { + fontsToDereference[i]->zeroUserRef(); + } + + if(mLibrary) { + FT_Done_FreeType( mLibrary ); + mLibrary = NULL; + } +} + +namespace android { +namespace renderscript { + +RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) +{ + Font *newFont = Font::create(rsc, name, fontSize, dpi); + if(newFont) { + newFont->incUserRef(); + } + return newFont; +} + +} // renderscript +} // android |