rsFont.cpp revision e27cdeeecba5b445e307d653d9cb7da007adfac3
19b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
29b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk/*
39b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * Copyright (C) 2009 The Android Open Source Project
49b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *
59b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * Licensed under the Apache License, Version 2.0 (the "License");
69b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * you may not use this file except in compliance with the License.
79b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * You may obtain a copy of the License at
89b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *
99b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *      http://www.apache.org/licenses/LICENSE-2.0
109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk *
119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * Unless required by applicable law or agreed to in writing, software
129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * distributed under the License is distributed on an "AS IS" BASIS,
139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * See the License for the specific language governing permissions and
159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk * limitations under the License.
169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk */
179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#ifndef ANDROID_RS_BUILD_FOR_HOST
199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsContext.h"
209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#else
219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsContextHostStub.h"
229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#endif
239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsFont.h"
259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsProgramFragment.h"
263bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk#include <cutils/properties.h>
279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include FT_BITMAP_H
289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES/gl.h>
309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES/glext.h>
319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES2/gl2.h>
329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include <GLES2/gl2ext.h>
339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukusing namespace android;
359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukusing namespace android::renderscript;
369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
37ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = false;
40b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mFace = NULL;
419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
43e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchoukbool Font::init(const char *name, float fontSize, uint32_t dpi) {
44ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mInitialized) {
459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
49e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk    FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
50ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (error) {
51e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk        LOGE("Unable to initialize font %s", name);
529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontName = name;
569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSize = fontSize;
579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDpi = dpi;
589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
59e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
60ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (error) {
61e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk        LOGE("Unable to set font size on %s", name);
629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
71ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid Font::invalidateTextureCache() {
72ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
77ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
8110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float u1 = glyph->mBitmapMinU;
8410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float u2 = glyph->mBitmapMaxU;
8510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float v1 = glyph->mBitmapMinV;
8610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float v2 = glyph->mBitmapMaxV;
879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
8910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
9110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
9210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX + width, nPenY, 0, u2, v2,
9310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX + width, nPenY - height, 0, u2, v1,
9410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX, nPenY - height, 0, u1, v1);
9510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk}
9610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
9710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
9810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
9910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
10010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y + glyph->mBitmapTop;
10110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
10210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
10310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
10410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
10510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
10610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
10710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    const uint8_t* cacheBuffer = state->getTextTextureData();
10810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
10910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
11010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t bX = 0, bY = 0;
11110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
11210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
11310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
11410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                LOGE("Skipping invalid index");
11510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                continue;
11610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            }
11710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
11810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
11910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        }
12010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
1219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
1229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
12310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
12410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
12510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
12610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
12710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
12810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
12910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
13010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->bottom > nPenY) {
13110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->bottom = nPenY;
13210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
13310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->left > nPenX) {
13410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->left = nPenX;
13510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
13610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->right < nPenX + width) {
13710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->right = nPenX + width;
13810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
13910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->top < nPenY + height) {
14010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->top = nPenY + height;
14110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
14210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk}
14310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
14410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
14510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     uint32_t start, int32_t numGlyphs,
14610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     RenderMode mode, Rect *bounds,
147ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
148ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
1499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
1509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
152ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mode == Font::MEASURE) {
15310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        if (bounds == NULL) {
15410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            LOGE("No return rectangle provided to measure text");
15510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            return;
15610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        }
15710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        // Reset min and max of the bounding box to something large
15810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->set(1e6, -1e6, -1e6, 1e6);
15910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
16010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
16110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t penX = x, penY = y;
16210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t glyphsLeft = 1;
163ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (numGlyphs > 0) {
1649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        glyphsLeft = numGlyphs;
1659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t index = start;
1689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t nextIndex = 0;
1699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    while (glyphsLeft > 0) {
1719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
172300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root        int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
1739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Reached the end of the string or encountered
175ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (utfChar < 0) {
1769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
1779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Move to the next character in the array
1809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        index = nextIndex;
1819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
18294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
1839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
185ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (cachedGlyph->mIsValid) {
186ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk            switch (mode) {
18710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case FRAMEBUFFER:
18810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
18910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
19010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case BITMAP:
19110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
19210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
19310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case MEASURE:
19410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
19510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
19610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            }
1979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        penX += (cachedGlyph->mAdvance.x >> 6);
2009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
202ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (numGlyphs > 0) {
2039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            glyphsLeft --;
2049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
20894bbccc36322168a596369c8341dad938c8f949fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
20994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
21094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
211ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (cachedGlyph == NULL) {
21294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
21394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
21494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Is the glyph still in texture cache?
215ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!cachedGlyph->mIsValid) {
21694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        updateGlyphCache(cachedGlyph);
21794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
21894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
21994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return cachedGlyph;
22094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
22194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
222ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph) {
223071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
224ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (error) {
225071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        LOGE("Couldn't load glyph.");
226071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        return;
227071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
2289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
229071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mAdvance = mFace->glyph->advance;
230071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
231071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
2329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
233071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
2349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
2369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
2379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
2389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
2409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
241071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
2429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
243ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!glyph->mIsValid) {
2449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
2459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
247071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
248071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
2499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinX = startX;
2519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinY = startY;
252071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
253071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
2549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
2569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
2579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
2599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
2609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
2619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
2629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
264ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
2659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
2669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
2679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
2699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mIsValid = false;
2709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    updateGlyphCache(newGlyph);
2729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return newGlyph;
2749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
276e27cdeeecba5b445e307d653d9cb7da007adfac3Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi) {
27727f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    rsc->mStateFont.checkInit();
2789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
2799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
280ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < activeFonts.size(); i ++) {
2819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        Font *ithFont = activeFonts[i];
282ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
2839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return ithFont;
2849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *newFont = new Font(rsc);
2889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi);
289ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (isInitialized) {
2909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        activeFonts.push(newFont);
29194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
2929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return newFont;
2939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
295b38d534873ca514f5a5230596c838aa37eca1568Jason Sams    ObjectBase::checkDelete(newFont);
2969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return NULL;
2979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
299ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFont::~Font() {
300ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mFace) {
3019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        FT_Done_Face(mFace);
3029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
3059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
3069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            mRSC->mStateFont.mActiveFonts.removeAt(ct);
3079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
3089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
311ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
3129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
3139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete glyph;
3149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
317ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFontState::FontState() {
3189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
3199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
3209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex = 0;
3219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC = NULL;
322b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mLibrary = NULL;
3233bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3243bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the renderer properties
3253bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
3263bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3273bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the gamma
3283bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    float gamma = DEFAULT_TEXT_GAMMA;
3293bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
3303bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        gamma = atof(property);
3313bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3323bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3333bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the black gamma threshold
33410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
3353bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
3363bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        blackThreshold = atoi(property);
3373bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3383bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mBlackThreshold = (float)(blackThreshold) / 255.0f;
3393bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3403bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the white gamma threshold
34110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
3423bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
3433bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        whiteThreshold = atoi(property);
3443bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3453bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
3463bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3473bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Compute the gamma tables
3483bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mBlackGamma = gamma;
3493bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
350960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk
351960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
3529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
354ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFontState::~FontState() {
355ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
3569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete mCacheLines[i];
3579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
3609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
362ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFT_Library FontState::getLib() {
363ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!mLibrary) {
364071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
365ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (error) {
3669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Unable to initialize freetype");
367071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            return NULL;
3689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
370b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
371071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return mLibrary;
372071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk}
3739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
374ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::init(Context *rsc) {
375071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mRSC = rsc;
3769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
378ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::flushAllAndInvalidate() {
379ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mCurrentQuadIndex != 0) {
3809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
3819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
3829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
383ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
3849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
3859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
386ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
3879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
3889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
391ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
3929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the glyph is too tall, don't cache it
393ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
3949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
3959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
3969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
3999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
4009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
4019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool bitmapFit = false;
403ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
405ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (bitmapFit) {
4069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
4079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
411ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!bitmapFit) {
4129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        flushAllAndInvalidate();
4139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Try to fit it again
415ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
417ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk            if (bitmapFit) {
4189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                break;
4199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            }
4209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
423ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (!bitmapFit) {
4249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
4259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return false;
4269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginX = startX;
4309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginY = startY;
4319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
4339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
4349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
4369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
43710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
43810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
4399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
441ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
442ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
44310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
4449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
4459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // This will dirty the texture and the shader so next time
4499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // we draw it will upload the data
4506d8eb266dd398abf0511685fdaf98abba3396174Jason Sams    mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
451b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
4529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Some debug code
454ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
4569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
4579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
4589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }*/
4609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
4629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
464ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::initRenderState() {
465d2091639be426574c04f74969fe553162d7a51c9Alex Sakhartchouk    String8 shaderString("varying vec2 varTex0;\n");
466c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("void main() {\n");
467c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
468c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
4693bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
470c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
471c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("}\n");
472c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
473c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
4743bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
475c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
476c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
4773bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
478c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
479c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
48031a7e42f4baa059352f0db119de38428e655eab2Jason Sams    Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
481c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
482c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    uint32_t tmp[4];
483c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
484c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[1] = (uint32_t)inputType;
48567f2e442a31b8395e3c1951f8e91139ec7f2be99Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
48667f2e442a31b8395e3c1951f8e91139ec7f2be99Alex Sakhartchouk    tmp[3] = RS_TEXTURE_2D;
487c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
4885476b450e50939940dcf3f15c92335cee2fc572dJason Sams    mFontShaderFConstant.set(new Allocation(mRSC, inputType,
4895476b450e50939940dcf3f15c92335cee2fc572dJason Sams                                            RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
490c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
491c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk                                              shaderString.length(), tmp, 4);
4929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontShaderF.set(pf);
493b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
4949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
4969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
4979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSampler.set(sampler);
498b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, sampler);
4999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ProgramStore *fontStore = new ProgramStore(mRSC);
5019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore.set(fontStore);
5029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
5039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
5049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDitherEnable(false);
5059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthMask(false);
5069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
508ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::initTextTexture() {
5099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
5109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
51231a7e42f4baa059352f0db119de38428e655eab2Jason Sams    Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
5139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5145476b450e50939940dcf3f15c92335cee2fc572dJason Sams    Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
5159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
5166d8eb266dd398abf0511685fdaf98abba3396174Jason Sams    mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
5179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
51910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nextLine = 0;
5209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
5219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
5239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
52494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
52594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
5279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
5299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
5319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
5339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
536ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::initVertexArrayBuffers() {
5379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now lets write index data
5389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
5399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
54031a7e42f4baa059352f0db119de38428e655eab2Jason Sams    Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
5419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5425476b450e50939940dcf3f15c92335cee2fc572dJason Sams    Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
5439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
5449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
546ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
54710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        int32_t i6 = i * 6;
54810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        int32_t i4 = i * 4;
5499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
5519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
5529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
5539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
5559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
5569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
5579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
5589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexAlloc->deferedUploadToBufferObject(mRSC);
5609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer.set(indexAlloc);
5619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
5639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
5649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
56598bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
56698bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
56798bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
56898bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
5699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
57031a7e42f4baa059352f0db119de38428e655eab2Jason Sams    Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
57131a7e42f4baa059352f0db119de38428e655eab2Jason Sams                                         mMaxNumberOfQuads * 4,
57231a7e42f4baa059352f0db119de38428e655eab2Jason Sams                                         0, 0, false, false);
5739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5745476b450e50939940dcf3f15c92335cee2fc572dJason Sams    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
5759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
5769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mVertexArray.set(vertexAlloc);
5789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
581ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::checkInit() {
582ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mInitialized) {
5839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
5849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
5859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initTextTexture();
5879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initRenderState();
5889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initVertexArrayBuffers();
5909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
59127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
59227f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
59327f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
59427f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
59527f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("0123456789");
59627f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk
5979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
5989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::issueDrawCommand() {
601a17af04e62a3f40f729e7ebb8bd868d192e18405Jason Sams    Context::PushState ps(mRSC);
6029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
603a17af04e62a3f40f729e7ebb8bd868d192e18405Jason Sams    mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
604a17af04e62a3f40f729e7ebb8bd868d192e18405Jason Sams    mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
605a17af04e62a3f40f729e7ebb8bd868d192e18405Jason Sams    mRSC->setProgramFragment(mFontShaderF.get());
606a17af04e62a3f40f729e7ebb8bd868d192e18405Jason Sams    mRSC->setProgramStore(mFontProgramStore.get());
6079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
608ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mConstantsDirty) {
6093bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
6103bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstantsDirty = false;
61155e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    }
61255e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
6139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if (!mRSC->setupCheck()) {
6149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *vtx = (float*)mVertexArray->getPtr();
6189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *tex = vtx + 3;
6199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6209d71e2180062931416092f26276a07e55b318f62Alex Sakhartchouk    VertexArray::Attrib attribs[2];
6219d71e2180062931416092f26276a07e55b318f62Alex Sakhartchouk    attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
6229d71e2180062931416092f26276a07e55b318f62Alex Sakhartchouk    attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
6239d71e2180062931416092f26276a07e55b318f62Alex Sakhartchouk    VertexArray va(attribs, 2);
6249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
6259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer->uploadCheck(mRSC);
6279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
6289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
6299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
632ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u1, float v1,
633ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float x2, float y2, float z2,
634ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u2, float v2,
635ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float x3, float y3, float z3,
636ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u3, float v3,
637ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float x4, float y4, float z4,
638ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u4, float v4) {
6399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
6409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
6419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
6429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Cull things that are off the screen
6449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float width = (float)mRSC->getWidth();
6459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float height = (float)mRSC->getHeight();
6469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
647ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
6489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
6529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
6539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
6549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
6559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x1;
6579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y1;
6589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z1;
6599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u1;
6609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v1;
6619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x2;
6639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y2;
6649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z2;
6659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u2;
6669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v2;
6679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x3;
6699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y3;
6709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z3;
6719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u3;
6729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v3;
6739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x4;
6759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y4;
6769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z4;
6779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u4;
6789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v4;
6799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex ++;
6819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
682ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
6839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
6849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
6859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
68894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
68994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = 0;
69027f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    uint32_t totalPixels = 0;
691ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
69294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
69394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
69494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
69594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
69694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return remainingCapacity;
69794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
69894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
69994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
70094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Remaining capacity is measured in %
70194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
70294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t precacheIdx = 0;
703ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
70494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
70594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
70694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        precacheIdx ++;
70794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
70894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
70994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
71094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
71110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
71210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
71310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           Font::RenderMode mode,
71410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           Font::Rect *bounds,
715ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
7169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    checkInit();
7179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Render code here
7199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
720ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!currentFont) {
721ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (!mDefault.get()) {
722e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk            String8 fontsDir("/fonts/DroidSans.ttf");
723e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk            String8 fullPath(getenv("ANDROID_ROOT"));
724e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk            fullPath += fontsDir;
725e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk
726e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk            mDefault.set(Font::create(mRSC, fullPath.string(), 16, 96));
727071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        }
728071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        currentFont = mDefault.get();
729071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
730ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!currentFont) {
731b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        LOGE("Unable to initialize any fonts");
732b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        return;
733b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
734b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
73510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
73610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
7379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
738ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mCurrentQuadIndex != 0) {
7399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
7409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
7419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
74410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
74510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
7469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
748fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
7493bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[0] = r;
7503bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[1] = g;
7513bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[2] = b;
7523bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[3] = a;
7533bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
7543bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mGamma = 1.0f;
75576322af2a6c109a79431f019dcef6e038c030686Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
7563bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (luminance <= mBlackThreshold) {
7573bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstants.mGamma = mBlackGamma;
7583bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
7593bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
7603bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
761960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk
7623bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstantsDirty = true;
763fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk}
764fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk
76555e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
7663bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *r = mConstants.mFontColor[0];
7673bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *g = mConstants.mFontColor[1];
7683bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *b = mConstants.mFontColor[2];
7693bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *a = mConstants.mFontColor[3];
77055e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk}
77155e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
772ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::deinit(Context *rsc) {
773071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mInitialized = false;
774071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
77501f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines    mFontShaderFConstant.clear();
77601f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines
777071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mIndexBuffer.clear();
778071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mVertexArray.clear();
779071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
780071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontShaderF.clear();
781071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontSampler.clear();
782071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontProgramStore.clear();
783071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
784071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mTextTexture.clear();
785ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
786071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        delete mCacheLines[i];
7879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
788071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mCacheLines.clear();
7899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDefault.clear();
791071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
792b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    Vector<Font*> fontsToDereference = mActiveFonts;
793ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < fontsToDereference.size(); i ++) {
794b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        fontsToDereference[i]->zeroUserRef();
795b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
796b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
797ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mLibrary) {
798071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Done_FreeType( mLibrary );
799b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        mLibrary = NULL;
800071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
8019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace android {
8049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace renderscript {
8059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
806e27cdeeecba5b445e307d653d9cb7da007adfac3Alex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) {
807071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
808ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (newFont) {
809071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        newFont->incUserRef();
810071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
811071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return newFont;
8129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // renderscript
8159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // android
816