rsFont.cpp revision 70b83c111beceaf8fbb700580833e7fec99272cf
1d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
2d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk/*
3d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Copyright (C) 2009 The Android Open Source Project
4d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
5d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Licensed under the Apache License, Version 2.0 (the "License");
6d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * you may not use this file except in compliance with the License.
7d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * You may obtain a copy of the License at
8d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
9d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *      http://www.apache.org/licenses/LICENSE-2.0
10d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
11d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Unless required by applicable law or agreed to in writing, software
12d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * distributed under the License is distributed on an "AS IS" BASIS,
13d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * See the License for the specific language governing permissions and
15d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * limitations under the License.
16d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk */
17d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
18d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsContext.h"
19d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
20d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsFont.h"
21d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsProgramFragment.h"
22c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk#include <cutils/properties.h>
2302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
2402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk#include <ft2build.h>
2502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk#include FT_FREETYPE_H
26d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include FT_BITMAP_H
27d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
28d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES/gl.h>
29d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES/glext.h>
30d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES2/gl2.h>
31d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES2/gl2ext.h>
32d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
33d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android;
34d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android::renderscript;
35d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
36afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
37d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
38d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = false;
393659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mFace = NULL;
40d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
41d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
425224a27798f89093b13722b41143551a057ce550Alex Sakhartchoukbool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
43afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
44d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
45d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
46d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
47d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
485224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    FT_Error error = 0;
495224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (data != NULL && dataLen > 0) {
505224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
515224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    } else {
525224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
535224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    }
545224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk
55afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
56c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk        LOGE("Unable to initialize font %s", name);
57d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
58d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
59d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
60d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontName = name;
61d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSize = fontSize;
62d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDpi = dpi;
63d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
64c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
65afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
66c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk        LOGE("Unable to set font size on %s", name);
67d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
68d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
69d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
70d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
71d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
72d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
73d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
74d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
75d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
762e8665de7c0eb4514c67baf8693d61c892e5303dJason Samsvoid Font::preDestroy() const {
772e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
782e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
792e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams            mRSC->mStateFont.mActiveFonts.removeAt(ct);
802e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams            break;
812e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams        }
822e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams    }
832e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams}
842e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams
85afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::invalidateTextureCache() {
86afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
87d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
88d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
89d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
90d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
91afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
92d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
93d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
9409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
9509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
96d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
9709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float u1 = glyph->mBitmapMinU;
9809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float u2 = glyph->mBitmapMaxU;
9909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float v1 = glyph->mBitmapMinV;
10009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float v2 = glyph->mBitmapMaxV;
101d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
10209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
10309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
104d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
10509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
10609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX + width, nPenY, 0, u2, v2,
10709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX + width, nPenY - height, 0, u2, v1,
10809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX, nPenY - height, 0, u1, v1);
10909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk}
11009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
11209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
11309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
11409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y + glyph->mBitmapTop;
11509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
11709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
11809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
12009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
12109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    const uint8_t* cacheBuffer = state->getTextTextureData();
12209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
12309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
12409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t bX = 0, bY = 0;
12509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
12609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
12709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
12809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                LOGE("Skipping invalid index");
12909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                continue;
13009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            }
13109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
13209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
13309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        }
13409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
135d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
136d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
13709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
13809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
13909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
14009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
14109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
14209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
14309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
1445224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    // 0, 0 is top left, so bottom is a positive number
1455224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (bounds->bottom < nPenY) {
14609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->bottom = nPenY;
14709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
14809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->left > nPenX) {
14909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->left = nPenX;
15009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
15109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->right < nPenX + width) {
15209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->right = nPenX + width;
15309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
1545224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (bounds->top > nPenY - height) {
1555224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        bounds->top = nPenY - height;
15609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
15709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk}
15809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
15909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
16009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                     uint32_t start, int32_t numGlyphs,
16109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                     RenderMode mode, Rect *bounds,
162afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
163afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
164d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
165d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
166d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
167afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mode == Font::MEASURE) {
16809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        if (bounds == NULL) {
16909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            LOGE("No return rectangle provided to measure text");
17009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            return;
17109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        }
17209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        // Reset min and max of the bounding box to something large
1735224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        bounds->set(1e6, -1e6, 1e6, -1e6);
17409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
17509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
17609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t penX = x, penY = y;
17709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t glyphsLeft = 1;
178afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (numGlyphs > 0) {
179d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        glyphsLeft = numGlyphs;
180d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
181d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
182d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t index = start;
183d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t nextIndex = 0;
184d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
185d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    while (glyphsLeft > 0) {
186d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
187c9c38dd8508a2f805213abee1f9f44f103ac0a0dKenny Root        int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
188d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
189d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Reached the end of the string or encountered
190afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (utfChar < 0) {
191d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
192d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
193d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
194d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Move to the next character in the array
195d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        index = nextIndex;
196d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
19701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
198d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
199d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
200afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (cachedGlyph->mIsValid) {
201afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            switch (mode) {
20209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case FRAMEBUFFER:
20309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
20409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
20509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case BITMAP:
20609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
20709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
20809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case MEASURE:
20909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
21009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
21109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            }
212d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
213d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
21402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        penX += (cachedGlyph->mAdvanceX >> 6);
215d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
216d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
217afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (numGlyphs > 0) {
218d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            glyphsLeft --;
219d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
220d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
221d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
222d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
22301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
22401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
22501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
226afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (cachedGlyph == NULL) {
22701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
22801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
22901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Is the glyph still in texture cache?
230afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!cachedGlyph->mIsValid) {
23101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        updateGlyphCache(cachedGlyph);
23201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
23301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
23401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return cachedGlyph;
23501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
23601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
237afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph) {
238a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
239afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
240a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        LOGE("Couldn't load glyph.");
241a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        return;
242a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
243d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
24402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    glyph->mAdvanceX = mFace->glyph->advance.x;
24502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    glyph->mAdvanceY = mFace->glyph->advance.y;
246a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
247a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
248d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
249a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
250d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
251d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
252d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
253d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
254d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
255d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
256d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
257a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
258d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
259afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!glyph->mIsValid) {
260d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
261d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
262d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
263a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endX = startX + bitmap->width;
264a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
265d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
266d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinX = startX;
267d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinY = startY;
268a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
269a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
270d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
271d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
272d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
273d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
274d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
275d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
276d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
277d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
278d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
279d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
280afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
281d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
282d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
283d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
284d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
285d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mIsValid = false;
286d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
287d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    updateGlyphCache(newGlyph);
288d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
289d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return newGlyph;
290d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
291d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
2925224a27798f89093b13722b41143551a057ce550Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
2935224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk                    const void *data, uint32_t dataLen) {
29435b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    rsc->mStateFont.checkInit();
295d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
296d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
297afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < activeFonts.size(); i ++) {
298d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        Font *ithFont = activeFonts[i];
299afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
300d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return ithFont;
301d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
302d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
303d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
304d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *newFont = new Font(rsc);
3055224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
306afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (isInitialized) {
307d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        activeFonts.push(newFont);
30801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
309d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return newFont;
310d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
311d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
312225afd317e101a7be5fe02c0a86361146ea89f05Jason Sams    ObjectBase::checkDelete(newFont);
313d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return NULL;
314d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
315d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
316afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::~Font() {
317afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mFace) {
318d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        FT_Done_Face(mFace);
319d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
320d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
321afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
322d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
323d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete glyph;
324d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
325d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
326d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
327afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::FontState() {
328d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
329d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
330d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex = 0;
331d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC = NULL;
3323659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mLibrary = NULL;
333c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
334c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the renderer properties
335c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
336c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
337c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the gamma
338c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    float gamma = DEFAULT_TEXT_GAMMA;
339c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
340c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        gamma = atof(property);
341c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
342c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
343c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the black gamma threshold
34409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
345c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
346c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        blackThreshold = atoi(property);
347c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
348c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackThreshold = (float)(blackThreshold) / 255.0f;
349c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
350c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the white gamma threshold
35109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
352c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
353c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        whiteThreshold = atoi(property);
354c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
355c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
356c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
357c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Compute the gamma tables
358c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackGamma = gamma;
359c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
3604f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
3614f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
362d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
363d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
364afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::~FontState() {
365afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
366d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete mCacheLines[i];
367d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
368d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
369d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
370d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
371d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
372afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFT_Library FontState::getLib() {
373afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!mLibrary) {
374a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
375afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (error) {
376d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            LOGE("Unable to initialize freetype");
377a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk            return NULL;
378d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
379d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
3803659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
381a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return mLibrary;
382a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk}
383d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
384afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::init(Context *rsc) {
385a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mRSC = rsc;
386d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
387d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
388afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::flushAllAndInvalidate() {
389afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
390d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
391d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
392d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
393afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
394d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
395d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
396afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
397d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
398d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
399d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
400d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
401afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
402d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the glyph is too tall, don't cache it
403afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
404d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
405d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
406d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
407d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
408d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
409d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
410d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
411d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
412d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool bitmapFit = false;
413afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
414d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
415afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (bitmapFit) {
416d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
417d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
418d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
419d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
420d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
421afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!bitmapFit) {
422d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        flushAllAndInvalidate();
423d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
424d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Try to fit it again
425afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
426d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
427afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            if (bitmapFit) {
428d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                break;
429d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            }
430d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
431d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
432d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
433afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!bitmapFit) {
434d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
435d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return false;
436d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
437d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
438d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
439d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginX = startX;
440d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginY = startY;
441d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
442d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
443d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
444d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
445d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
446d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
44709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
44809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
449d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
450d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
451afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
452afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
45309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
454d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
455d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
456d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
457d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
458d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // This will dirty the texture and the shader so next time
459d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // we draw it will upload the data
460b7e83bda41e66c966b98935b44140692bfe0c4caJason Sams    mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
461383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
462d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
463d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Some debug code
464afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
465d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
466d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
467d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
468d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
469d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }*/
470d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
471d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
472d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
473d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
474afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initRenderState() {
4757ffcaf20cbb115326f3d72a983835d6c314a4cefAlex Sakhartchouk    String8 shaderString("varying vec2 varTex0;\n");
476e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("void main() {\n");
477e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
478e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
479c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
480e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
481e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("}\n");
482e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
483e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
484c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
485e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
486e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
487c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
488e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
489e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
490f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams    Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
491e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
492e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    uint32_t tmp[4];
493e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
494e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[1] = (uint32_t)inputType;
49584e4027f83b20af59f5b1fc52be6e45f159d3970Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
49684e4027f83b20af59f5b1fc52be6e45f159d3970Alex Sakhartchouk    tmp[3] = RS_TEXTURE_2D;
497e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
498366c9c85196675437a8dd74c1cf6b63ddbde3d6aJason Sams    mFontShaderFConstant.set(new Allocation(mRSC, inputType,
499366c9c85196675437a8dd74c1cf6b63ddbde3d6aJason Sams                                            RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
500e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
501e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk                                              shaderString.length(), tmp, 4);
502d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontShaderF.set(pf);
503383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
504d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
505d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
506d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
507d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSampler.set(sampler);
508383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, sampler);
509d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
510721acc495b859c6d884725a4f9b5523583dd11c7Jason Sams    ProgramStore *fontStore = new ProgramStore(mRSC, true, true, true, true,
511721acc495b859c6d884725a4f9b5523583dd11c7Jason Sams                                               false, false,
51200237f18a9d31afdca5cca8d621397fbf5b16076Jason Sams                                               RS_BLEND_SRC_SRC_ALPHA,
51300237f18a9d31afdca5cca8d621397fbf5b16076Jason Sams                                               RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
514721acc495b859c6d884725a4f9b5523583dd11c7Jason Sams                                               RS_DEPTH_FUNC_ALWAYS);
515d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore.set(fontStore);
5168feea4e0dec48ea03bd6d32706d058b86dddc5baJason Sams    mFontProgramStore->init();
517d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
518d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
519afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initTextTexture() {
520d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
521d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
522d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
523f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams    Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
524d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
525366c9c85196675437a8dd74c1cf6b63ddbde3d6aJason Sams    Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
526d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
527b7e83bda41e66c966b98935b44140692bfe0c4caJason Sams    mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
528d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
529d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
53009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nextLine = 0;
531d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
532d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
533d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
534d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
53501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
53601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
537d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
538d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
539d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
540d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
541d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
542d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
543d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
544d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
545d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
546d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
547afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initVertexArrayBuffers() {
548d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now lets write index data
549d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
550d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
551f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams    Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
552d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
553366c9c85196675437a8dd74c1cf6b63ddbde3d6aJason Sams    Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
554d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
555d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
556d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
557afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
55809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i6 = i * 6;
55909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i4 = i * 4;
560d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
561d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
562d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
563d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
564d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
565d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
566d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
567d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
568d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
569d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
5707d9c5ffccb7a5e682860f752403e5a03aed587beAlex Sakhartchouk    indexAlloc->deferredUploadToBufferObject(mRSC);
571d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mIndexBuffer.set(indexAlloc);
572d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
573d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
574d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
575d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
57664cd98e83d33011950b88f229d013e06c62b36e9Alex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
57764cd98e83d33011950b88f229d013e06c62b36e9Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
57864cd98e83d33011950b88f229d013e06c62b36e9Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
57964cd98e83d33011950b88f229d013e06c62b36e9Alex Sakhartchouk    const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
580d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
581f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams    Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
582f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams                                         mMaxNumberOfQuads * 4,
583f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams                                         0, 0, false, false);
584d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
585366c9c85196675437a8dd74c1cf6b63ddbde3d6aJason Sams    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
586d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
587d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
588d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mVertexArray.set(vertexAlloc);
589d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
590d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
591d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
592afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::checkInit() {
593afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
594d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
595d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
596d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
597d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initTextTexture();
598d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initRenderState();
599d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
600d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initVertexArrayBuffers();
601d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
60235b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
60335b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
60435b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
60535b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
60635b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("0123456789");
60735b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk
608d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
609d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
610d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
611d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::issueDrawCommand() {
61260709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    Context::PushState ps(mRSC);
613d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
61460709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
61560709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
61660709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramFragment(mFontShaderF.get());
61760709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramStore(mFontProgramStore.get());
618d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
619afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mConstantsDirty) {
6204b45b8998e0d7038efaea80c70d23c086640b4e3Jason Sams        mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
621c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstantsDirty = false;
622ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    }
623ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
624d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if (!mRSC->setupCheck()) {
625d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
626d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
627d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
628d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *vtx = (float*)mVertexArray->getPtr();
629d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *tex = vtx + 3;
630d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
63154929cce0bf44090424b1f91b676529a2422378fAlex Sakhartchouk    VertexArray::Attrib attribs[2];
63254929cce0bf44090424b1f91b676529a2422378fAlex Sakhartchouk    attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
63354929cce0bf44090424b1f91b676529a2422378fAlex Sakhartchouk    attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
63454929cce0bf44090424b1f91b676529a2422378fAlex Sakhartchouk    VertexArray va(attribs, 2);
635d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
636d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
637d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mIndexBuffer->uploadCheck(mRSC);
638d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
639d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
640d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
641d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
642d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
643afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u1, float v1,
644afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x2, float y2, float z2,
645afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u2, float v2,
646afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x3, float y3, float z3,
647afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u3, float v3,
648afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x4, float y4, float z4,
649afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u4, float v4) {
650d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
651d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
652d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
653d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
654d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Cull things that are off the screen
655d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float width = (float)mRSC->getWidth();
656d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float height = (float)mRSC->getHeight();
657d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
658afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
659d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
660d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
661d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
662d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
663d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
664d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
665d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
666d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
667d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x1;
668d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y1;
669d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z1;
670d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u1;
671d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v1;
672d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
673d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x2;
674d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y2;
675d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z2;
676d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u2;
677d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v2;
678d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
679d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x3;
680d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y3;
681d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z3;
682d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u3;
683d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v3;
684d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
685d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x4;
686d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y4;
687d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z4;
688d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u4;
689d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v4;
690d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
691d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex ++;
692d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
693afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
694d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
695d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
696d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
697d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
698d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
69901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
70001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = 0;
70135b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    uint32_t totalPixels = 0;
702afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
70301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
70401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
70501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
70601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
70701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return remainingCapacity;
70801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
70901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
71001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
71101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Remaining capacity is measured in %
71201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
71301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t precacheIdx = 0;
714afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
71501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
71601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
71701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        precacheIdx ++;
71801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
71901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
72001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
72101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
72209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
72309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
72409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::RenderMode mode,
72509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::Rect *bounds,
726afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
727d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    checkInit();
728d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
729d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Render code here
730d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
731afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
732afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!mDefault.get()) {
733c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk            String8 fontsDir("/fonts/DroidSans.ttf");
734c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk            String8 fullPath(getenv("ANDROID_ROOT"));
735c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk            fullPath += fontsDir;
736c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk
7377b3e9bd825901e33661e3c385e3e7c6f40ca6000Alex Sakhartchouk            mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
738a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        }
739a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        currentFont = mDefault.get();
740a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
741afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
7423659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        LOGE("Unable to initialize any fonts");
7433659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        return;
7443659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
7453659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
74609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
74709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
748d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
749afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
750d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
751d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
752d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
753d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
754d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
75509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
75609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
7575224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bounds->bottom = - bounds->bottom;
7585224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bounds->top = - bounds->top;
759d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
760d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
7619fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
762c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[0] = r;
763c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[1] = g;
764c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[2] = b;
765c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[3] = a;
766c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
767c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mGamma = 1.0f;
768c8fb69e4a3e01501a3d38a6d3ea185e583d3f493Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
769c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (luminance <= mBlackThreshold) {
770c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mBlackGamma;
771c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
772c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
773c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
7744f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
775c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstantsDirty = true;
7769fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk}
7779fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk
778ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
779c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *r = mConstants.mFontColor[0];
780c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *g = mConstants.mFontColor[1];
781c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *b = mConstants.mFontColor[2];
782c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *a = mConstants.mFontColor[3];
783ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk}
784ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
785afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::deinit(Context *rsc) {
786a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mInitialized = false;
787a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
78801b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines    mFontShaderFConstant.clear();
78901b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines
790a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mIndexBuffer.clear();
791a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mVertexArray.clear();
792a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
793a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontShaderF.clear();
794a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontSampler.clear();
795a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontProgramStore.clear();
796a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
797a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mTextTexture.clear();
798afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
799a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        delete mCacheLines[i];
800d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
801a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mCacheLines.clear();
802d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
803d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDefault.clear();
804a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
805afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mLibrary) {
806a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Done_FreeType( mLibrary );
8073659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        mLibrary = NULL;
808a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
809d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
810d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
81102000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchoukbool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
81202000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    if ((uint32_t)bitmap->rows > mMaxHeight) {
81302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        return false;
81402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    }
81502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
81602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
81702000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        *retOriginX = mCurrentCol;
81802000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        *retOriginY = mCurrentRow;
81902000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        mCurrentCol += bitmap->width;
82002000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        mDirty = true;
82102000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk       return true;
82202000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    }
82302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
82402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    return false;
82502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk}
82602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
827d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace android {
828d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace renderscript {
829d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
83070b83c111beceaf8fbb700580833e7fec99272cfAlex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc,
83170b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                              char const *name, size_t name_length,
83270b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                              float fontSize, uint32_t dpi) {
833a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
834afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (newFont) {
835a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        newFont->incUserRef();
836a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
837a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return newFont;
838d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
839d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
84070b83c111beceaf8fbb700580833e7fec99272cfAlex SakhartchoukRsFont rsi_FontCreateFromMemory(Context *rsc,
84170b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                char const *name, size_t name_length,
84270b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                float fontSize, uint32_t dpi,
84370b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                const void *data, size_t data_length) {
84470b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
8455224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (newFont) {
8465224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        newFont->incUserRef();
8475224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    }
8485224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    return newFont;
8495224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk}
8505224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk
851d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // renderscript
852d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // android
853