rsFont.cpp revision 76322af2a6c109a79431f019dcef6e038c030686
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{
39071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mAllocFile = __FILE__;
40071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mAllocLine = __LINE__;
419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = false;
43b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mFace = NULL;
449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukbool Font::init(const char *name, uint32_t fontSize, uint32_t dpi)
479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mInitialized) {
499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 fontsDir("/fonts/");
549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 fullPath(getenv("ANDROID_ROOT"));
559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    fullPath += fontsDir;
569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    fullPath += name;
579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
58071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(error) {
609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Unable to initialize font %s", fullPath.string());
619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontName = name;
659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSize = fontSize;
669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDpi = dpi;
679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(error) {
709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Unable to set font size on %s", fullPath.string());
719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::invalidateTextureCache()
819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y)
889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
9110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
9210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
9410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float u1 = glyph->mBitmapMinU;
9510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float u2 = glyph->mBitmapMaxU;
9610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float v1 = glyph->mBitmapMinV;
9710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float v2 = glyph->mBitmapMaxV;
989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
9910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
10010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
1019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
10210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
10310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX + width, nPenY, 0, u2, v2,
10410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX + width, nPenY - height, 0, u2, v1,
10510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX, nPenY - height, 0, u1, v1);
10610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk}
10710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
10810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
10910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
11010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
11110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y + glyph->mBitmapTop;
11210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
11310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
11410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
11510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
11610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
11710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
11810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    const uint8_t* cacheBuffer = state->getTextTextureData();
11910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
12010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
12110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t bX = 0, bY = 0;
12210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
12310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
12410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
12510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                LOGE("Skipping invalid index");
12610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                continue;
12710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            }
12810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
12910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
13010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        }
13110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
1329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
1349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
13510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
13610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
13710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
13810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
13910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
14010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
14110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
14210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->bottom > nPenY) {
14310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->bottom = nPenY;
14410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
14510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->left > nPenX) {
14610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->left = nPenX;
14710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
14810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->right < nPenX + width) {
14910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->right = nPenX + width;
15010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
15110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->top < nPenY + height) {
15210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->top = nPenY + height;
15310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
15410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk}
15510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
15610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
15710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     uint32_t start, int32_t numGlyphs,
15810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     RenderMode mode, Rect *bounds,
15910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
1609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
1619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
1629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
1639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
16510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if(mode == Font::MEASURE) {
16610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        if (bounds == NULL) {
16710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            LOGE("No return rectangle provided to measure text");
16810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            return;
16910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        }
17010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        // Reset min and max of the bounding box to something large
17110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->set(1e6, -1e6, -1e6, 1e6);
17210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
17310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
17410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t penX = x, penY = y;
17510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t glyphsLeft = 1;
1769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(numGlyphs > 0) {
1779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        glyphsLeft = numGlyphs;
1789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t index = start;
1819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t nextIndex = 0;
1829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    while (glyphsLeft > 0) {
1849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        int32_t utfChar = utf32_at(text, len, index, &nextIndex);
1869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Reached the end of the string or encountered
1889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(utfChar < 0) {
1899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
1909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Move to the next character in the array
1939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        index = nextIndex;
1949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
19594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
1969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
1989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(cachedGlyph->mIsValid) {
19910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            switch(mode) {
20010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case FRAMEBUFFER:
20110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
20210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
20310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case BITMAP:
20410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
20510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
20610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case MEASURE:
20710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
20810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
20910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            }
2109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        penX += (cachedGlyph->mAdvance.x >> 6);
2139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
2159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(numGlyphs > 0) {
2169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            glyphsLeft --;
2179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
22194bbccc36322168a596369c8341dad938c8f949fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
22294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
22394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
22494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    if(cachedGlyph == NULL) {
22594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
22694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
22794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Is the glyph still in texture cache?
22894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    if(!cachedGlyph->mIsValid) {
22994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        updateGlyphCache(cachedGlyph);
23094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
23194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
23294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return cachedGlyph;
23394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
23494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
2359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph)
2369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
237071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
238071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(error) {
239071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        LOGE("Couldn't load glyph.");
240071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        return;
241071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
2429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
243071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mAdvance = mFace->glyph->advance;
244071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
245071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
2469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
247071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
2489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
2509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
2519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
2529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
2549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
255071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
2569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!glyph->mIsValid) {
2589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
2599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
261071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
262071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
2639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinX = startX;
2659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinY = startY;
266071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
267071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
2689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
2709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
2719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
2739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
2749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
2759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
2769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2789b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph)
2799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
2809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
2819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
2829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
2849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mIsValid = false;
2859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    updateGlyphCache(newGlyph);
2879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return newGlyph;
2899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2919b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi)
2929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
29327f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    rsc->mStateFont.checkInit();
2949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
2959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < activeFonts.size(); i ++) {
2979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        Font *ithFont = activeFonts[i];
2989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
2999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return ithFont;
3009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *newFont = new Font(rsc);
3049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi);
3059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(isInitialized) {
3069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        activeFonts.push(newFont);
30794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
3089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return newFont;
3099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    delete newFont;
3129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return NULL;
3139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3169b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFont::~Font()
3179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mFace) {
3199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        FT_Done_Face(mFace);
3209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
3239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
3249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            mRSC->mStateFont.mActiveFonts.removeAt(ct);
3259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
3269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
3309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
3319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete glyph;
3329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3359b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFontState::FontState()
3369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
3389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
3399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex = 0;
3409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC = NULL;
341b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mLibrary = NULL;
34255e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
3433bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3443bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the renderer properties
3453bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
3463bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3473bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the gamma
3483bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    float gamma = DEFAULT_TEXT_GAMMA;
3493bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
3503bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Setting text gamma to %s", property);
3513bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        gamma = atof(property);
3523bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else {
3533bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
3543bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3553bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3563bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the black gamma threshold
35710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
3583bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
3593bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Setting text black gamma threshold to %s", property);
3603bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        blackThreshold = atoi(property);
3613bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else {
3623bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Using default text black gamma threshold of %d",
3633bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk                DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
3643bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3653bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mBlackThreshold = (float)(blackThreshold) / 255.0f;
3663bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3673bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the white gamma threshold
36810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
3693bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
3703bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Setting text white gamma threshold to %s", property);
3713bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        whiteThreshold = atoi(property);
3723bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else {
3733bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Using default white black gamma threshold of %d",
3743bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk                DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
3753bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3763bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
3773bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3783bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Compute the gamma tables
3793bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mBlackGamma = gamma;
3803bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
3819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3839b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukFontState::~FontState()
3849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
3869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete mCacheLines[i];
3879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
3909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
392071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex SakhartchoukFT_Library FontState::getLib()
3939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
3949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!mLibrary) {
395071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
3969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(error) {
3979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Unable to initialize freetype");
398071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            return NULL;
3999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
401b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
402071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return mLibrary;
403071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk}
4049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
405071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchoukvoid FontState::init(Context *rsc)
406071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk{
407071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mRSC = rsc;
4089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::flushAllAndInvalidate()
4119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
4129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
4139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
4149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
4159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mActiveFonts.size(); i ++) {
4179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
4189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
4209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
4219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY)
4259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
4269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the glyph is too tall, don't cache it
4279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
4289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
4299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
4309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
4339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
4349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
4359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool bitmapFit = false;
4379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
4389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
4399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(bitmapFit) {
4409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
4419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
4459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(!bitmapFit) {
4469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        flushAllAndInvalidate();
4479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Try to fit it again
4499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
4509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
4519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            if(bitmapFit) {
4529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                break;
4539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            }
4549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
4579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if(!bitmapFit) {
4589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
4599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return false;
4609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginX = startX;
4649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginY = startY;
4659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
4679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
4689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
4709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
47110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
47210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
4739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
4759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
4769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
47710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
4789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
4799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // This will dirty the texture and the shader so next time
4839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // we draw it will upload the data
4849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
485b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
4869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Some debug code
4889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
4899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
4909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
4919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
4929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }*/
4949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
4969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initRenderState()
4999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
500c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    String8 shaderString("varying vec4 varTex0;\n");
501c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("void main() {\n");
502c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
503c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
5043bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
505c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
506c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("}\n");
507c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
508c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
5093bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
510c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
511c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
5123bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
513c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
514c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
515c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    Type *inputType = new Type(mRSC);
516c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    inputType->setElement(constInput);
517c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    inputType->setDimX(1);
518c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    inputType->compute();
519c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
520c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    uint32_t tmp[4];
521c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
522c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[1] = (uint32_t)inputType;
523c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
524c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[3] = 1;
525c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
526c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mFontShaderFConstant.set(new Allocation(mRSC, inputType));
527c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
528c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk                                              shaderString.length(), tmp, 4);
5299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontShaderF.set(pf);
530b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
5319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
5339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
5349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSampler.set(sampler);
535b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, sampler);
5369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ProgramStore *fontStore = new ProgramStore(mRSC);
5389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore.set(fontStore);
5399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
5409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
5419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDitherEnable(false);
5429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthMask(false);
5439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initTextTexture()
5469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
5479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
5489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
5509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *texType = new Type(mRSC);
5519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setElement(alphaElem);
5529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setDimX(1024);
5539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->setDimY(256);
5549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    texType->compute();
5559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *cacheAlloc = new Allocation(mRSC, texType);
5579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
5589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
5599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
56110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nextLine = 0;
5629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
5639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
5659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
56694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
56794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
5699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
5719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
5739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
5759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
5789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::initVertexArrayBuffers()
5799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
5809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now lets write index data
5819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
5829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *indexType = new Type(mRSC);
5839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
5849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->setDimX(numIndicies);
5859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->setElement(indexElem);
5869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexType->compute();
5879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *indexAlloc = new Allocation(mRSC, indexType);
5899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
5909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
5929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
59310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        int32_t i6 = i * 6;
59410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        int32_t i4 = i * 4;
5959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
5979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
5989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
5999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
6019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
6029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
6039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexAlloc->deferedUploadToBufferObject(mRSC);
6069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer.set(indexAlloc);
6079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
6099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
6109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *elemArray[2];
6129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    elemArray[0] = posElem;
6139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    elemArray[1] = texElem;
6149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 posName("position");
6169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 texName("texture0");
6179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const char *nameArray[2];
6199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nameArray[0] = posName.string();
6209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nameArray[1] = texName.string();
6219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t lengths[2];
6229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    lengths[0] = posName.size();
6239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    lengths[1] = texName.size();
62470d4e5024298f71edb3b04867e05568f5495b4ceJason Sams    uint32_t arraySizes[2] = {1, 1};
6259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
62670d4e5024298f71edb3b04867e05568f5495b4ceJason Sams    const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
6279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Type *vertexDataType = new Type(mRSC);
6299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->setDimX(mMaxNumberOfQuads * 4);
6309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->setElement(vertexDataElem);
6319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    vertexDataType->compute();
6329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
6349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
6359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mVertexArray.set(vertexAlloc);
6379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
6409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::checkInit()
6419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
6429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mInitialized) {
6439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initTextTexture();
6479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initRenderState();
6489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initVertexArrayBuffers();
6509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
65127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
65227f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
65327f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
65427f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
65527f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("0123456789");
65627f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk
6579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
6589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::issueDrawCommand() {
6619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
6639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setVertex(mRSC->getDefaultProgramVertex());
6649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
66580a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
66680a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    mRSC->setRaster(mRSC->getDefaultProgramRaster());
66780a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk
6689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
6699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragment(mFontShaderF.get());
6709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
6729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragmentStore(mFontProgramStore.get());
6739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6743bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if(mConstantsDirty) {
6753bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
6763bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstantsDirty = false;
67755e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    }
67855e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
6799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if (!mRSC->setupCheck()) {
6809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setVertex((ProgramVertex *)tmpV.get());
68180a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk        mRSC->setRaster((ProgramRaster *)tmpR.get());
6829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setFragment((ProgramFragment *)tmpF.get());
6839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
6849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *vtx = (float*)mVertexArray->getPtr();
6889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *tex = vtx + 3;
6899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    VertexArray va;
6914378f1175546616c76ecb7f0b1159940ab22d5f4Alex Sakhartchouk    va.add(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
6924378f1175546616c76ecb7f0b1159940ab22d5f4Alex Sakhartchouk    va.add(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
6939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
6949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer->uploadCheck(mRSC);
6969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
6979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
6989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Reset the state
7009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setVertex((ProgramVertex *)tmpV.get());
70180a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    mRSC->setRaster((ProgramRaster *)tmpR.get());
7029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragment((ProgramFragment *)tmpF.get());
7039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
7049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
7079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u1, float v1,
7089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x2, float y2, float z2,
7099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u2, float v2,
7109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x3, float y3, float z3,
7119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u3, float v3,
7129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float x4, float y4, float z4,
7139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                  float u4, float v4)
7149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
7159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
7169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
7179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
7189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Cull things that are off the screen
7209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float width = (float)mRSC->getWidth();
7219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float height = (float)mRSC->getHeight();
7229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
7249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
7259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
7289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
7299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
7309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
7319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x1;
7339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y1;
7349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z1;
7359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u1;
7369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v1;
7379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x2;
7399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y2;
7409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z2;
7419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u2;
7429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v2;
7439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x3;
7459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y3;
7469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z3;
7479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u3;
7489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v3;
7499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x4;
7519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y4;
7529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z4;
7539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u4;
7549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v4;
7559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex ++;
7579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex == mMaxNumberOfQuads) {
7599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
7609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
7619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
76494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
76594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = 0;
76627f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    uint32_t totalPixels = 0;
76794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
76894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
76994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
77094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
77194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
77294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return remainingCapacity;
77394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
77494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
77594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
77694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Remaining capacity is measured in %
77794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
77894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t precacheIdx = 0;
77994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
78094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
78194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
78294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        precacheIdx ++;
78394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
78494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
78594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
78694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
78710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
78810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
78910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           Font::RenderMode mode,
79010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           Font::Rect *bounds,
79110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
7929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
7939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    checkInit();
7949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Render code here
7969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
797071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(!currentFont) {
798071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        if(!mDefault.get()) {
799071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
800071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        }
801071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        currentFont = mDefault.get();
802071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
803b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    if(!currentFont) {
804b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        LOGE("Unable to initialize any fonts");
805b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        return;
806b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
807b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
80810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
80910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
8109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if(mCurrentQuadIndex != 0) {
8129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
8139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
8149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
8159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
81710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
81810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
8199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
821fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
8223bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[0] = r;
8233bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[1] = g;
8243bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[2] = b;
8253bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[3] = a;
8263bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
8273bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mGamma = 1.0f;
82876322af2a6c109a79431f019dcef6e038c030686Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
8293bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (luminance <= mBlackThreshold) {
8303bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstants.mGamma = mBlackGamma;
8313bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
8323bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
8333bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
8343bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstantsDirty = true;
835fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk}
836fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk
83755e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
8383bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *r = mConstants.mFontColor[0];
8393bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *g = mConstants.mFontColor[1];
8403bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *b = mConstants.mFontColor[2];
8413bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *a = mConstants.mFontColor[3];
84255e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk}
84355e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
8449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::deinit(Context *rsc)
8459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
846071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mInitialized = false;
847071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
84801f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines    mFontShaderFConstant.clear();
84901f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines
850071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mIndexBuffer.clear();
851071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mVertexArray.clear();
852071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
853071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontShaderF.clear();
854071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontSampler.clear();
855071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontProgramStore.clear();
856071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
857071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mTextTexture.clear();
858071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
859071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        delete mCacheLines[i];
8609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
861071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mCacheLines.clear();
8629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDefault.clear();
864071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
865b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    Vector<Font*> fontsToDereference = mActiveFonts;
866b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    for(uint32_t i = 0; i < fontsToDereference.size(); i ++) {
867b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        fontsToDereference[i]->zeroUserRef();
868b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
869b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
870071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(mLibrary) {
871071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Done_FreeType( mLibrary );
872b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        mLibrary = NULL;
873071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
8749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace android {
8779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace renderscript {
8789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8799b949fce39f0f39ce9275b71d7c347210775e7a8Alex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi)
8809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk{
881071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
882071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    if(newFont) {
883071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        newFont->incUserRef();
884071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
885071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return newFont;
8869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // renderscript
8899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // android
890