rsFont.cpp revision e23d239828a229eb7d4d33c9630070f0a87833e1
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"
19e23d239828a229eb7d4d33c9630070f0a87833e1Alex Sakhartchouk#include "rs.h"
20d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsFont.h"
21d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsProgramFragment.h"
22c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk#include <cutils/properties.h>
2302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
24b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
2502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk#include <ft2build.h>
2602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk#include FT_FREETYPE_H
27d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include FT_BITMAP_H
28b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
29d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
30d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android;
31d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android::renderscript;
32d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
33afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
34d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
35d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = false;
363659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mFace = NULL;
37d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
38d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
395224a27798f89093b13722b41143551a057ce550Alex Sakhartchoukbool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
40b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
41afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
42af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Reinitialization of fonts not supported");
43d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
44d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
45d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
465224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    FT_Error error = 0;
475224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (data != NULL && dataLen > 0) {
485224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
495224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    } else {
505224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
515224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    }
525224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk
53afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
54af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to initialize font %s", name);
55d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
56d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
57d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
58d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontName = name;
59d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSize = fontSize;
60d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDpi = dpi;
61d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
62c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
63afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
64af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to set font size on %s", name);
65d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
66d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
67d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
68d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
69d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
70d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
71b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
72d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
73d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
74d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
752e8665de7c0eb4514c67baf8693d61c892e5303dJason Samsvoid Font::preDestroy() const {
762e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
772e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
782e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams            mRSC->mStateFont.mActiveFonts.removeAt(ct);
792e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams            break;
802e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams        }
812e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams    }
822e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams}
832e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams
84afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::invalidateTextureCache() {
85afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
86d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
87d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
88d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
89d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
90afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
91d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
92d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
9309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
9409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
95d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
9609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float u1 = glyph->mBitmapMinU;
9709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float u2 = glyph->mBitmapMaxU;
9809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float v1 = glyph->mBitmapMinV;
9909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float v2 = glyph->mBitmapMaxV;
100d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
10109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
10209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
103d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
10409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
10509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX + width, nPenY, 0, u2, v2,
10609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX + width, nPenY - height, 0, u2, v1,
10709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX, nPenY - height, 0, u1, v1);
10809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk}
10909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
11109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
11209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
11309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y + glyph->mBitmapTop;
11409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
11609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
11709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
11909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
12009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    const uint8_t* cacheBuffer = state->getTextTextureData();
12109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
12209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
12309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t bX = 0, bY = 0;
12409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
12509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
12609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
127af12ac6a08651464f8d823add667c706f993b587Steve Block                ALOGE("Skipping invalid index");
12809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                continue;
12909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            }
13009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
13109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
13209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        }
13309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
134d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
135d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
13609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
13709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
13809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
13909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
14009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
14109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
14209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
1435224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    // 0, 0 is top left, so bottom is a positive number
1445224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (bounds->bottom < nPenY) {
14509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->bottom = nPenY;
14609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
14709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->left > nPenX) {
14809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->left = nPenX;
14909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
15009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->right < nPenX + width) {
15109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->right = nPenX + width;
15209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
1535224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (bounds->top > nPenY - height) {
1545224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        bounds->top = nPenY - height;
15509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
15609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk}
15709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
15809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
15909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                     uint32_t start, int32_t numGlyphs,
16009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                     RenderMode mode, Rect *bounds,
161afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
162afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
163d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
164d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
165d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
166afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mode == Font::MEASURE) {
16709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        if (bounds == NULL) {
168af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("No return rectangle provided to measure text");
16909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            return;
17009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        }
17109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        // Reset min and max of the bounding box to something large
1725224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        bounds->set(1e6, -1e6, 1e6, -1e6);
17309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
17409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
17509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t penX = x, penY = y;
17609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t glyphsLeft = 1;
177afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (numGlyphs > 0) {
178d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        glyphsLeft = numGlyphs;
179d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
180d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
181d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t index = start;
182d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t nextIndex = 0;
183d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
184d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    while (glyphsLeft > 0) {
185d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
186c9c38dd8508a2f805213abee1f9f44f103ac0a0dKenny Root        int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
187d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
188d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Reached the end of the string or encountered
189afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (utfChar < 0) {
190d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
191d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
192d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
193d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Move to the next character in the array
194d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        index = nextIndex;
195d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
19601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
197d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
198d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
199afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (cachedGlyph->mIsValid) {
200afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            switch (mode) {
20109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case FRAMEBUFFER:
20209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
20309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
20409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case BITMAP:
20509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
20609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
20709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case MEASURE:
20809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
20909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
21009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            }
211d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
212d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
21302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        penX += (cachedGlyph->mAdvanceX >> 6);
214d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
215d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
216afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (numGlyphs > 0) {
217d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            glyphsLeft --;
218d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
219d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
220d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
221d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
22201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
22301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
22401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
225afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (cachedGlyph == NULL) {
22601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
22701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
22801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Is the glyph still in texture cache?
229afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!cachedGlyph->mIsValid) {
23001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        updateGlyphCache(cachedGlyph);
23101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
23201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
23301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return cachedGlyph;
23401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
23501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
236afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph) {
237b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
238a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
239afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
240af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("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;
278b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
279d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
280d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
281afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
282d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
283d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
284b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
285d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
286d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mIsValid = false;
287b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
288d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    updateGlyphCache(newGlyph);
289d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
290d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return newGlyph;
291d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
292d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
2935224a27798f89093b13722b41143551a057ce550Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
2945224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk                    const void *data, uint32_t dataLen) {
29535b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    rsc->mStateFont.checkInit();
296d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
297d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
298afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < activeFonts.size(); i ++) {
299d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        Font *ithFont = activeFonts[i];
300afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
301d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return ithFont;
302d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
303d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
304d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
305d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *newFont = new Font(rsc);
3065224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
307afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (isInitialized) {
308d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        activeFonts.push(newFont);
30901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
310d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return newFont;
311d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
312d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
313225afd317e101a7be5fe02c0a86361146ea89f05Jason Sams    ObjectBase::checkDelete(newFont);
314d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return NULL;
315d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
316d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
317afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::~Font() {
318b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
319afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mFace) {
320d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        FT_Done_Face(mFace);
321d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
322b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif
323d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
324afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
325d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
326d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete glyph;
327d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
328d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
329d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
330afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::FontState() {
331d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
332d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
333d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex = 0;
334d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC = NULL;
335b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
3363659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mLibrary = NULL;
337b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
338c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
339c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the renderer properties
340c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
341c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
342c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the gamma
343c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    float gamma = DEFAULT_TEXT_GAMMA;
344c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
345c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        gamma = atof(property);
346c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
347c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
348c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the black gamma threshold
34909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
350c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
351c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        blackThreshold = atoi(property);
352c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
353c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackThreshold = (float)(blackThreshold) / 255.0f;
354c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
355c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the white gamma threshold
35609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
357c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
358c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        whiteThreshold = atoi(property);
359c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
360c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
361c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
362c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Compute the gamma tables
363c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackGamma = gamma;
364c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
3654f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
3664f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
367d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
368d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
369afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::~FontState() {
370afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
371d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete mCacheLines[i];
372d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
373d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
374d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
375d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
376b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
377afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFT_Library FontState::getLib() {
378afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!mLibrary) {
379a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
380afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (error) {
381af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("Unable to initialize freetype");
382a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk            return NULL;
383d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
384d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
3853659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
386a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return mLibrary;
387a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk}
388b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
389b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk
390d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
391afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::init(Context *rsc) {
392a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mRSC = rsc;
393d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
394d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
395afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::flushAllAndInvalidate() {
396afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
397d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
398d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
399d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
400afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
401d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
402d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
403afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
404d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
405d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
406d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
407d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
408b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
409afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
410d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the glyph is too tall, don't cache it
411afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
412af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
413d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
414d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
415d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
416d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
417d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
418d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
419d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
420d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool bitmapFit = false;
421afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
422d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
423afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (bitmapFit) {
424d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
425d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
426d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
427d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
428d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
429afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!bitmapFit) {
430d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        flushAllAndInvalidate();
431d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
432d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Try to fit it again
433afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
434d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
435afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            if (bitmapFit) {
436d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                break;
437d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            }
438d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
439d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
440d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
441afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!bitmapFit) {
442af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
443d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return false;
444d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
445d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
446d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
447d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginX = startX;
448d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginY = startY;
449d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
450d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
451d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
452d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
453d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
454d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
45509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
45609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
457d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
458d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
459afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
460afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
46109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
462d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
463d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
464d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
465d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
466d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // This will dirty the texture and the shader so next time
467d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // we draw it will upload the data
468eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
469eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    mTextTexture->sendDirty(mRSC);
470383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
471d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
472d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Some debug code
473afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
474af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Cache Line: H: %u Empty Space: %f",
475d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
476d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
477d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
478d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }*/
479d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
480d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
481d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
482b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
483d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
484afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initRenderState() {
4857ffcaf20cbb115326f3d72a983835d6c314a4cefAlex Sakhartchouk    String8 shaderString("varying vec2 varTex0;\n");
486e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("void main() {\n");
487e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
488e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
489c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
490e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
491e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("}\n");
492e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
493748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    const char *textureNames[] = { "Tex0" };
494748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    const size_t textureNamesLengths[] = { 4 };
495748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
496748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk
497748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
498748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_USER, false, 4);
499748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
500748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_USER, false, 1);
501c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Element::Builder builder;
502c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    builder.add(colorElem.get(), "Color", 1);
503c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    builder.add(gammaElem.get(), "Gamma", 1);
504c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> constInput = builder.create(mRSC);
505e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
506c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false);
507e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
508e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    uint32_t tmp[4];
509e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
510c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    tmp[1] = (uint32_t)inputType.get();
51184e4027f83b20af59f5b1fc52be6e45f159d3970Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
51284e4027f83b20af59f5b1fc52be6e45f159d3970Alex Sakhartchouk    tmp[3] = RS_TEXTURE_2D;
513e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
514c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
515748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                          RS_ALLOCATION_USAGE_SCRIPT |
516748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                          RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
517748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), shaderString.length(),
518748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                              textureNames, numTextures, textureNamesLengths,
519748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                              tmp, 4);
520d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontShaderF.set(pf);
521383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
522d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
523c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
524748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                         RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
525748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                         RS_SAMPLER_CLAMP).get());
526c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
527c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk
528c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
529c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        false, false,
530c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_BLEND_SRC_SRC_ALPHA,
531c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
532c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_DEPTH_FUNC_ALWAYS).get());
5338feea4e0dec48ea03bd6d32706d058b86dddc5baJason Sams    mFontProgramStore->init();
534d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
535d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
536afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initTextTexture() {
537748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
538748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_PIXEL_A, true, 1);
539d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
540d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
541748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
542748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                   1024, 256, 0, false, false);
543d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
544c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
545eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
546d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
547b7e83bda41e66c966b98935b44140692bfe0c4caJason Sams    mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
548d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
549d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
55009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nextLine = 0;
551d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
552d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
553d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
554d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
55501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
55601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
557d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
558d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
559d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
560d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
561d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
562d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
563d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
564d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
565d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
566d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
567afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initVertexArrayBuffers() {
568d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now lets write index data
569c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
570d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
571c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false);
572d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
573c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
574eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                          RS_ALLOCATION_USAGE_SCRIPT |
575eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                          RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
576d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
577d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
578d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
579afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
58009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i6 = i * 6;
58109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i4 = i * 4;
582d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
583d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
584d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
585d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
586d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
587d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
588d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
589d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
590d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
591d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
592eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    indexAlloc->sendDirty(mRSC);
593d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
594c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
595c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
596d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
597c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Element::Builder builder;
598c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    builder.add(posElem.get(), "position", 1);
599c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    builder.add(texElem.get(), "texture0", 1);
600c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> vertexDataElem = builder.create(mRSC);
601d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
602c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
603c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                          mMaxNumberOfQuads * 4,
604c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                          0, 0, false, false);
605d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
606c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
607eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                           RS_ALLOCATION_USAGE_SCRIPT);
608d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
609d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
610a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh.set(new Mesh(mRSC, 1, 1));
611a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->setVertexBuffer(vertexAlloc, 0);
612a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
613a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->init();
614d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
615d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
616d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
617afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::checkInit() {
618afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
619d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
620d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
621d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
622d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initTextTexture();
623d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initRenderState();
624d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
625d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initVertexArrayBuffers();
626d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
62735b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
62835b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
62935b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
63035b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
63135b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("0123456789");
63235b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk
633d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
634d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
635d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
636d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::issueDrawCommand() {
63760709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    Context::PushState ps(mRSC);
638d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
63960709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
64060709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
64160709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramFragment(mFontShaderF.get());
64260709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramStore(mFontProgramStore.get());
643d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
644afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mConstantsDirty) {
6454b45b8998e0d7038efaea80c70d23c086640b4e3Jason Sams        mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
646c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstantsDirty = false;
647ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    }
648ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
649d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if (!mRSC->setupCheck()) {
650d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
651d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
652d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
653a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
654d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
655d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
656d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
657afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u1, float v1,
658afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x2, float y2, float z2,
659afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u2, float v2,
660afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x3, float y3, float z3,
661afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u3, float v3,
662afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x4, float y4, float z4,
663afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u4, float v4) {
664d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
6652d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    const uint32_t floatsPerVert = 6;
666d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
667d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
668a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
669d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
670d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
671d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
672d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
673af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
674af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
675af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
676d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
677d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x1;
678d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y1;
679d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z1;
6802d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
681d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u1;
682d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v1;
683d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
684d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x2;
685d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y2;
686d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z2;
6872d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
688d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u2;
689d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v2;
690d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
691d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x3;
692d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y3;
693d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z3;
6942d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
695d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u3;
696d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v3;
697d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
698d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x4;
699d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y4;
700d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z4;
7012d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
702d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u4;
703d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v4;
704d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
705d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex ++;
706d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
707afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
708d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
709d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
710d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
711d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
712d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
71301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
71401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = 0;
71535b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    uint32_t totalPixels = 0;
716afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
71701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
71801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
71901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
72001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
72101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return remainingCapacity;
72201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
72301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
72401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
72501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Remaining capacity is measured in %
72601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
72701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t precacheIdx = 0;
728afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
72901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
73001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
73101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        precacheIdx ++;
73201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
73301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
73401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
73501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
73609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
73709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
73809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::RenderMode mode,
73909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::Rect *bounds,
740afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
741d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    checkInit();
742d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
743d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Render code here
744d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
745afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
746afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!mDefault.get()) {
7471f5f9a30d71973f0c54e0142ed80740b71c720e3Christian Robertson            String8 fontsDir("/fonts/Roboto-Regular.ttf");
748c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk            String8 fullPath(getenv("ANDROID_ROOT"));
749c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk            fullPath += fontsDir;
750c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk
7517b3e9bd825901e33661e3c385e3e7c6f40ca6000Alex Sakhartchouk            mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
752a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        }
753a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        currentFont = mDefault.get();
754a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
755afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
756af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to initialize any fonts");
7573659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        return;
7583659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
7593659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
760a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    // Cull things that are off the screen
761a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
762a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
763a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk
76409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
76509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
766d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
767afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
768d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
769d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
770d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
771d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
772d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
77309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
77409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
7755224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bounds->bottom = - bounds->bottom;
7765224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bounds->top = - bounds->top;
777d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
778d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
7799fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
780c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[0] = r;
781c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[1] = g;
782c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[2] = b;
783c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[3] = a;
784c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
785c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mGamma = 1.0f;
786c8fb69e4a3e01501a3d38a6d3ea185e583d3f493Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
787c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (luminance <= mBlackThreshold) {
788c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mBlackGamma;
789c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
790c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
791c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
7924f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
793c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstantsDirty = true;
7949fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk}
7959fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk
796ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
797c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *r = mConstants.mFontColor[0];
798c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *g = mConstants.mFontColor[1];
799c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *b = mConstants.mFontColor[2];
800c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *a = mConstants.mFontColor[3];
801ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk}
802ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
803afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::deinit(Context *rsc) {
804a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mInitialized = false;
805a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
80601b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines    mFontShaderFConstant.clear();
80701b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines
808a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh.clear();
809a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
810a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontShaderF.clear();
811a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontSampler.clear();
812a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontProgramStore.clear();
813a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
814a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mTextTexture.clear();
815afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
816a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        delete mCacheLines[i];
817d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
818a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mCacheLines.clear();
819d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
820d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDefault.clear();
821b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
822afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mLibrary) {
823a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Done_FreeType( mLibrary );
8243659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        mLibrary = NULL;
825a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
826b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
827d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
828d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
829b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
83002000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchoukbool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
83102000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    if ((uint32_t)bitmap->rows > mMaxHeight) {
83202000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        return false;
83302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    }
83402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
83502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
83602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        *retOriginX = mCurrentCol;
83702000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        *retOriginY = mCurrentRow;
83802000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        mCurrentCol += bitmap->width;
83902000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        mDirty = true;
84002000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk       return true;
84102000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    }
84202000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
84302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    return false;
84402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk}
845b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
84602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
847d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace android {
848d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace renderscript {
849d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
85070b83c111beceaf8fbb700580833e7fec99272cfAlex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc,
85170b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                              char const *name, size_t name_length,
85270b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                              float fontSize, uint32_t dpi) {
853a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
854afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (newFont) {
855a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        newFont->incUserRef();
856a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
857a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return newFont;
858d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
859d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
86070b83c111beceaf8fbb700580833e7fec99272cfAlex SakhartchoukRsFont rsi_FontCreateFromMemory(Context *rsc,
86170b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                char const *name, size_t name_length,
86270b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                float fontSize, uint32_t dpi,
86370b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                const void *data, size_t data_length) {
86470b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
8655224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (newFont) {
8665224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        newFont->incUserRef();
8675224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    }
8685224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    return newFont;
8695224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk}
8705224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk
871d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // renderscript
872d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // android
873