rsFont.cpp revision e7ae69f4a70f1813cf8086ebd9714192c635300a
1d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
2d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk/*
3d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Copyright (C) 2009 The Android Open Source Project
4d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
5d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Licensed under the Apache License, Version 2.0 (the "License");
6d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * you may not use this file except in compliance with the License.
7d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * You may obtain a copy of the License at
8d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
9d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *      http://www.apache.org/licenses/LICENSE-2.0
10d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
11d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Unless required by applicable law or agreed to in writing, software
12d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * distributed under the License is distributed on an "AS IS" BASIS,
13d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * See the License for the specific language governing permissions and
15d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * limitations under the License.
16d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk */
17d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
18d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#ifndef ANDROID_RS_BUILD_FOR_HOST
19d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsContext.h"
20d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#else
21d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsContextHostStub.h"
22d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#endif
23d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
24d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsFont.h"
25d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsProgramFragment.h"
26d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include FT_BITMAP_H
27d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
28d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES/gl.h>
29d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES/glext.h>
30d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES2/gl2.h>
31d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES2/gl2ext.h>
32d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
33d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android;
34d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android::renderscript;
35d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
36d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL)
37d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
38a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mAllocFile = __FILE__;
39a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mAllocLine = __LINE__;
40d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
41d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = false;
423659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mFace = NULL;
43d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
44d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
45d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukbool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
46d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
47d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mInitialized) {
48d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
49d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
50d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
51d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
52d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    String8 fontsDir("/fonts/");
53d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    String8 fullPath(getenv("ANDROID_ROOT"));
54d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    fullPath += fontsDir;
55d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    fullPath += name;
56d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
57a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
58d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(error) {
59d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Unable to initialize font %s", fullPath.string());
60d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
61d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
62d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
63d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontName = name;
64d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSize = fontSize;
65d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDpi = dpi;
66d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
67d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
68d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(error) {
69d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Unable to set font size on %s", fullPath.string());
70d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
71d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
72d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
73d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
74d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
75d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
76d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
77d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
78d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
79d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid Font::invalidateTextureCache()
80d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
81d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
82d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
83d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
84d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
85d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
86d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y)
87d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
88d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
89d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
90d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    int nPenX = x + glyph->mBitmapLeft;
91d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
92d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
93d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0,
94d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            glyph->mBitmapMinU, glyph->mBitmapMaxV,
95d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
96d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            nPenX + (int)glyph->mBitmapWidth, nPenY, 0,
97d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            glyph->mBitmapMaxU, glyph->mBitmapMaxV,
98d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
99d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0,
100d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            glyph->mBitmapMaxU, glyph->mBitmapMinV,
101d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
102d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            nPenX, nPenY - (int)glyph->mBitmapHeight, 0,
103d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                            glyph->mBitmapMinU, glyph->mBitmapMinV);
104d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
105d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
106d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y)
107d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
108d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
109d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
110d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
111d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
112d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    int penX = x, penY = y;
113d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    int glyphsLeft = 1;
114d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(numGlyphs > 0) {
115d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        glyphsLeft = numGlyphs;
116d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
117d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
118d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t index = start;
119d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t nextIndex = 0;
120d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
121d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    while (glyphsLeft > 0) {
122d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
123d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        int32_t utfChar = utf32_at(text, len, index, &nextIndex);
124d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
125d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Reached the end of the string or encountered
126d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(utfChar < 0) {
127d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
128d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
129d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
130d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Move to the next character in the array
131d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        index = nextIndex;
132d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
13301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
134d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
135d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
136d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(cachedGlyph->mIsValid) {
137d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            drawCachedGlyph(cachedGlyph, penX, penY);
138d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
139d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
140d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        penX += (cachedGlyph->mAdvance.x >> 6);
141d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
142d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
143d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(numGlyphs > 0) {
144d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            glyphsLeft --;
145d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
146d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
147d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
148d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
14901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
15001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
15101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
15201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    if(cachedGlyph == NULL) {
15301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
15401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
15501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Is the glyph still in texture cache?
15601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    if(!cachedGlyph->mIsValid) {
15701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        updateGlyphCache(cachedGlyph);
15801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
15901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
16001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return cachedGlyph;
16101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
16201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
163d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph)
164d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
165a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
166a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    if(error) {
167a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        LOGE("Couldn't load glyph.");
168a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        return;
169a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
170d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
171a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mAdvance = mFace->glyph->advance;
172a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
173a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
174d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
175a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
176d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
177d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
178d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
179d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
180d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
181d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
182d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
183a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
184d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
185d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!glyph->mIsValid) {
186d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
187d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
188d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
189a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endX = startX + bitmap->width;
190a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
191d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
192d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinX = startX;
193d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinY = startY;
194a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
195a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
196d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
197d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
198d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
199d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
200d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
201d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
202d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
203d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
204d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
205d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
206d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
207d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
208d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
209d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
210d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
211d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
212d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mIsValid = false;
213d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
214d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    updateGlyphCache(newGlyph);
215d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
216d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return newGlyph;
217d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
218d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
219d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
220d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
22135b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    rsc->mStateFont.checkInit();
222d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
223d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
224d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < activeFonts.size(); i ++) {
225d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        Font *ithFont = activeFonts[i];
226d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
227d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return ithFont;
228d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
229d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
230d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
231d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *newFont = new Font(rsc);
232d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi);
233d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(isInitialized) {
234d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        activeFonts.push(newFont);
23501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
236d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return newFont;
237d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
238d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
239d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    delete newFont;
240d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return NULL;
241d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
242d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
243d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
244d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFont::~Font()
245d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
246d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mFace) {
247d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        FT_Done_Face(mFace);
248d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
249d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
250d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
251d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
252d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            mRSC->mStateFont.mActiveFonts.removeAt(ct);
253d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
254d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
255d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
256d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
257d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
258d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
259d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete glyph;
260d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
261d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
262d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
263d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFontState::FontState()
264d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
265d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
266d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
267d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex = 0;
268d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC = NULL;
2693659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mLibrary = NULL;
270ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
271d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
272d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
273d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukFontState::~FontState()
274d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
275d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
276d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete mCacheLines[i];
277d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
278d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
279d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
280d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
281d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
282a1ccecd965c07c2739f1258989526051a010bdabAlex SakhartchoukFT_Library FontState::getLib()
283d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
284d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!mLibrary) {
285a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
286d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(error) {
287d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            LOGE("Unable to initialize freetype");
288a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk            return NULL;
289d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
290d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
2913659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
292a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return mLibrary;
293a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk}
294d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
295a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchoukvoid FontState::init(Context *rsc)
296a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk{
297a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mRSC = rsc;
298d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
299d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
300d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::flushAllAndInvalidate()
301d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
302d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
303d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
304d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
305d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
306d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
307d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
308d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
309d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
310d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
311d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
312d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
313d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
314d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
315d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
316d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the glyph is too tall, don't cache it
317d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
318d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
319d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
320d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
321d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
322d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
323d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
324d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
325d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
326d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool bitmapFit = false;
327d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
328d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
329d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(bitmapFit) {
330d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
331d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
332d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
333d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
334d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
335d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!bitmapFit) {
336d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        flushAllAndInvalidate();
337d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
338d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Try to fit it again
339d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
340d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
341d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            if(bitmapFit) {
342d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                break;
343d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            }
344d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
345d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
346d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
347d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if(!bitmapFit) {
348d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
349d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return false;
350d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
351d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
352d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
353d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginX = startX;
354d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginY = startY;
355d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
356d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
357d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
358d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
359d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
360d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
361d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
362d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    unsigned char *bitmapBuffer = bitmap->buffer;
363d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
364d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
365d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
366d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
367d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
368d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
369d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
370d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
371d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
372d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // This will dirty the texture and the shader so next time
373d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // we draw it will upload the data
374d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
375d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontShaderF->bindTexture(0, mTextTexture.get());
376d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
377d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Some debug code
378d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
379d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
380d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
381d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
382d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
383d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }*/
384d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
385d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
386d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
387d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
388d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::initRenderState()
389d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
390e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    String8 shaderString("varying vec4 varTex0;\n");
391e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("void main() {\n");
392e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
393e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
394e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
395e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("}\n");
396e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
397e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
398e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
399e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
400e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
401e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
402e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    Type *inputType = new Type(mRSC);
403e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    inputType->setElement(constInput);
404e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    inputType->setDimX(1);
405e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    inputType->compute();
406e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
407e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    uint32_t tmp[4];
408e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
409e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[1] = (uint32_t)inputType;
410e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
411e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[3] = 1;
412e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
413e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mFontShaderFConstant.set(new Allocation(mRSC, inputType));
414e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
415e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk                                              shaderString.length(), tmp, 4);
416d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontShaderF.set(pf);
417e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mFontShaderF->bindAllocation(mFontShaderFConstant.get(), 0);
418d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
419d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
420d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
421d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSampler.set(sampler);
422d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontShaderF->bindSampler(0, sampler);
423d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
424d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    ProgramStore *fontStore = new ProgramStore(mRSC);
425d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore.set(fontStore);
426d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
427d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
428d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setDitherEnable(false);
429d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setDepthMask(false);
430d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
431d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
432d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::initTextTexture()
433d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
434d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
435d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
436d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
437d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Type *texType = new Type(mRSC);
438d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    texType->setElement(alphaElem);
439d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    texType->setDimX(1024);
440d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    texType->setDimY(256);
441d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    texType->compute();
442d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
443d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Allocation *cacheAlloc = new Allocation(mRSC, texType);
444d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
445d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
446d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
447d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
448d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    int nextLine = 0;
449d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
450d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
451d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
452d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
45301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
45401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
455d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
456d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
457d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
458d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
459d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
460d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
461d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
462d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
463d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
464d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
465d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::initVertexArrayBuffers()
466d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
467d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now lets write index data
468d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
469d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Type *indexType = new Type(mRSC);
470d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
471d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    indexType->setDimX(numIndicies);
472d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    indexType->setElement(indexElem);
473d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    indexType->compute();
474d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
475d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Allocation *indexAlloc = new Allocation(mRSC, indexType);
476d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
477d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
478d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
479d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
480d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        int i6 = i * 6;
481d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        int i4 = i * 4;
482d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
483d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
484d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
485d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
486d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
487d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
488d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
489d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
490d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
491d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
492d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    indexAlloc->deferedUploadToBufferObject(mRSC);
493d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mIndexBuffer.set(indexAlloc);
494d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
495d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
496d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
497d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
498d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *elemArray[2];
499d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    elemArray[0] = posElem;
500d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    elemArray[1] = texElem;
501d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
502d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    String8 posName("position");
503d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    String8 texName("texture0");
504d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
505d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const char *nameArray[2];
506d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nameArray[0] = posName.string();
507d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nameArray[1] = texName.string();
508d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t lengths[2];
509d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    lengths[0] = posName.size();
510d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    lengths[1] = texName.size();
51146e45548dc80e801139c9ccc2f2aa927e7f35027Jason Sams    uint32_t arraySizes[2] = {1, 1};
512d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
51346e45548dc80e801139c9ccc2f2aa927e7f35027Jason Sams    const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
514d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
515d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Type *vertexDataType = new Type(mRSC);
516d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    vertexDataType->setDimX(mMaxNumberOfQuads * 4);
517d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    vertexDataType->setElement(vertexDataElem);
518d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    vertexDataType->compute();
519d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
520d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
521d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
522d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
523d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mVertexArray.set(vertexAlloc);
524d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
525d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
526d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
527d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::checkInit()
528d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
529d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mInitialized) {
530d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
531d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
532d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
533d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initTextTexture();
534d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initRenderState();
535d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
536d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initVertexArrayBuffers();
537d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
53835b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
53935b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
54035b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
54135b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
54235b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("0123456789");
54335b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk
544d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
545d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
546d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
547d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::issueDrawCommand() {
548d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
549d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
550d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setVertex(mRSC->getDefaultProgramVertex());
551d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
552d18c744a37441311c9b65254a35db456835adad3Alex Sakhartchouk    ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
553d18c744a37441311c9b65254a35db456835adad3Alex Sakhartchouk    mRSC->setRaster(mRSC->getDefaultProgramRaster());
554d18c744a37441311c9b65254a35db456835adad3Alex Sakhartchouk
555d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
556d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setFragment(mFontShaderF.get());
557d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
558d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
559d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setFragmentStore(mFontProgramStore.get());
560d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
561ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    if(mFontColorDirty) {
562e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk        mFontShaderFConstant->data(mRSC, &mFontColor, 4*sizeof(float));
563ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk        mFontColorDirty = false;
564ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    }
565ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
566d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if (!mRSC->setupCheck()) {
567d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mRSC->setVertex((ProgramVertex *)tmpV.get());
568d18c744a37441311c9b65254a35db456835adad3Alex Sakhartchouk        mRSC->setRaster((ProgramRaster *)tmpR.get());
569d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mRSC->setFragment((ProgramFragment *)tmpF.get());
570d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
571d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
572d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
573d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
574d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *vtx = (float*)mVertexArray->getPtr();
575d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *tex = vtx + 3;
576d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
577d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    VertexArray va;
578d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "position");
579d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "texture0");
580d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
581d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
582d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mIndexBuffer->uploadCheck(mRSC);
583d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
584d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
585d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
586d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Reset the state
587d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setVertex((ProgramVertex *)tmpV.get());
588d18c744a37441311c9b65254a35db456835adad3Alex Sakhartchouk    mRSC->setRaster((ProgramRaster *)tmpR.get());
589d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setFragment((ProgramFragment *)tmpF.get());
590d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
591d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
592d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
593d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
594d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float u1, float v1,
595d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float x2, float y2, float z2,
596d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float u2, float v2,
597d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float x3, float y3, float z3,
598d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float u3, float v3,
599d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float x4, float y4, float z4,
600d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                  float u4, float v4)
601d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
602d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
603d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
604d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
605d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
606d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Cull things that are off the screen
607d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float width = (float)mRSC->getWidth();
608d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float height = (float)mRSC->getHeight();
609d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
610d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
611d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
612d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
613d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
614d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
615d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
616d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
617d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
618d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
619d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x1;
620d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y1;
621d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z1;
622d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u1;
623d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v1;
624d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
625d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x2;
626d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y2;
627d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z2;
628d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u2;
629d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v2;
630d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
631d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x3;
632d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y3;
633d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z3;
634d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u3;
635d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v3;
636d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
637d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x4;
638d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y4;
639d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z4;
640d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u4;
641d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v4;
642d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
643d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex ++;
644d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
645d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mCurrentQuadIndex == mMaxNumberOfQuads) {
646d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
647d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
648d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
649d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
650d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
65101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
65201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = 0;
65335b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    uint32_t totalPixels = 0;
65401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
65501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
65601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
65701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
65801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
65901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return remainingCapacity;
66001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
66101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
66201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
66301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Remaining capacity is measured in %
66401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
66501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t precacheIdx = 0;
66601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
66701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
66801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
66901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        precacheIdx ++;
67001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
67101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
67201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
67301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
674d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
675d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
676d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    checkInit();
677d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
678d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Render code here
679d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
680a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    if(!currentFont) {
681a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        if(!mDefault.get()) {
682a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk            mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
683a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        }
684a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        currentFont = mDefault.get();
685a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
6863659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    if(!currentFont) {
6873659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        LOGE("Unable to initialize any fonts");
6883659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        return;
6893659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
6903659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
691d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
692d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
693d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
694d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
695d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
696d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
697d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
698d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
699d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::renderText(const char *text, int x, int y)
700d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
701d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t textLen = strlen(text);
702d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    renderText(text, textLen, 0, -1, x, y);
703d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
704d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
705d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::renderText(Allocation *alloc, int x, int y)
706d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
707d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!alloc) {
708d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
709d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
710d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
711d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const char *text = (const char *)alloc->getPtr();
712d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t allocSize = alloc->getType()->getSizeBytes();
713d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    renderText(text, allocSize, 0, -1, x, y);
714d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
715d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
716d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
717d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
718d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if(!alloc) {
719d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
720d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
721d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
722d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const char *text = (const char *)alloc->getPtr();
723d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t allocSize = alloc->getType()->getSizeBytes();
724d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    renderText(text, allocSize, start, len, x, y);
725d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
726d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
7279fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
7289fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk    mFontColor[0] = r;
7299fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk    mFontColor[1] = g;
7309fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk    mFontColor[2] = b;
7319fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk    mFontColor[3] = a;
7329fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk    mFontColorDirty = true;
7339fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk}
7349fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk
735ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
736ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    *r = mFontColor[0];
737ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    *g = mFontColor[1];
738ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    *b = mFontColor[2];
739ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    *a = mFontColor[3];
740ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk}
741ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
742d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::deinit(Context *rsc)
743d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
744a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mInitialized = false;
745a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
746a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mIndexBuffer.clear();
747a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mVertexArray.clear();
748a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
749a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontShaderF.clear();
750a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontSampler.clear();
751a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontProgramStore.clear();
752a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
753a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mTextTexture.clear();
754a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
755a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        delete mCacheLines[i];
756d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
757a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mCacheLines.clear();
758d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
759d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDefault.clear();
760a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
7613659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    Vector<Font*> fontsToDereference = mActiveFonts;
7623659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
7633659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        fontsToDereference[i]->zeroUserRef();
7643659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
7653659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
766a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    if(mLibrary) {
767a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Done_FreeType( mLibrary );
7683659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        mLibrary = NULL;
769a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
770d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
771d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
772d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace android {
773d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace renderscript {
774d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
775d3e0ad43dc758c409fc23d1893dab67b18520c24Alex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
776d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk{
777a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
778a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    if(newFont) {
779a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        newFont->incUserRef();
780a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
781a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return newFont;
782d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
783d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
784d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // renderscript
785d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // android
786