rsFont.cpp revision 60709257bbdeb0c50f39b9c8969dc76264d6e142
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#ifndef ANDROID_RS_BUILD_FOR_HOST
19d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsContext.h"
20d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#else
21d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsContextHostStub.h"
22d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#endif
23d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
24d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsFont.h"
25d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsProgramFragment.h"
26c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk#include <cutils/properties.h>
27d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include FT_BITMAP_H
28d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
29d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES/gl.h>
30d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES/glext.h>
31d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES2/gl2.h>
32d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include <GLES2/gl2ext.h>
33d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
34d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android;
35d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukusing namespace android::renderscript;
36d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
37afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
38d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
39d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = false;
403659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mFace = NULL;
41d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
42d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
43afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukbool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) {
44afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
45d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
46d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
47d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
48d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
49d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    String8 fontsDir("/fonts/");
50d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    String8 fullPath(getenv("ANDROID_ROOT"));
51d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    fullPath += fontsDir;
52d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    fullPath += name;
53d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
54a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
55afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
56d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Unable to initialize font %s", fullPath.string());
57d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
58d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
59d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
60d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontName = name;
61d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSize = fontSize;
62d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDpi = dpi;
63d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
64d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
65afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
66d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Unable to set font size on %s", fullPath.string());
67d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
68d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
69d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
70d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
71d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
72d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
73d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
74d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
75d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
76afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::invalidateTextureCache() {
77afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
78d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
79d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
80d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
81d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
82afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
83d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
84d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
8509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
8609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
87d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
8809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float u1 = glyph->mBitmapMinU;
8909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float u2 = glyph->mBitmapMaxU;
9009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float v1 = glyph->mBitmapMinV;
9109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float v2 = glyph->mBitmapMaxV;
92d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
9309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
9409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
95d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
9609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
9709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX + width, nPenY, 0, u2, v2,
9809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX + width, nPenY - height, 0, u2, v1,
9909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX, nPenY - height, 0, u1, v1);
10009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk}
10109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
10209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
10309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
10409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
10509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y + glyph->mBitmapTop;
10609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
10709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
10809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
10909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
11109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
11209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    const uint8_t* cacheBuffer = state->getTextTextureData();
11309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
11509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t bX = 0, bY = 0;
11609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
11709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
11809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
11909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                LOGE("Skipping invalid index");
12009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                continue;
12109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            }
12209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
12309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
12409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        }
12509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
126d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
127d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
12809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
12909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
13009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
13109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
13209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
13309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
13409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
13509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->bottom > nPenY) {
13609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->bottom = nPenY;
13709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
13809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->left > nPenX) {
13909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->left = nPenX;
14009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
14109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->right < nPenX + width) {
14209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->right = nPenX + width;
14309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
14409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->top < nPenY + height) {
14509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->top = nPenY + height;
14609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
14709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk}
14809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
14909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
15009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                     uint32_t start, int32_t numGlyphs,
15109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                     RenderMode mode, Rect *bounds,
152afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
153afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
154d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
155d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
156d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
157afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mode == Font::MEASURE) {
15809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        if (bounds == NULL) {
15909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            LOGE("No return rectangle provided to measure text");
16009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            return;
16109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        }
16209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        // Reset min and max of the bounding box to something large
16309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->set(1e6, -1e6, -1e6, 1e6);
16409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
16509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
16609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t penX = x, penY = y;
16709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t glyphsLeft = 1;
168afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (numGlyphs > 0) {
169d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        glyphsLeft = numGlyphs;
170d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
171d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
172d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t index = start;
173d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t nextIndex = 0;
174d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
175d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    while (glyphsLeft > 0) {
176d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
177c9c38dd8508a2f805213abee1f9f44f103ac0a0dKenny Root        int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
178d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
179d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Reached the end of the string or encountered
180afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (utfChar < 0) {
181d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
182d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
183d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
184d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Move to the next character in the array
185d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        index = nextIndex;
186d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
18701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
188d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
189d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
190afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (cachedGlyph->mIsValid) {
191afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            switch (mode) {
19209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case FRAMEBUFFER:
19309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
19409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
19509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case BITMAP:
19609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
19709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
19809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case MEASURE:
19909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
20009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
20109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            }
202d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
203d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
204d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        penX += (cachedGlyph->mAdvance.x >> 6);
205d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
206d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
207afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (numGlyphs > 0) {
208d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            glyphsLeft --;
209d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
210d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
211d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
212d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
21301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
21401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
21501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
216afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (cachedGlyph == NULL) {
21701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
21801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
21901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Is the glyph still in texture cache?
220afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!cachedGlyph->mIsValid) {
22101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        updateGlyphCache(cachedGlyph);
22201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
22301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
22401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return cachedGlyph;
22501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
22601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
227afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph) {
228a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
229afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
230a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        LOGE("Couldn't load glyph.");
231a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        return;
232a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
233d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
234a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mAdvance = mFace->glyph->advance;
235a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
236a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
237d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
238a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
239d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
240d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
241d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
242d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
243d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
244d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
245d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
246a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
247d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
248afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!glyph->mIsValid) {
249d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
250d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
251d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
252a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endX = startX + bitmap->width;
253a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
254d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
255d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinX = startX;
256d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinY = startY;
257a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
258a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
259d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
260d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
261d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
262d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
263d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
264d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
265d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
266d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
267d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
268d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
269afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
270d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
271d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
272d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
273d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
274d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mIsValid = false;
275d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
276d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    updateGlyphCache(newGlyph);
277d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
278d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return newGlyph;
279d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
280d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
281afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi) {
28235b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    rsc->mStateFont.checkInit();
283d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
284d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
285afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < activeFonts.size(); i ++) {
286d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        Font *ithFont = activeFonts[i];
287afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
288d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return ithFont;
289d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
290d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
291d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
292d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *newFont = new Font(rsc);
293d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi);
294afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (isInitialized) {
295d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        activeFonts.push(newFont);
29601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
297d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return newFont;
298d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
299d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
300225afd317e101a7be5fe02c0a86361146ea89f05Jason Sams    ObjectBase::checkDelete(newFont);
301d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return NULL;
302d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
303d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
304afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::~Font() {
305afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mFace) {
306d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        FT_Done_Face(mFace);
307d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
308d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
309d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
310d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
311d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            mRSC->mStateFont.mActiveFonts.removeAt(ct);
312d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
313d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
314d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
315d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
316afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
317d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
318d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete glyph;
319d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
320d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
321d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
322afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::FontState() {
323d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
324d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
325d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex = 0;
326d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mRSC = NULL;
3273659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    mLibrary = NULL;
328c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
329c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the renderer properties
330c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
331c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
332c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the gamma
333c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    float gamma = DEFAULT_TEXT_GAMMA;
334c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
335c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Setting text gamma to %s", property);
336c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        gamma = atof(property);
337c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else {
338c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
339c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
340c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
341c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the black gamma threshold
34209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
343c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
344c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Setting text black gamma threshold to %s", property);
345c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        blackThreshold = atoi(property);
346c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else {
347c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Using default text black gamma threshold of %d",
348c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk                DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
349c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
350c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackThreshold = (float)(blackThreshold) / 255.0f;
351c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
352c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the white gamma threshold
35309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
354c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
355c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Setting text white gamma threshold to %s", property);
356c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        whiteThreshold = atoi(property);
357c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else {
358c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        LOGD("  Using default white black gamma threshold of %d",
359c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk                DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
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}
377d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
378afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFT_Library FontState::getLib() {
379afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!mLibrary) {
380a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
381afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (error) {
382d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            LOGE("Unable to initialize freetype");
383a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk            return NULL;
384d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
385d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
3863659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
387a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return mLibrary;
388a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk}
389d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
390afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::init(Context *rsc) {
391a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mRSC = rsc;
392d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
393d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
394afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::flushAllAndInvalidate() {
395afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
396d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
397d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
398d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
399afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
400d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
401d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
402afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
403d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
404d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
405d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
406d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
407afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
408d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the glyph is too tall, don't cache it
409afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
410d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
411d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
412d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
413d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
414d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
415d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
416d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
417d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
418d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool bitmapFit = false;
419afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
420d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
421afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (bitmapFit) {
422d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
423d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
424d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
425d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
426d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
427afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!bitmapFit) {
428d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        flushAllAndInvalidate();
429d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
430d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Try to fit it again
431afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
432d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
433afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            if (bitmapFit) {
434d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                break;
435d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            }
436d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
437d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
438d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
439afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!bitmapFit) {
440d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
441d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return false;
442d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
443d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
444d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
445d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginX = startX;
446d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginY = startY;
447d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
448d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
449d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
450d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
451d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
452d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
45309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
45409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
455d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
456d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
457afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
458afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
45909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
460d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
461d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
462d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
463d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
464d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // This will dirty the texture and the shader so next time
465d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // we draw it will upload the data
466d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
467383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
468d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
469d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Some debug code
470afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
471d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
472d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
473d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
474d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
475d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }*/
476d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
477d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
478d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
479d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
480afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initRenderState() {
4817ffcaf20cbb115326f3d72a983835d6c314a4cefAlex Sakhartchouk    String8 shaderString("varying vec2 varTex0;\n");
482e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("void main() {\n");
483e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
484e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
485c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
486e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
487e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    shaderString.append("}\n");
488e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
489e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
490c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
491e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
492e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
493c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
494e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
495e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
496f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams    Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
497e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
498e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    uint32_t tmp[4];
499e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
500e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[1] = (uint32_t)inputType;
501e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
502e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[3] = 1;
503e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
504e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    mFontShaderFConstant.set(new Allocation(mRSC, inputType));
505e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
506e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk                                              shaderString.length(), tmp, 4);
507d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontShaderF.set(pf);
508383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
509d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
510d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
511d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
512d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSampler.set(sampler);
513383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, sampler);
514d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
515d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    ProgramStore *fontStore = new ProgramStore(mRSC);
516d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore.set(fontStore);
517d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
518d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
519d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setDitherEnable(false);
520d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontProgramStore->setDepthMask(false);
521d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
522d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
523afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initTextTexture() {
524d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
525d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
526d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
527f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams    Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
528d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
529d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Allocation *cacheAlloc = new Allocation(mRSC, texType);
530d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
531d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
532d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
533d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
53409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nextLine = 0;
535d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
536d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
537d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
538d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
53901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
54001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
541d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
542d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
543d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
544d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
545d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
546d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
547d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
548d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
549d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
550d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
551afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initVertexArrayBuffers() {
552d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now lets write index data
553d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
554d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
555f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams    Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
556d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
557d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Allocation *indexAlloc = new Allocation(mRSC, indexType);
558d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
559d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
560d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
561afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
56209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i6 = i * 6;
56309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i4 = i * 4;
564d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
565d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
566d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
567d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
568d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
569d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
570d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
571d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
572d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
573d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
574d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    indexAlloc->deferedUploadToBufferObject(mRSC);
575d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mIndexBuffer.set(indexAlloc);
576d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
577d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
578d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
579d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
58064cd98e83d33011950b88f229d013e06c62b36e9Alex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
58164cd98e83d33011950b88f229d013e06c62b36e9Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
58264cd98e83d33011950b88f229d013e06c62b36e9Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
58364cd98e83d33011950b88f229d013e06c62b36e9Alex Sakhartchouk    const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
584d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
585f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams    Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
586f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams                                         mMaxNumberOfQuads * 4,
587f0c1df480304a72ce41e7d4b088319cbd7f0938aJason Sams                                         0, 0, false, false);
588d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
589d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
590d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
591d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
592d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mVertexArray.set(vertexAlloc);
593d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
594d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
595d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
596afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::checkInit() {
597afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
598d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
599d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
600d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
601d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initTextTexture();
602d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initRenderState();
603d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
604d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initVertexArrayBuffers();
605d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
60635b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
60735b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
60835b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
60935b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
61035b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    mLatinPrecache += String8("0123456789");
61135b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk
612d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
613d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
614d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
615d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::issueDrawCommand() {
61660709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    Context::PushState ps(mRSC);
617d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
61860709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
61960709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
62060709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramFragment(mFontShaderF.get());
62160709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramStore(mFontProgramStore.get());
622d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
623afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mConstantsDirty) {
624c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
625c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstantsDirty = false;
626ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    }
627ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
628d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if (!mRSC->setupCheck()) {
629d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
630d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
631d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
632d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *vtx = (float*)mVertexArray->getPtr();
633d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *tex = vtx + 3;
634d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
63554929cce0bf44090424b1f91b676529a2422378fAlex Sakhartchouk    VertexArray::Attrib attribs[2];
63654929cce0bf44090424b1f91b676529a2422378fAlex Sakhartchouk    attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
63754929cce0bf44090424b1f91b676529a2422378fAlex Sakhartchouk    attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
63854929cce0bf44090424b1f91b676529a2422378fAlex Sakhartchouk    VertexArray va(attribs, 2);
639d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
640d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
641d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mIndexBuffer->uploadCheck(mRSC);
642d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
643d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
644d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
645d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
646d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
647afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u1, float v1,
648afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x2, float y2, float z2,
649afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u2, float v2,
650afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x3, float y3, float z3,
651afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u3, float v3,
652afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x4, float y4, float z4,
653afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u4, float v4) {
654d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
655d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
656d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
657d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
658d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Cull things that are off the screen
659d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float width = (float)mRSC->getWidth();
660d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float height = (float)mRSC->getHeight();
661d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
662afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
663d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
664d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
665d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
666d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
667d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
668d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
669d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
670d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
671d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x1;
672d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y1;
673d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z1;
674d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u1;
675d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v1;
676d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
677d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x2;
678d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y2;
679d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z2;
680d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u2;
681d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v2;
682d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
683d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x3;
684d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y3;
685d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z3;
686d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u3;
687d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v3;
688d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
689d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x4;
690d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y4;
691d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z4;
692d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u4;
693d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v4;
694d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
695d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex ++;
696d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
697afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
698d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
699d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
700d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
701d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
702d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
70301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
70401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = 0;
70535b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    uint32_t totalPixels = 0;
706afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
70701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
70801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
70901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
71001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
71101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return remainingCapacity;
71201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
71301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
71401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
71501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Remaining capacity is measured in %
71601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
71701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t precacheIdx = 0;
718afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
71901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
72001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
72101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        precacheIdx ++;
72201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
72301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
72401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
72501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
72609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
72709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
72809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::RenderMode mode,
72909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::Rect *bounds,
730afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
731d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    checkInit();
732d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
733d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Render code here
734d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
735afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
736afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!mDefault.get()) {
737a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk            mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
738a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        }
739a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        currentFont = mDefault.get();
740a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
741afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
7423659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        LOGE("Unable to initialize any fonts");
7433659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        return;
7443659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
7453659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
74609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
74709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
748d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
749afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
750d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
751d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
752d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
753d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
754d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
75509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
75609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
757d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
758d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
7599fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
760c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[0] = r;
761c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[1] = g;
762c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[2] = b;
763c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[3] = a;
764c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
765c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mGamma = 1.0f;
766c8fb69e4a3e01501a3d38a6d3ea185e583d3f493Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
767c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (luminance <= mBlackThreshold) {
768c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mBlackGamma;
769c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
770c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
771c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
7724f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
773c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstantsDirty = true;
7749fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk}
7759fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk
776ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
777c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *r = mConstants.mFontColor[0];
778c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *g = mConstants.mFontColor[1];
779c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *b = mConstants.mFontColor[2];
780c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *a = mConstants.mFontColor[3];
781ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk}
782ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
783afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::deinit(Context *rsc) {
784a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mInitialized = false;
785a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
78601b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines    mFontShaderFConstant.clear();
78701b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines
788a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mIndexBuffer.clear();
789a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mVertexArray.clear();
790a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
791a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontShaderF.clear();
792a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontSampler.clear();
793a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontProgramStore.clear();
794a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
795a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mTextTexture.clear();
796afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
797a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        delete mCacheLines[i];
798d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
799a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mCacheLines.clear();
800d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
801d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDefault.clear();
802a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
8033659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    Vector<Font*> fontsToDereference = mActiveFonts;
804afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < fontsToDereference.size(); i ++) {
8053659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        fontsToDereference[i]->zeroUserRef();
8063659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
8073659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
808afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mLibrary) {
809a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Done_FreeType( mLibrary );
8103659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        mLibrary = NULL;
811a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
812d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
813d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
814d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace android {
815d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouknamespace renderscript {
816d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
817afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) {
818a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
819afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (newFont) {
820a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        newFont->incUserRef();
821a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
822a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return newFont;
823d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
824d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
825d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // renderscript
826d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk} // android
827