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"
237e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich#ifdef HAVE_ANDROID_OS
24c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk#include <cutils/properties.h>
257e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich#endif
2602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
27b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
2802000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk#include <ft2build.h>
2902000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk#include FT_FREETYPE_H
30d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include FT_BITMAP_H
31b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
32d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
33d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android;
34d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android::renderscript;
35d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
36afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
37d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
38d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = false;
393659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mFace = NULL;
40d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
41d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
425224a27798f89093b13722b41143551a057ce550Alex Sakhartchoukbool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
43b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
44afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
45af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Reinitialization of fonts not supported");
46d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
47d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
48d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
495224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    FT_Error error = 0;
505224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (data != NULL && dataLen > 0) {
515224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
525224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    } else {
535224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
545224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    }
555224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk
56afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
57af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to initialize font %s", name);
58d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
59d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
60d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
6148ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams    mFontName = rsuCopyString(name);
62d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSize = fontSize;
63d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDpi = dpi;
64d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
65c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
66afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
67af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to set font size on %s", name);
68d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
69d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
70d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
71d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
72d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
73d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
74b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
75d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
76d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
77d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
782e8665de7c0eb4514c67baf8693d61c892e5303dJason Samsvoid Font::preDestroy() const {
792e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
802e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
812e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams            mRSC->mStateFont.mActiveFonts.removeAt(ct);
822e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams            break;
832e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams        }
842e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams    }
852e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams}
862e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams
87afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::invalidateTextureCache() {
88afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
89d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
90d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
91d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
92d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
93afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
94d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
95d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
9609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
9709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
98d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
9909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float u1 = glyph->mBitmapMinU;
10009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float u2 = glyph->mBitmapMaxU;
10109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float v1 = glyph->mBitmapMinV;
10209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float v2 = glyph->mBitmapMaxV;
103d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
10409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
10509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
106d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
10709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
10809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX + width, nPenY, 0, u2, v2,
10909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX + width, nPenY - height, 0, u2, v1,
11009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX, nPenY - height, 0, u1, v1);
11109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk}
11209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
11409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
11509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
11609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y + glyph->mBitmapTop;
11709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
11909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
12009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
12109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
12209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
123a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    const uint8_t* cacheBuffer = state->mCacheBuffer;
12409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
12509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
12609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t bX = 0, bY = 0;
12709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
12809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
12909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
130af12ac6a08651464f8d823add667c706f993b587Steve Block                ALOGE("Skipping invalid index");
13109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                continue;
13209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            }
13309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
13409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
13509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        }
13609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
137d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
138d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
13909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
14009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
14109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
14209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
14309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
14409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
14509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
1465224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    // 0, 0 is top left, so bottom is a positive number
1475224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (bounds->bottom < nPenY) {
14809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->bottom = nPenY;
14909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
15009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->left > nPenX) {
15109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->left = nPenX;
15209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
15309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->right < nPenX + width) {
15409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->right = nPenX + width;
15509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
1565224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (bounds->top > nPenY - height) {
1575224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        bounds->top = nPenY - height;
15809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
15909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk}
16009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
16109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
16209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                     uint32_t start, int32_t numGlyphs,
16309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                     RenderMode mode, Rect *bounds,
164afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
165afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
166d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
167d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
168d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
169afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mode == Font::MEASURE) {
17009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        if (bounds == NULL) {
171af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("No return rectangle provided to measure text");
17209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            return;
17309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        }
17409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        // Reset min and max of the bounding box to something large
1755224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        bounds->set(1e6, -1e6, 1e6, -1e6);
17609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
17709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
17809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t penX = x, penY = y;
17909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t glyphsLeft = 1;
180afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (numGlyphs > 0) {
181d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        glyphsLeft = numGlyphs;
182d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
183d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
184d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t index = start;
185d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t nextIndex = 0;
186d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
187d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    while (glyphsLeft > 0) {
188d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
189c9c38dd8508a2f805213abee1f9f44f103ac0a0dKenny Root        int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
190d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
191d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Reached the end of the string or encountered
192afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (utfChar < 0) {
193d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
194d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
195d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
196d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Move to the next character in the array
197d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        index = nextIndex;
198d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
19901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
200d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
201d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
202afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (cachedGlyph->mIsValid) {
203afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            switch (mode) {
20409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case FRAMEBUFFER:
20509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
20609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
20709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case BITMAP:
20809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
20909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
21009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case MEASURE:
21109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
21209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
21309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            }
214d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
215d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
21602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        penX += (cachedGlyph->mAdvanceX >> 6);
217d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
218d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
219afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (numGlyphs > 0) {
220d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            glyphsLeft --;
221d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
222d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
223d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
224d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
22501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
22601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
22701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
228afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (cachedGlyph == NULL) {
22901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
23001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
23101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Is the glyph still in texture cache?
232afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!cachedGlyph->mIsValid) {
23301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        updateGlyphCache(cachedGlyph);
23401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
23501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
23601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return cachedGlyph;
23701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
23801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
239afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph) {
240b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
241a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
242afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
243af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Couldn't load glyph.");
244a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        return;
245a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
246d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
24702000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    glyph->mAdvanceX = mFace->glyph->advance.x;
24802000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    glyph->mAdvanceY = mFace->glyph->advance.y;
249a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
250a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
251d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
252a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
253d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
254d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
255d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
256d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
257d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
258d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
259d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
260a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
261d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
262afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!glyph->mIsValid) {
263d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
264d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
265d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
266a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endX = startX + bitmap->width;
267a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
268d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
269d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinX = startX;
270d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinY = startY;
271a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
272a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
273d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
274d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
275d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
276d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
277d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
278d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
279d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
280d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
281b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
282d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
283d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
284afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
285d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
286d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
287b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
288d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
289d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mIsValid = false;
290b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
291d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    updateGlyphCache(newGlyph);
292d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
293d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return newGlyph;
294d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
295d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
2965224a27798f89093b13722b41143551a057ce550Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
2975224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk                    const void *data, uint32_t dataLen) {
29835b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    rsc->mStateFont.checkInit();
299d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
300d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
301afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < activeFonts.size(); i ++) {
302d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        Font *ithFont = activeFonts[i];
303afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
304d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return ithFont;
305d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
306d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
307d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
308d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *newFont = new Font(rsc);
3095224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
310afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (isInitialized) {
311d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        activeFonts.push(newFont);
31201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
313d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return newFont;
314d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
315d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
316225afd317e101a7be5fe02c0a86361146ea89f05Jason Sams    ObjectBase::checkDelete(newFont);
317d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return NULL;
318d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
319d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
320afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::~Font() {
321b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
322afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mFace) {
323d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        FT_Done_Face(mFace);
324d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
325b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif
326d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
327afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
328d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
329d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete glyph;
330d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
331d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
332d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
333afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::FontState() {
334d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
335d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
336d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex = 0;
337d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC = NULL;
338b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
3393659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mLibrary = NULL;
340b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
341c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
3427e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich    float gamma = DEFAULT_TEXT_GAMMA;
3437e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
3447e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
3457e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich
3467e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich#ifdef HAVE_ANDROID_OS
347c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the renderer properties
348c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
349c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
350c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the gamma
351c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
352c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        gamma = atof(property);
353c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
354c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
355c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the black gamma threshold
356c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
357c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        blackThreshold = atoi(property);
358c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
359c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
360c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the white gamma threshold
361c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
362c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        whiteThreshold = atoi(property);
363c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
3647e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich#endif
3657e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich
3667e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich    mBlackThreshold = (float)(blackThreshold) / 255.0f;
367c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
368c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
369c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Compute the gamma tables
370c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackGamma = gamma;
371c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
3724f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
3734f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
374d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
375d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
376afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::~FontState() {
377afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
378d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete mCacheLines[i];
379d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
380d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
381d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
382d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
383b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
384afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFT_Library FontState::getLib() {
385afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!mLibrary) {
386a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
387afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (error) {
388af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("Unable to initialize freetype");
389a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk            return NULL;
390d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
391d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
3923659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
393a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return mLibrary;
394a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk}
395b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
396b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk
397d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
398afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::init(Context *rsc) {
399a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mRSC = rsc;
400d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
401d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
402afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::flushAllAndInvalidate() {
403afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
404d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
405d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
406d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
407afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
408d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
409d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
410afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
411d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
412d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
413d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
414d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
415b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
416afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
417d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the glyph is too tall, don't cache it
418afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
419af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
420d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
421d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
422d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
423d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
424d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
425d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
426d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
427d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool bitmapFit = false;
428afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
429d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
430afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (bitmapFit) {
431d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
432d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
433d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
434d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
435d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
436afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!bitmapFit) {
437d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        flushAllAndInvalidate();
438d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
439d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Try to fit it again
440afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
441d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
442afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            if (bitmapFit) {
443d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                break;
444d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            }
445d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
446d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
447d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
448afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!bitmapFit) {
449af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
450d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return false;
451d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
452d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
453d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
454d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginX = startX;
455d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginY = startY;
456d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
457d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
458d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
459d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
460d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
461d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
462a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    uint8_t *cacheBuffer = mCacheBuffer;
46309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
464d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
465d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
466afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
467afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
46809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
469d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
470d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
471d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
472d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
473d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // This will dirty the texture and the shader so next time
474d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // we draw it will upload the data
475eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
476a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
477a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams        RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
478358747a3118301c5faeee73c98dd5f839bbfb54aTim Murray        mCacheBuffer, mCacheWidth*mCacheHeight, mCacheWidth);
479a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams
480383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
481d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
482d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Some debug code
483afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
484af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Cache Line: H: %u Empty Space: %f",
485d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
486d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
487d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
488d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }*/
489d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
490d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
491d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
492b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
493d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
494afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initRenderState() {
49548ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams    const char *shaderString = "varying vec2 varTex0;\n"
49648ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "void main() {\n"
49748ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "  lowp vec4 col = UNI_Color;\n"
49848ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"
49948ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "  col.a = pow(col.a, UNI_Gamma);\n"
50048ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "  gl_FragColor = col;\n"
50148ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "}\n";
502e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
503748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    const char *textureNames[] = { "Tex0" };
504748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    const size_t textureNamesLengths[] = { 4 };
505748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
506748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk
507748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
508748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_USER, false, 4);
509748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
510748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_USER, false, 1);
511f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams
512f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    const char *ebn1[] = { "Color", "Gamma" };
513f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    const Element *ebe1[] = {colorElem.get(), gammaElem.get()};
514f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    ObjectBaseRef<const Element> constInput = Element::create(mRSC, 2, ebe1, ebn1);
515e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
516a572aca4eb4ddb32c10baa1f529431cfefd756b8Jason Sams    ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false, 0);
517e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
518f8852d0494a260c583795a96a2a06c49b86a9b10Ian Rogers    uintptr_t tmp[4];
519e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
520f8852d0494a260c583795a96a2a06c49b86a9b10Ian Rogers    tmp[1] = (uintptr_t)inputType.get();
52184e4027f83b20af59f5b1fc52be6e45f159d3970Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
52284e4027f83b20af59f5b1fc52be6e45f159d3970Alex Sakhartchouk    tmp[3] = RS_TEXTURE_2D;
523e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
524c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
525748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                          RS_ALLOCATION_USAGE_SCRIPT |
526748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                          RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
52748ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
528748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                              textureNames, numTextures, textureNamesLengths,
529748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                              tmp, 4);
530d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontShaderF.set(pf);
531383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
532d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
533c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
534748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                         RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
535748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                         RS_SAMPLER_CLAMP).get());
536c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
537c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk
538c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
539c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        false, false,
540c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_BLEND_SRC_SRC_ALPHA,
541c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
542c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_DEPTH_FUNC_ALWAYS).get());
5438feea4e0dec48ea03bd6d32706d058b86dddc5baJason Sams    mFontProgramStore->init();
544d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
545d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
546afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initTextTexture() {
547748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
548748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_PIXEL_A, true, 1);
549d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
550d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
551a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mCacheHeight = 256;
552a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mCacheWidth = 1024;
553748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
554a572aca4eb4ddb32c10baa1f529431cfefd756b8Jason Sams                                                   mCacheWidth, mCacheHeight, 0, false, false, 0);
555a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
556a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams
557d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
558c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
559a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams                                RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
560d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
561d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
562d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
56309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nextLine = 0;
564d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
565d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
566d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
567d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
56801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
56901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
570d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
571d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
572d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
573d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
574d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
575d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
576d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
577d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
578d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
579d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
580afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initVertexArrayBuffers() {
581d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now lets write index data
582c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
583d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
584a572aca4eb4ddb32c10baa1f529431cfefd756b8Jason Sams    ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false, 0);
585d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
586c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
587eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                          RS_ALLOCATION_USAGE_SCRIPT |
588eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                          RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
589a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
590d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
591d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
592afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
59309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i6 = i * 6;
59409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i4 = i * 4;
595d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
596d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
597d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
598d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
599d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
600d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
601d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
602d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
603d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
604d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
605eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    indexAlloc->sendDirty(mRSC);
606d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
607c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
608c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
609d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
610f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    const char *ebn1[] = { "position", "texture0" };
611f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    const Element *ebe1[] = {posElem.get(), texElem.get()};
612f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
613d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
614c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
615c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                          mMaxNumberOfQuads * 4,
616a572aca4eb4ddb32c10baa1f529431cfefd756b8Jason Sams                                                          0, 0, false, false, 0);
617d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
618c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
619eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                           RS_ALLOCATION_USAGE_SCRIPT);
620a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
621d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
622a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh.set(new Mesh(mRSC, 1, 1));
623a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->setVertexBuffer(vertexAlloc, 0);
624a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
625a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->init();
626a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
627a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
628d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
629d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
630d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
631afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::checkInit() {
632afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
633d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
634d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
635d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
636d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initTextTexture();
637d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initRenderState();
638d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
639d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initVertexArrayBuffers();
640d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
64135b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
642a7f5e0406825151660c1c2e75c287e2fc8368023Jason Sams    mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
643a7f5e0406825151660c1c2e75c287e2fc8368023Jason Sams                     "EISARNTOLCDUGPMHBYFVKWZXJQ"
644a7f5e0406825151660c1c2e75c287e2fc8368023Jason Sams                     ",.?!()-+@;:`'0123456789";
645d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
646d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
647d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
648d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::issueDrawCommand() {
64960709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    Context::PushState ps(mRSC);
650d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
65160709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
65260709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
65360709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramFragment(mFontShaderF.get());
65460709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramStore(mFontProgramStore.get());
655d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
656afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mConstantsDirty) {
6574b45b8998e0d7038efaea80c70d23c086640b4e3Jason Sams        mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
658c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstantsDirty = false;
659ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    }
660ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
661d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if (!mRSC->setupCheck()) {
662d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
663d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
664d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
665a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
666d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
667d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
668d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
669afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u1, float v1,
670afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x2, float y2, float z2,
671afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u2, float v2,
672afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x3, float y3, float z3,
673afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u3, float v3,
674afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x4, float y4, float z4,
675afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u4, float v4) {
676d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
6772d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    const uint32_t floatsPerVert = 6;
678d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
679d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
680a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
681d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
682d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
683d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
684d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
685af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
686af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
687af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
688d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
689d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x1;
690d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y1;
691d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z1;
6922d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
693d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u1;
694d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v1;
695d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
696d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x2;
697d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y2;
698d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z2;
6992d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
700d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u2;
701d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v2;
702d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
703d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x3;
704d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y3;
705d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z3;
7062d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
707d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u3;
708d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v3;
709d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
710d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x4;
711d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y4;
712d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z4;
7132d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
714d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u4;
715d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v4;
716d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
717d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex ++;
718d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
719afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
720d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
721d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
722d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
723d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
724d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
72501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
72601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = 0;
72735b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    uint32_t totalPixels = 0;
728afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
72901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
73001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
73101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
73201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
73301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return remainingCapacity;
73401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
73501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
73601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
73701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Remaining capacity is measured in %
73801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
73901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t precacheIdx = 0;
740a7f5e0406825151660c1c2e75c287e2fc8368023Jason Sams    const size_t l = strlen(mLatinPrecache);
741a7f5e0406825151660c1c2e75c287e2fc8368023Jason Sams    while ((remainingCapacity > 25) && (precacheIdx < l)) {
74201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
74301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
74401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        precacheIdx ++;
74501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
74601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
74701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
74801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
74909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
75009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
75109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::RenderMode mode,
75209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::Rect *bounds,
753afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
754d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    checkInit();
755d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
756d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Render code here
757d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
758afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
759afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!mDefault.get()) {
76048ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams            char fullPath[1024];
76148ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams            const char * root = getenv("ANDROID_ROOT");
76248ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams            rsAssert(strlen(root) < 256);
76348ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams            strcpy(fullPath, root);
76448ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams            strcat(fullPath, "/fonts/Roboto-Regular.ttf");
76548ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams            mDefault.set(Font::create(mRSC, fullPath, 8, mRSC->getDPI()));
766a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        }
767a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        currentFont = mDefault.get();
768a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
769afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
770af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to initialize any fonts");
7713659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        return;
7723659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
7733659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
774a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    // Cull things that are off the screen
775a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
776a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
777a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk
77809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
77909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
780d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
781afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
782d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
783d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
784d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
785d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
786d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
78709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
78809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
7895224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bounds->bottom = - bounds->bottom;
7905224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bounds->top = - bounds->top;
791d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
792d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
7939fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
794c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[0] = r;
795c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[1] = g;
796c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[2] = b;
797c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[3] = a;
798c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
799c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mGamma = 1.0f;
800c8fb69e4a3e01501a3d38a6d3ea185e583d3f493Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
801c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (luminance <= mBlackThreshold) {
802c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mBlackGamma;
803c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
804c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
805c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
8064f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
807c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstantsDirty = true;
8089fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk}
8099fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk
810ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
811c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *r = mConstants.mFontColor[0];
812c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *g = mConstants.mFontColor[1];
813c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *b = mConstants.mFontColor[2];
814c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *a = mConstants.mFontColor[3];
815ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk}
816ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
817afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::deinit(Context *rsc) {
818a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mInitialized = false;
819a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
82001b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines    mFontShaderFConstant.clear();
82101b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines
822a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh.clear();
823a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
824a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontShaderF.clear();
825a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontSampler.clear();
826a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontProgramStore.clear();
827a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
828a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mTextTexture.clear();
829afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
830a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        delete mCacheLines[i];
831d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
832a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mCacheLines.clear();
833d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
834d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDefault.clear();
835b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
836afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mLibrary) {
837a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Done_FreeType( mLibrary );
8383659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        mLibrary = NULL;
839a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
840b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
841d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
842d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
843b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
84402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchoukbool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
84502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    if ((uint32_t)bitmap->rows > mMaxHeight) {
84602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        return false;
84702000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    }
84802000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
84902000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
85002000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        *retOriginX = mCurrentCol;
85102000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        *retOriginY = mCurrentRow;
85202000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        mCurrentCol += bitmap->width;
85302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        mDirty = true;
85402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk       return true;
85502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    }
85602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
85702000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    return false;
85802000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk}
859b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
86002000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
861d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace android {
862d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace renderscript {
863d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
86470b83c111beceaf8fbb700580833e7fec99272cfAlex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc,
86570b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                              char const *name, size_t name_length,
86670b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                              float fontSize, uint32_t dpi) {
867a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
868afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (newFont) {
869a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        newFont->incUserRef();
870a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
871a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return newFont;
872d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
873d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
87470b83c111beceaf8fbb700580833e7fec99272cfAlex SakhartchoukRsFont rsi_FontCreateFromMemory(Context *rsc,
87570b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                char const *name, size_t name_length,
87670b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                float fontSize, uint32_t dpi,
87770b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                const void *data, size_t data_length) {
87870b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
8795224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (newFont) {
8805224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        newFont->incUserRef();
8815224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    }
8825224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    return newFont;
8835224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk}
8845224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk
885d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // renderscript
886d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // android
887