rsFont.cpp revision 01f0ad7c13b8878c2167bff10ea875d7509edca5
19b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
29b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk/*
39b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * Copyright (C) 2009 The Android Open Source Project
49b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *
59b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * Licensed under the Apache License, Version 2.0 (the "License");
69b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * you may not use this file except in compliance with the License.
79b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * You may obtain a copy of the License at
89b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *
99b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *      http://www.apache.org/licenses/LICENSE-2.0
109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *
119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * Unless required by applicable law or agreed to in writing, software
129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * distributed under the License is distributed on an "AS IS" BASIS,
139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * See the License for the specific language governing permissions and
159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * limitations under the License.
169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk */
179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#ifndef ANDROID_RS_BUILD_FOR_HOST
199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsContext.h"
209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#else
219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsContextHostStub.h"
229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#endif
239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsFont.h"
259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsProgramFragment.h"
269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include FT_BITMAP_H
279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES/gl.h>
299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES/glext.h>
309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES2/gl2.h>
319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES2/gl2ext.h>
329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukusing namespace android;
349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukusing namespace android::renderscript;
359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
369b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL)
379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
38071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mAllocFile = __FILE__;
39071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mAllocLine = __LINE__;
409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = false;
42b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mFace = NULL;
439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukbool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mInitialized) {
489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 fontsDir("/fonts/");
539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 fullPath(getenv("ANDROID_ROOT"));
549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    fullPath += fontsDir;
559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    fullPath += name;
569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
57071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(error) {
599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Unable to initialize font %s", fullPath.string());
609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontName = name;
649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSize = fontSize;
659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDpi = dpi;
669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(error) {
699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Unable to set font size on %s", fullPath.string());
709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::invalidateTextureCache()
809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y)
879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    int nPenX = x + glyph->mBitmapLeft;
919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0,
949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            glyph->mBitmapMinU, glyph->mBitmapMaxV,
959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            nPenX + (int)glyph->mBitmapWidth, nPenY, 0,
979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            glyph->mBitmapMaxU, glyph->mBitmapMaxV,
989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0,
1009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            glyph->mBitmapMaxU, glyph->mBitmapMinV,
1019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            nPenX, nPenY - (int)glyph->mBitmapHeight, 0,
1039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                            glyph->mBitmapMinU, glyph->mBitmapMinV);
1049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
1059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y)
1079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
1089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
1099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
1109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    int penX = x, penY = y;
1139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    int glyphsLeft = 1;
1149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(numGlyphs > 0) {
1159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        glyphsLeft = numGlyphs;
1169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t index = start;
1199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t nextIndex = 0;
1209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    while (glyphsLeft > 0) {
1229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        int32_t utfChar = utf32_at(text, len, index, &nextIndex);
1249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Reached the end of the string or encountered
1269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(utfChar < 0) {
1279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
1289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Move to the next character in the array
1319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        index = nextIndex;
1329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
13394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
1349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
1369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(cachedGlyph->mIsValid) {
1379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            drawCachedGlyph(cachedGlyph, penX, penY);
1389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        penX += (cachedGlyph->mAdvance.x >> 6);
1419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
1439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(numGlyphs > 0) {
1449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            glyphsLeft --;
1459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
1489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
14994bbccc36322168a596369c8341dad938c8f949fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
15094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
15194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
15294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    if(cachedGlyph == NULL) {
15394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
15494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
15594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Is the glyph still in texture cache?
15694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    if(!cachedGlyph->mIsValid) {
15794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        updateGlyphCache(cachedGlyph);
15894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
15994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
16094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return cachedGlyph;
16194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
16294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
1639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph)
1649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
165071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
166071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(error) {
167071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        LOGE("Couldn't load glyph.");
168071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        return;
169071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
1709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
171071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mAdvance = mFace->glyph->advance;
172071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
173071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
1749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
175071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
1769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
1789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
1799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
1809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
1829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
183071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
1849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!glyph->mIsValid) {
1869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
1879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
189071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
190071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
1919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinX = startX;
1939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinY = startY;
194071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
195071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
1969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
1989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
1999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
2019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
2029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
2039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
2049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2069b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
2079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
2099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
2109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
2129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mIsValid = false;
2139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    updateGlyphCache(newGlyph);
2159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return newGlyph;
2179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2199b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
2209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
22127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    rsc->mStateFont.checkInit();
2229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
2239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < activeFonts.size(); i ++) {
2259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        Font *ithFont = activeFonts[i];
2269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
2279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return ithFont;
2289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *newFont = new Font(rsc);
2329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi);
2339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(isInitialized) {
2349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        activeFonts.push(newFont);
23594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
2369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return newFont;
2379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    delete newFont;
2409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return NULL;
2419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2449b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::~Font()
2459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mFace) {
2479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        FT_Done_Face(mFace);
2489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
2519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
2529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            mRSC->mStateFont.mActiveFonts.removeAt(ct);
2539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
2549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
2589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
2599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete glyph;
2609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2639b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFontState::FontState()
2649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
2669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
2679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex = 0;
2689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC = NULL;
269b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mLibrary = NULL;
27055e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
2719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2739b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFontState::~FontState()
2749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
2769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete mCacheLines[i];
2779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
2809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
282071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex SakhartchoukFT_Library FontState::getLib()
2839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!mLibrary) {
285071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
2869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(error) {
2879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Unable to initialize freetype");
288071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            return NULL;
2899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
291b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
292071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return mLibrary;
293071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk}
2949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
295071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchoukvoid FontState::init(Context *rsc)
296071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk{
297071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mRSC = rsc;
2989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::flushAllAndInvalidate()
3019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
3039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
3049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
3059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
3079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
3089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
3109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
3119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
3159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the glyph is too tall, don't cache it
3179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
3189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
3199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
3209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
3239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
3249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
3259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool bitmapFit = false;
3279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
3289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
3299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(bitmapFit) {
3309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
3319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
3359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!bitmapFit) {
3369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        flushAllAndInvalidate();
3379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Try to fit it again
3399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
3409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
3419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            if(bitmapFit) {
3429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                break;
3439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            }
3449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
3479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(!bitmapFit) {
3489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
3499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return false;
3509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginX = startX;
3549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginY = startY;
3559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
3579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
3589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
3609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
3629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    unsigned char *bitmapBuffer = bitmap->buffer;
3639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
3659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
3669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
3679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
3689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
3699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // This will dirty the texture and the shader so next time
3739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // we draw it will upload the data
3749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
375b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
3769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Some debug code
3789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
3799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
3809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
3819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
3829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }*/
3849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
3869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initRenderState()
3899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
390c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    String8 shaderString("varying vec4 varTex0;\n");
391c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("void main() {\n");
392c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
393c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
394c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
395c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("}\n");
396c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
397c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
398c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
399c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
400c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
401c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
402c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    Type *inputType = new Type(mRSC);
403c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    inputType->setElement(constInput);
404c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    inputType->setDimX(1);
405c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    inputType->compute();
406c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
407c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    uint32_t tmp[4];
408c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
409c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[1] = (uint32_t)inputType;
410c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
411c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[3] = 1;
412c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
413c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mFontShaderFConstant.set(new Allocation(mRSC, inputType));
414c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
415c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk                                              shaderString.length(), tmp, 4);
4169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontShaderF.set(pf);
417b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
4189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
4209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
4219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSampler.set(sampler);
422b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, sampler);
4239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ProgramStore *fontStore = new ProgramStore(mRSC);
4259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore.set(fontStore);
4269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
4279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
4289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDitherEnable(false);
4299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthMask(false);
4309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initTextTexture()
4339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
4349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
4359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
4379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *texType = new Type(mRSC);
4389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setElement(alphaElem);
4399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setDimX(1024);
4409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setDimY(256);
4419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->compute();
4429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *cacheAlloc = new Allocation(mRSC, texType);
4449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
4459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
4469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
4489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    int nextLine = 0;
4499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
4509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
4519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
4529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
45394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
45494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
4559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
4569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
4579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
4589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
4599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
4609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
4619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
4629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
4659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initVertexArrayBuffers()
4669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
4679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now lets write index data
4689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
4699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *indexType = new Type(mRSC);
4709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
4719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->setDimX(numIndicies);
4729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->setElement(indexElem);
4739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->compute();
4749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *indexAlloc = new Allocation(mRSC, indexType);
4769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
4779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
4799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
4809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        int i6 = i * 6;
4819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        int i4 = i * 4;
4829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
4849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
4859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
4869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
4889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
4899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
4909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexAlloc->deferedUploadToBufferObject(mRSC);
4939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer.set(indexAlloc);
4949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
4969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
4979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *elemArray[2];
4999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    elemArray[0] = posElem;
5009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    elemArray[1] = texElem;
5019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 posName("position");
5039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 texName("texture0");
5049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const char *nameArray[2];
5069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nameArray[0] = posName.string();
5079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nameArray[1] = texName.string();
5089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t lengths[2];
5099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    lengths[0] = posName.size();
5109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    lengths[1] = texName.size();
51170d4e5024298f71edb3b04867e05568f5495b4ceJason Sams    uint32_t arraySizes[2] = {1, 1};
5129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
51370d4e5024298f71edb3b04867e05568f5495b4ceJason Sams    const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
5149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *vertexDataType = new Type(mRSC);
5169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->setDimX(mMaxNumberOfQuads * 4);
5179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->setElement(vertexDataElem);
5189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->compute();
5199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
5219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
5229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mVertexArray.set(vertexAlloc);
5249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
5279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::checkInit()
5289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
5299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mInitialized) {
5309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
5319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
5329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initTextTexture();
5349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initRenderState();
5359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initVertexArrayBuffers();
5379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
53827f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
53927f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
54027f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
54127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
54227f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("0123456789");
54327f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk
5449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
5459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::issueDrawCommand() {
5489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
5509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setVertex(mRSC->getDefaultProgramVertex());
5519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
55280a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
55380a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    mRSC->setRaster(mRSC->getDefaultProgramRaster());
55480a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk
5559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
5569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragment(mFontShaderF.get());
5579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
5599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragmentStore(mFontProgramStore.get());
5609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
56155e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    if(mFontColorDirty) {
562c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk        mFontShaderFConstant->data(mRSC, &mFontColor, 4*sizeof(float));
56355e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk        mFontColorDirty = false;
56455e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    }
56555e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
5669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if (!mRSC->setupCheck()) {
5679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setVertex((ProgramVertex *)tmpV.get());
56880a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk        mRSC->setRaster((ProgramRaster *)tmpR.get());
5699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setFragment((ProgramFragment *)tmpF.get());
5709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
5719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
5729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
5739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *vtx = (float*)mVertexArray->getPtr();
5759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *tex = vtx + 3;
5769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    VertexArray va;
5784378f1175546616c76ecb7f0b1159940ab22d5f4Alex Sakhartchouk    va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
5794378f1175546616c76ecb7f0b1159940ab22d5f4Alex Sakhartchouk    va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
5809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
5819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer->uploadCheck(mRSC);
5839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
5849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
5859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Reset the state
5879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setVertex((ProgramVertex *)tmpV.get());
58880a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    mRSC->setRaster((ProgramRaster *)tmpR.get());
5899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragment((ProgramFragment *)tmpF.get());
5909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
5919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
5949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u1, float v1,
5959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x2, float y2, float z2,
5969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u2, float v2,
5979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x3, float y3, float z3,
5989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u3, float v3,
5999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x4, float y4, float z4,
6009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u4, float v4)
6019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
6029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
6039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
6049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
6059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Cull things that are off the screen
6079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float width = (float)mRSC->getWidth();
6089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float height = (float)mRSC->getHeight();
6099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
6119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
6159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
6169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
6179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
6189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x1;
6209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y1;
6219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z1;
6229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u1;
6239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v1;
6249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x2;
6269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y2;
6279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z2;
6289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u2;
6299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v2;
6309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x3;
6329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y3;
6339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z3;
6349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u3;
6359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v3;
6369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x4;
6389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y4;
6399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z4;
6409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u4;
6419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v4;
6429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex ++;
6449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex == mMaxNumberOfQuads) {
6469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
6479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
6489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
65194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
65294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = 0;
65327f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    uint32_t totalPixels = 0;
65494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
65594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
65694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
65794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
65894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
65994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return remainingCapacity;
66094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
66194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
66294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
66394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Remaining capacity is measured in %
66494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
66594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t precacheIdx = 0;
66694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
66794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
66894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
66994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        precacheIdx ++;
67094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
67194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
67294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
67394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
6749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
6759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
6769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    checkInit();
6779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Render code here
6799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
680071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(!currentFont) {
681071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        if(!mDefault.get()) {
682071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
683071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        }
684071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        currentFont = mDefault.get();
685071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
686b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    if(!currentFont) {
687b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        LOGE("Unable to initialize any fonts");
688b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        return;
689b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
690b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
6919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
6929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
6949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
6959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
6969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(const char *text, int x, int y)
7009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
7019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t textLen = strlen(text);
7029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    renderText(text, textLen, 0, -1, x, y);
7039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(Allocation *alloc, int x, int y)
7069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
7079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!alloc) {
7089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
7099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const char *text = (const char *)alloc->getPtr();
7129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t allocSize = alloc->getType()->getSizeBytes();
7139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    renderText(text, allocSize, 0, -1, x, y);
7149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
7179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
7189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!alloc) {
7199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
7209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const char *text = (const char *)alloc->getPtr();
7239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t allocSize = alloc->getType()->getSizeBytes();
7249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    renderText(text, allocSize, start, len, x, y);
7259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
727fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
728fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk    mFontColor[0] = r;
729fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk    mFontColor[1] = g;
730fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk    mFontColor[2] = b;
731fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk    mFontColor[3] = a;
732fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk    mFontColorDirty = true;
733fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk}
734fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk
73555e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
73655e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    *r = mFontColor[0];
73755e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    *g = mFontColor[1];
73855e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    *b = mFontColor[2];
73955e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    *a = mFontColor[3];
74055e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk}
74155e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
7429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::deinit(Context *rsc)
7439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
744071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mInitialized = false;
745071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
74601f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines    mFontShaderFConstant.clear();
74701f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines
748071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mIndexBuffer.clear();
749071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mVertexArray.clear();
750071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
751071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontShaderF.clear();
752071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontSampler.clear();
753071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontProgramStore.clear();
754071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
755071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mTextTexture.clear();
756071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
757071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        delete mCacheLines[i];
7589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
759071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mCacheLines.clear();
7609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDefault.clear();
762071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
763b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    Vector<Font*> fontsToDereference = mActiveFonts;
764b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
765b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        fontsToDereference[i]->zeroUserRef();
766b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
767b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
768071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(mLibrary) {
769071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Done_FreeType( mLibrary );
770b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        mLibrary = NULL;
771071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
7729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace android {
7759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace renderscript {
7769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7779b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
7789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
779071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
780071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(newFont) {
781071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        newFont->incUserRef();
782071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
783071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return newFont;
7849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // renderscript
7879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // android
788