rsFont.cpp revision b38d534873ca514f5a5230596c838aa37eca1568
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"
263bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk#include <cutils/properties.h>
279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include FT_BITMAP_H
289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES/gl.h>
309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES/glext.h>
319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES2/gl2.h>
329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES2/gl2ext.h>
339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukusing namespace android;
359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukusing namespace android::renderscript;
369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
379b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL)
389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = false;
41b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mFace = NULL;
429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukbool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mInitialized) {
479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 fontsDir("/fonts/");
529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 fullPath(getenv("ANDROID_ROOT"));
539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    fullPath += fontsDir;
549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    fullPath += name;
559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
56071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(error) {
589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Unable to initialize font %s", fullPath.string());
599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontName = name;
639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSize = fontSize;
649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDpi = dpi;
659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(error) {
689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Unable to set font size on %s", fullPath.string());
699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::invalidateTextureCache()
799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y)
869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
9010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
9210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float u1 = glyph->mBitmapMinU;
9310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float u2 = glyph->mBitmapMaxU;
9410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float v1 = glyph->mBitmapMinV;
9510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float v2 = glyph->mBitmapMaxV;
969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
9710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
9810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
10010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
10110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX + width, nPenY, 0, u2, v2,
10210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX + width, nPenY - height, 0, u2, v1,
10310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX, nPenY - height, 0, u1, v1);
10410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk}
10510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
10610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
10710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
10810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
10910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y + glyph->mBitmapTop;
11010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
11110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
11210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
11310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
11410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
11510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
11610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    const uint8_t* cacheBuffer = state->getTextTextureData();
11710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
11810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
11910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t bX = 0, bY = 0;
12010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
12110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
12210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
12310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                LOGE("Skipping invalid index");
12410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                continue;
12510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            }
12610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
12710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
12810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        }
12910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
1309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
1329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
13310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
13410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
13510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
13610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
13710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
13810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
13910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
14010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->bottom > nPenY) {
14110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->bottom = nPenY;
14210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
14310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->left > nPenX) {
14410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->left = nPenX;
14510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
14610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->right < nPenX + width) {
14710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->right = nPenX + width;
14810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
14910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->top < nPenY + height) {
15010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->top = nPenY + height;
15110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
15210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk}
15310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
15410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
15510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     uint32_t start, int32_t numGlyphs,
15610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     RenderMode mode, Rect *bounds,
15710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
1589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
1599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
1609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
1619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
16310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if(mode == Font::MEASURE) {
16410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        if (bounds == NULL) {
16510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            LOGE("No return rectangle provided to measure text");
16610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            return;
16710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        }
16810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        // Reset min and max of the bounding box to something large
16910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->set(1e6, -1e6, -1e6, 1e6);
17010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
17110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
17210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t penX = x, penY = y;
17310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t glyphsLeft = 1;
1749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(numGlyphs > 0) {
1759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        glyphsLeft = numGlyphs;
1769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t index = start;
1799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t nextIndex = 0;
1809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    while (glyphsLeft > 0) {
1829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        int32_t utfChar = utf32_at(text, len, index, &nextIndex);
1849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Reached the end of the string or encountered
1869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(utfChar < 0) {
1879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
1889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Move to the next character in the array
1919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        index = nextIndex;
1929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
19394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
1949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
1969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(cachedGlyph->mIsValid) {
19710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            switch(mode) {
19810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case FRAMEBUFFER:
19910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
20010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
20110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case BITMAP:
20210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
20310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
20410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case MEASURE:
20510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
20610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
20710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            }
2089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        penX += (cachedGlyph->mAdvance.x >> 6);
2119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
2139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(numGlyphs > 0) {
2149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            glyphsLeft --;
2159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
21994bbccc36322168a596369c8341dad938c8f949fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
22094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
22194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
22294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    if(cachedGlyph == NULL) {
22394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
22494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
22594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Is the glyph still in texture cache?
22694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    if(!cachedGlyph->mIsValid) {
22794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        updateGlyphCache(cachedGlyph);
22894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
22994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
23094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return cachedGlyph;
23194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
23294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
2339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph)
2349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
235071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
236071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(error) {
237071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        LOGE("Couldn't load glyph.");
238071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        return;
239071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
2409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
241071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mAdvance = mFace->glyph->advance;
242071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
243071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
2449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
245071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
2469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
2489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
2499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
2509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
2529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
253071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
2549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!glyph->mIsValid) {
2569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
2579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
259071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
260071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
2619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinX = startX;
2639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinY = startY;
264071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
265071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
2669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
2689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
2699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
2719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
2729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
2739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
2749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2769b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
2779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
2799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
2809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
2829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mIsValid = false;
2839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    updateGlyphCache(newGlyph);
2859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return newGlyph;
2879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2899b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
2909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
29127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    rsc->mStateFont.checkInit();
2929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
2939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < activeFonts.size(); i ++) {
2959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        Font *ithFont = activeFonts[i];
2969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
2979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return ithFont;
2989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *newFont = new Font(rsc);
3029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi);
3039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(isInitialized) {
3049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        activeFonts.push(newFont);
30594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
3069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return newFont;
3079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
309b38d534873ca514f5a5230596c838aa37eca1568Jason Sams    ObjectBase::checkDelete(newFont);
3109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return NULL;
3119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3149b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::~Font()
3159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mFace) {
3179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        FT_Done_Face(mFace);
3189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
3219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
3229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            mRSC->mStateFont.mActiveFonts.removeAt(ct);
3239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
3249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
3289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
3299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete glyph;
3309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3339b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFontState::FontState()
3349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
3369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
3379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex = 0;
3389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC = NULL;
339b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mLibrary = NULL;
3403bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3413bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the renderer properties
3423bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
3433bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3443bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the gamma
3453bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    float gamma = DEFAULT_TEXT_GAMMA;
3463bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
3473bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Setting text gamma to %s", property);
3483bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        gamma = atof(property);
3493bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else {
3503bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
3513bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3523bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3533bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the black gamma threshold
35410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
3553bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
3563bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Setting text black gamma threshold to %s", property);
3573bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        blackThreshold = atoi(property);
3583bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else {
3593bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Using default text black gamma threshold of %d",
3603bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk                DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
3613bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3623bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mBlackThreshold = (float)(blackThreshold) / 255.0f;
3633bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3643bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the white gamma threshold
36510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
3663bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
3673bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Setting text white gamma threshold to %s", property);
3683bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        whiteThreshold = atoi(property);
3693bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else {
3703bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Using default white black gamma threshold of %d",
3713bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk                DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
3723bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3733bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
3743bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3753bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Compute the gamma tables
3763bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mBlackGamma = gamma;
3773bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
378960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk
379960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
3809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3829b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFontState::~FontState()
3839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
3859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete mCacheLines[i];
3869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
3899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
391071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex SakhartchoukFT_Library FontState::getLib()
3929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!mLibrary) {
394071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
3959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(error) {
3969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Unable to initialize freetype");
397071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            return NULL;
3989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
400b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
401071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return mLibrary;
402071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk}
4039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
404071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchoukvoid FontState::init(Context *rsc)
405071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk{
406071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mRSC = rsc;
4079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::flushAllAndInvalidate()
4109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
4119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
4129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
4139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
4149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
4169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
4179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
4199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
4209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
4249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
4259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the glyph is too tall, don't cache it
4269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
4279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
4289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
4299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
4329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
4339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
4349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool bitmapFit = false;
4369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
4379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
4389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(bitmapFit) {
4399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
4409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
4449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!bitmapFit) {
4459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        flushAllAndInvalidate();
4469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Try to fit it again
4489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
4499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
4509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            if(bitmapFit) {
4519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                break;
4529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            }
4539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
4569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(!bitmapFit) {
4579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
4589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return false;
4599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginX = startX;
4639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginY = startY;
4649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
4669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
4679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
4699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
47010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
47110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
4729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
4749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
4759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
47610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
4779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
4789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // This will dirty the texture and the shader so next time
4829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // we draw it will upload the data
4839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
484b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
4859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Some debug code
4879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
4889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
4899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
4909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
4919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }*/
4939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
4959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initRenderState()
4989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
499d2091639be426574c04f74969fe553162d7a51c9Alex Sakhartchouk    String8 shaderString("varying vec2 varTex0;\n");
500c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("void main() {\n");
501c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
502c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
5033bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
504c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
505c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("}\n");
506c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
507c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
5083bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
509c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
510c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
5113bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
512c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
513c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
514c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    Type *inputType = new Type(mRSC);
515c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    inputType->setElement(constInput);
516c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    inputType->setDimX(1);
517c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    inputType->compute();
518c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
519c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    uint32_t tmp[4];
520c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
521c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[1] = (uint32_t)inputType;
522c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
523c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[3] = 1;
524c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
525c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mFontShaderFConstant.set(new Allocation(mRSC, inputType));
526c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
527c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk                                              shaderString.length(), tmp, 4);
5289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontShaderF.set(pf);
529b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
5309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
5329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
5339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSampler.set(sampler);
534b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, sampler);
5359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ProgramStore *fontStore = new ProgramStore(mRSC);
5379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore.set(fontStore);
5389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
5399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
5409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDitherEnable(false);
5419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthMask(false);
5429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initTextTexture()
5459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
5469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
5479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
5499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *texType = new Type(mRSC);
5509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setElement(alphaElem);
5519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setDimX(1024);
5529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setDimY(256);
5539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->compute();
5549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *cacheAlloc = new Allocation(mRSC, texType);
5569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
5579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
5589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
56010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nextLine = 0;
5619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
5629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
5649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
56594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
56694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
5689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
5709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
5729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
5749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
5779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initVertexArrayBuffers()
5789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
5799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now lets write index data
5809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
5819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *indexType = new Type(mRSC);
5829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
5839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->setDimX(numIndicies);
5849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->setElement(indexElem);
5859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->compute();
5869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *indexAlloc = new Allocation(mRSC, indexType);
5889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
5899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
5919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
59210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        int32_t i6 = i * 6;
59310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        int32_t i4 = i * 4;
5949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
5969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
5979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
5989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
6009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
6019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
6029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexAlloc->deferedUploadToBufferObject(mRSC);
6059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer.set(indexAlloc);
6069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
6089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
6099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
61098bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
61198bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
61298bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
61398bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
6149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *vertexDataType = new Type(mRSC);
6169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->setDimX(mMaxNumberOfQuads * 4);
6179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->setElement(vertexDataElem);
6189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->compute();
6199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
6219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
6229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mVertexArray.set(vertexAlloc);
6249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
6279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::checkInit()
6289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
6299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mInitialized) {
6309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initTextTexture();
6349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initRenderState();
6359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initVertexArrayBuffers();
6379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
63827f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
63927f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
64027f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
64127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
64227f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("0123456789");
64327f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk
6449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
6459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::issueDrawCommand() {
6489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
6509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setVertex(mRSC->getDefaultProgramVertex());
6519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
65280a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
65380a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    mRSC->setRaster(mRSC->getDefaultProgramRaster());
65480a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk
6559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
6569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragment(mFontShaderF.get());
6579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
6599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragmentStore(mFontProgramStore.get());
6609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6613bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if(mConstantsDirty) {
6623bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
6633bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstantsDirty = false;
66455e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    }
66555e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
6669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if (!mRSC->setupCheck()) {
6679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setVertex((ProgramVertex *)tmpV.get());
66880a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk        mRSC->setRaster((ProgramRaster *)tmpR.get());
6699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setFragment((ProgramFragment *)tmpF.get());
6709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
6719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *vtx = (float*)mVertexArray->getPtr();
6759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *tex = vtx + 3;
6769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    VertexArray va;
6784378f1175546616c76ecb7f0b1159940ab22d5f4Alex Sakhartchouk    va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
6794378f1175546616c76ecb7f0b1159940ab22d5f4Alex Sakhartchouk    va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
6809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
6819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer->uploadCheck(mRSC);
6839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
6849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
6859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Reset the state
6879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setVertex((ProgramVertex *)tmpV.get());
68880a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    mRSC->setRaster((ProgramRaster *)tmpR.get());
6899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragment((ProgramFragment *)tmpF.get());
6909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
6919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
6949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u1, float v1,
6959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x2, float y2, float z2,
6969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u2, float v2,
6979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x3, float y3, float z3,
6989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u3, float v3,
6999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x4, float y4, float z4,
7009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u4, float v4)
7019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
7029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
7039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
7049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
7059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Cull things that are off the screen
7079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float width = (float)mRSC->getWidth();
7089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float height = (float)mRSC->getHeight();
7099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
7119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
7129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
7159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
7169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
7179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
7189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x1;
7209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y1;
7219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z1;
7229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u1;
7239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v1;
7249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x2;
7269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y2;
7279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z2;
7289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u2;
7299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v2;
7309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x3;
7329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y3;
7339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z3;
7349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u3;
7359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v3;
7369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x4;
7389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y4;
7399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z4;
7409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u4;
7419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v4;
7429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex ++;
7449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex == mMaxNumberOfQuads) {
7469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
7479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
7489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
75194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
75294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = 0;
75327f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    uint32_t totalPixels = 0;
75494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
75594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
75694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
75794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
75894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
75994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return remainingCapacity;
76094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
76194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
76294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
76394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Remaining capacity is measured in %
76494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
76594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t precacheIdx = 0;
76694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
76794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
76894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
76994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        precacheIdx ++;
77094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
77194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
77294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
77394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
77410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
77510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
77610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           Font::RenderMode mode,
77710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           Font::Rect *bounds,
77810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
7799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
7809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    checkInit();
7819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Render code here
7839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
784071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(!currentFont) {
785071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        if(!mDefault.get()) {
786071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
787071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        }
788071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        currentFont = mDefault.get();
789071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
790b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    if(!currentFont) {
791b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        LOGE("Unable to initialize any fonts");
792b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        return;
793b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
794b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
79510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
79610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
7979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
7999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
8009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
8019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
8029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
80410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
80510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
8069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
808fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
8093bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[0] = r;
8103bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[1] = g;
8113bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[2] = b;
8123bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[3] = a;
8133bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
8143bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mGamma = 1.0f;
81576322af2a6c109a79431f019dcef6e038c030686Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
8163bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (luminance <= mBlackThreshold) {
8173bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstants.mGamma = mBlackGamma;
8183bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
8193bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
8203bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
821960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk
8223bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstantsDirty = true;
823fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk}
824fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk
82555e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
8263bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *r = mConstants.mFontColor[0];
8273bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *g = mConstants.mFontColor[1];
8283bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *b = mConstants.mFontColor[2];
8293bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *a = mConstants.mFontColor[3];
83055e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk}
83155e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
8329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::deinit(Context *rsc)
8339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
834071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mInitialized = false;
835071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
83601f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines    mFontShaderFConstant.clear();
83701f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines
838071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mIndexBuffer.clear();
839071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mVertexArray.clear();
840071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
841071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontShaderF.clear();
842071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontSampler.clear();
843071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontProgramStore.clear();
844071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
845071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mTextTexture.clear();
846071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
847071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        delete mCacheLines[i];
8489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
849071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mCacheLines.clear();
8509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDefault.clear();
852071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
853b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    Vector<Font*> fontsToDereference = mActiveFonts;
854b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
855b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        fontsToDereference[i]->zeroUserRef();
856b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
857b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
858071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(mLibrary) {
859071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Done_FreeType( mLibrary );
860b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        mLibrary = NULL;
861071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
8629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace android {
8659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace renderscript {
8669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8679b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
8689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
869071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
870071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(newFont) {
871071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        newFont->incUserRef();
872071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
873071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return newFont;
8749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // renderscript
8779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // android
878