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"
224edf030cbb7c6ac08dc563335c2af73c20f6e2e5Alex Sakhartchouk#include "rsMesh.h"
23c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk#include <cutils/properties.h>
2402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
25b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
2602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk#include <ft2build.h>
2702000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk#include FT_FREETYPE_H
28d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include FT_BITMAP_H
29b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
30d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
31d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android;
32d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android::renderscript;
33d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
34afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
35d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
36d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = false;
373659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mFace = NULL;
38d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
39d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
405224a27798f89093b13722b41143551a057ce550Alex Sakhartchoukbool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
41b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
42afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
43af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Reinitialization of fonts not supported");
44d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
45d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
46d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
475224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    FT_Error error = 0;
485224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (data != NULL && dataLen > 0) {
495224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
505224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    } else {
515224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
525224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    }
535224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk
54afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
55af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to initialize font %s", name);
56d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
57d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
58d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
59d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontName = name;
60d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSize = fontSize;
61d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDpi = dpi;
62d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
63c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
64afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
65af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to set font size on %s", name);
66d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
67d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
68d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
69d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
70d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
71d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
72b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
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();
12161a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams    const uint8_t* cacheBuffer = state->mCacheBuffer;
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) {
128af12ac6a08651464f8d823add667c706f993b587Steve Block                ALOGE("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) {
169af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("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) {
238b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
239a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
240afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
241af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Couldn't load glyph.");
242a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        return;
243a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
244d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
24502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    glyph->mAdvanceX = mFace->glyph->advance.x;
24602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    glyph->mAdvanceY = mFace->glyph->advance.y;
247a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
248a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
249d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
250a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
251d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
252d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
253d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
254d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
255d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
256d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
257d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
258a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
259d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
260afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!glyph->mIsValid) {
261d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
262d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
263d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
264a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endX = startX + bitmap->width;
265a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
266d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
267d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinX = startX;
268d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinY = startY;
269a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
270a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
271d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
272d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
273d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
274d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
275d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
276d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
277d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
278d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
279b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
280d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
281d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
282afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
283d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
284d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
285b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
286d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
287d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mIsValid = false;
288b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
289d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    updateGlyphCache(newGlyph);
290d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
291d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return newGlyph;
292d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
293d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
2945224a27798f89093b13722b41143551a057ce550Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
2955224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk                    const void *data, uint32_t dataLen) {
29635b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    rsc->mStateFont.checkInit();
297d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
298d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
299afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < activeFonts.size(); i ++) {
300d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        Font *ithFont = activeFonts[i];
301afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
302d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return ithFont;
303d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
304d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
305d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
306d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *newFont = new Font(rsc);
3075224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
308afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (isInitialized) {
309d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        activeFonts.push(newFont);
31001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
311d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return newFont;
312d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
313d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
314225afd317e101a7be5fe02c0a86361146ea89f05Jason Sams    ObjectBase::checkDelete(newFont);
315d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return NULL;
316d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
317d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
318afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::~Font() {
319b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
320afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mFace) {
321d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        FT_Done_Face(mFace);
322d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
323b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif
324d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
325afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
326d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
327d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete glyph;
328d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
329d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
330d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
331afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::FontState() {
332d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
333d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
334d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex = 0;
335d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC = NULL;
336b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
3373659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mLibrary = NULL;
338b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
339c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
340c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the renderer properties
341c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
342c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
343c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the gamma
344c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    float gamma = DEFAULT_TEXT_GAMMA;
345c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
346c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        gamma = atof(property);
347c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
348c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
349c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the black gamma threshold
35009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
351c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
352c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        blackThreshold = atoi(property);
353c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
354c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackThreshold = (float)(blackThreshold) / 255.0f;
355c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
356c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the white gamma threshold
35709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
358c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
359c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        whiteThreshold = atoi(property);
360c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
361c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
362c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
363c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Compute the gamma tables
364c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackGamma = gamma;
365c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
3664f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
3674f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
368d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
369d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
370afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::~FontState() {
371afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
372d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete mCacheLines[i];
373d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
374d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
375d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
376d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
377b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
378afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFT_Library FontState::getLib() {
379afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!mLibrary) {
380a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
381afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (error) {
382af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("Unable to initialize freetype");
383a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk            return NULL;
384d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
385d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
3863659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
387a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return mLibrary;
388a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk}
389b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
390b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk
391d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
392afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::init(Context *rsc) {
393a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mRSC = rsc;
394d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
395d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
396afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::flushAllAndInvalidate() {
397afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
398d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
399d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
400d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
401afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
402d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
403d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
404afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
405d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
406d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
407d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
408d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
409b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
410afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
411d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the glyph is too tall, don't cache it
412afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
413af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
414d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
415d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
416d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
417d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
418d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
419d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
420d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
421d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool bitmapFit = false;
422afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
423d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
424afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (bitmapFit) {
425d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
426d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
427d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
428d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
429d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
430afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!bitmapFit) {
431d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        flushAllAndInvalidate();
432d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
433d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Try to fit it again
434afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
435d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
436afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            if (bitmapFit) {
437d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                break;
438d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            }
439d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
440d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
441d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
442afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!bitmapFit) {
443af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
444d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return false;
445d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
446d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
447d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
448d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginX = startX;
449d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginY = startY;
450d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
451d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
452d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
453d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
454d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
455d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
45661a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams    uint8_t *cacheBuffer = mCacheBuffer;
45709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
458d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
459d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
460afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
461afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
46209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
463d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
464d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
465d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
466d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
467d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // This will dirty the texture and the shader so next time
468d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // we draw it will upload the data
469eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
47061a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams    mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
47161a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams        RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
47261a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams        mCacheBuffer, mCacheWidth*mCacheHeight);
47361a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams
474383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
475d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
476d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Some debug code
477afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
478af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Cache Line: H: %u Empty Space: %f",
479d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
480d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
481d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
482d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }*/
483d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
484d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
485d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
486b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
487d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
488afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initRenderState() {
4897ffcaf20cbb115326f3d72a983835d6c314a4cefAlex Sakhartchouk    String8 shaderString("varying vec2 varTex0;\n");
490e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("void main() {\n");
491e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
492e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
493c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
494e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
495e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("}\n");
496e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
497748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    const char *textureNames[] = { "Tex0" };
498748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    const size_t textureNamesLengths[] = { 4 };
499748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
500748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk
501748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
502748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_USER, false, 4);
503748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
504748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_USER, false, 1);
505c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Element::Builder builder;
506c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    builder.add(colorElem.get(), "Color", 1);
507c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    builder.add(gammaElem.get(), "Gamma", 1);
508c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> constInput = builder.create(mRSC);
509e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
510c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false);
511e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
512e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    uint32_t tmp[4];
513e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
514c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    tmp[1] = (uint32_t)inputType.get();
51584e4027f83b20af59f5b1fc52be6e45f159d3970Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
51684e4027f83b20af59f5b1fc52be6e45f159d3970Alex Sakhartchouk    tmp[3] = RS_TEXTURE_2D;
517e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
518c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
519748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                          RS_ALLOCATION_USAGE_SCRIPT |
520748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                          RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
521748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), shaderString.length(),
522748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                              textureNames, numTextures, textureNamesLengths,
523748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                              tmp, 4);
524d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontShaderF.set(pf);
525383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
526d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
527c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
528748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                         RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
529748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                         RS_SAMPLER_CLAMP).get());
530c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
531c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk
532c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
533c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        false, false,
534c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_BLEND_SRC_SRC_ALPHA,
535c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
536c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_DEPTH_FUNC_ALWAYS).get());
5378feea4e0dec48ea03bd6d32706d058b86dddc5baJason Sams    mFontProgramStore->init();
538d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
539d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
540afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initTextTexture() {
541748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
542748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_PIXEL_A, true, 1);
543d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
544d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
54561a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams    mCacheHeight = 256;
54661a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams    mCacheWidth = 1024;
547748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
54861a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams                                                   mCacheWidth, mCacheHeight, 0, false, false);
54961a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams    mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
55061a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams
551d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
552c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
55361a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams                                RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
554d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
555d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
556d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
55709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nextLine = 0;
558d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
559d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
560d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
561d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
56201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
56301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
564d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
565d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
566d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
567d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
568d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
569d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
570d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
571d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
572d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
573d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
574afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initVertexArrayBuffers() {
575d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now lets write index data
576c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
577d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
578c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false);
579d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
580c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
581eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                          RS_ALLOCATION_USAGE_SCRIPT |
582eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                          RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
58361a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams    uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
584d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
585d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
586afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
58709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i6 = i * 6;
58809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i4 = i * 4;
589d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
590d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
591d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
592d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
593d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
594d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
595d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
596d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
597d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
598d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
599eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    indexAlloc->sendDirty(mRSC);
600d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
601c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
602c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
603d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
604c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Element::Builder builder;
605c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    builder.add(posElem.get(), "position", 1);
606c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    builder.add(texElem.get(), "texture0", 1);
607c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> vertexDataElem = builder.create(mRSC);
608d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
609c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
610c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                          mMaxNumberOfQuads * 4,
611c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                          0, 0, false, false);
612d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
613c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
614eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                           RS_ALLOCATION_USAGE_SCRIPT);
61561a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams    mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
616d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
617a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh.set(new Mesh(mRSC, 1, 1));
618a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->setVertexBuffer(vertexAlloc, 0);
619a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
620a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->init();
62161a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams    mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
62261a4bb734b91ced09fbfee4214c6f253cb66e5f0Jason Sams    mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
623d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
624d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
625d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
626afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::checkInit() {
627afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
628d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
629d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
630d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
631d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initTextTexture();
632d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initRenderState();
633d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
634d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initVertexArrayBuffers();
635d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
63635b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
63735b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
63835b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
63935b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
64035b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("0123456789");
64135b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk
642d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
643d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
644d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
645d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::issueDrawCommand() {
64660709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    Context::PushState ps(mRSC);
647d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
64860709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
64960709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
65060709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramFragment(mFontShaderF.get());
65160709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramStore(mFontProgramStore.get());
652d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
653afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mConstantsDirty) {
6544b45b8998e0d7038efaea80c70d23c086640b4e3Jason Sams        mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
655c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstantsDirty = false;
656ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    }
657ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
658d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if (!mRSC->setupCheck()) {
659d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
660d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
661d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
662a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
663d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
664d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
665d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
666afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u1, float v1,
667afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x2, float y2, float z2,
668afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u2, float v2,
669afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x3, float y3, float z3,
670afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u3, float v3,
671afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x4, float y4, float z4,
672afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u4, float v4) {
673d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
6742d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    const uint32_t floatsPerVert = 6;
675d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
676d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
677a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
678d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
679d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
680d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
681d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
682af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
683af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
684af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
685d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
686d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x1;
687d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y1;
688d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z1;
6892d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
690d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u1;
691d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v1;
692d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
693d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x2;
694d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y2;
695d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z2;
6962d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
697d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u2;
698d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v2;
699d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
700d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x3;
701d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y3;
702d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z3;
7032d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
704d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u3;
705d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v3;
706d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
707d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x4;
708d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y4;
709d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z4;
7102d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
711d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u4;
712d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v4;
713d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
714d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex ++;
715d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
716afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
717d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
718d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
719d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
720d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
721d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
72201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
72301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = 0;
72435b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    uint32_t totalPixels = 0;
725afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
72601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
72701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
72801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
72901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
73001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return remainingCapacity;
73101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
73201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
73301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
73401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Remaining capacity is measured in %
73501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
73601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t precacheIdx = 0;
737afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
73801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
73901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
74001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        precacheIdx ++;
74101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
74201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
74301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
74401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
74509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
74609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
74709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::RenderMode mode,
74809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::Rect *bounds,
749afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
750d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    checkInit();
751d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
752d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Render code here
753d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
754afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
755afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!mDefault.get()) {
7561f5f9a30d71973f0c54e0142ed80740b71c720e3Christian Robertson            String8 fontsDir("/fonts/Roboto-Regular.ttf");
757c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk            String8 fullPath(getenv("ANDROID_ROOT"));
758c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk            fullPath += fontsDir;
759c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk
7607b3e9bd825901e33661e3c385e3e7c6f40ca6000Alex Sakhartchouk            mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
761a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        }
762a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        currentFont = mDefault.get();
763a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
764afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
765af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to initialize any fonts");
7663659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        return;
7673659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
7683659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
769a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    // Cull things that are off the screen
770a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
771a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
772a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk
77309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
77409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
775d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
776afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
777d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
778d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
779d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
780d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
781d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
78209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
78309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
7845224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bounds->bottom = - bounds->bottom;
7855224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bounds->top = - bounds->top;
786d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
787d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
7889fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
789c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[0] = r;
790c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[1] = g;
791c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[2] = b;
792c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[3] = a;
793c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
794c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mGamma = 1.0f;
795c8fb69e4a3e01501a3d38a6d3ea185e583d3f493Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
796c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (luminance <= mBlackThreshold) {
797c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mBlackGamma;
798c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
799c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
800c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
8014f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
802c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstantsDirty = true;
8039fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk}
8049fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk
805ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
806c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *r = mConstants.mFontColor[0];
807c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *g = mConstants.mFontColor[1];
808c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *b = mConstants.mFontColor[2];
809c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *a = mConstants.mFontColor[3];
810ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk}
811ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
812afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::deinit(Context *rsc) {
813a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mInitialized = false;
814a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
81501b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines    mFontShaderFConstant.clear();
81601b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines
817a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh.clear();
818a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
819a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontShaderF.clear();
820a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontSampler.clear();
821a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontProgramStore.clear();
822a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
823a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mTextTexture.clear();
824afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
825a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        delete mCacheLines[i];
826d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
827a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mCacheLines.clear();
828d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
829d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDefault.clear();
830b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
831afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mLibrary) {
832a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Done_FreeType( mLibrary );
8333659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        mLibrary = NULL;
834a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
835b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
836d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
837d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
838b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
83902000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchoukbool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
84002000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    if ((uint32_t)bitmap->rows > mMaxHeight) {
84102000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        return false;
84202000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    }
84302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
84402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
84502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        *retOriginX = mCurrentCol;
84602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        *retOriginY = mCurrentRow;
84702000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        mCurrentCol += bitmap->width;
84802000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        mDirty = true;
84902000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk       return true;
85002000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    }
85102000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
85202000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    return false;
85302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk}
854b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
85502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
856d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace android {
857d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace renderscript {
858d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
85970b83c111beceaf8fbb700580833e7fec99272cfAlex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc,
86070b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                              char const *name, size_t name_length,
86170b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                              float fontSize, uint32_t dpi) {
862a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
863afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (newFont) {
864a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        newFont->incUserRef();
865a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
866a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return newFont;
867d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
868d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
86970b83c111beceaf8fbb700580833e7fec99272cfAlex SakhartchoukRsFont rsi_FontCreateFromMemory(Context *rsc,
87070b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                char const *name, size_t name_length,
87170b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                float fontSize, uint32_t dpi,
87270b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                const void *data, size_t data_length) {
87370b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
8745224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (newFont) {
8755224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        newFont->incUserRef();
8765224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    }
8775224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    return newFont;
8785224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk}
8795224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk
880d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // renderscript
881d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // android
882