rsFont.cpp revision ed9f210568082dd6d1d8a0c92c693d574d87d545
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
43ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukbool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) {
44ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mInitialized) {
459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 fontsDir("/fonts/");
509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    String8 fullPath(getenv("ANDROID_ROOT"));
519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    fullPath += fontsDir;
529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    fullPath += name;
539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
54071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
55ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (error) {
569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Unable to initialize font %s", fullPath.string());
579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontName = name;
619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSize = fontSize;
629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDpi = dpi;
639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
65ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (error) {
669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Unable to set font size on %s", fullPath.string());
679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
76ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid Font::invalidateTextureCache() {
77ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
82ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
8610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float u1 = glyph->mBitmapMinU;
8910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float u2 = glyph->mBitmapMaxU;
9010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float v1 = glyph->mBitmapMinV;
9110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float v2 = glyph->mBitmapMaxV;
929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
9310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
9410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
9610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
9710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX + width, nPenY, 0, u2, v2,
9810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX + width, nPenY - height, 0, u2, v1,
9910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX, nPenY - height, 0, u1, v1);
10010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk}
10110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
10210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
10310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
10410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
10510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y + glyph->mBitmapTop;
10610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
10710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
10810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
10910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
11010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
11110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
11210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    const uint8_t* cacheBuffer = state->getTextTextureData();
11310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
11410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
11510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t bX = 0, bY = 0;
11610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
11710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
11810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
11910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                LOGE("Skipping invalid index");
12010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                continue;
12110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            }
12210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
12310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
12410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        }
12510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
1269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
1279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
12810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
12910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
13010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
13110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
13210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
13310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
13410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
13510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->bottom > nPenY) {
13610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->bottom = nPenY;
13710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
13810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->left > nPenX) {
13910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->left = nPenX;
14010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
14110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->right < nPenX + width) {
14210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->right = nPenX + width;
14310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
14410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->top < nPenY + height) {
14510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->top = nPenY + height;
14610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
14710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk}
14810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
14910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
15010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     uint32_t start, int32_t numGlyphs,
15110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     RenderMode mode, Rect *bounds,
152ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
153ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
1549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
1559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
157ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mode == Font::MEASURE) {
15810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        if (bounds == NULL) {
15910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            LOGE("No return rectangle provided to measure text");
16010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            return;
16110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        }
16210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        // Reset min and max of the bounding box to something large
16310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->set(1e6, -1e6, -1e6, 1e6);
16410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
16510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
16610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t penX = x, penY = y;
16710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t glyphsLeft = 1;
168ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (numGlyphs > 0) {
1699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        glyphsLeft = numGlyphs;
1709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t index = start;
1739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t nextIndex = 0;
1749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    while (glyphsLeft > 0) {
1769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        int32_t utfChar = utf32_at(text, len, index, &nextIndex);
1789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Reached the end of the string or encountered
180ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (utfChar < 0) {
1819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
1829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Move to the next character in the array
1859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        index = nextIndex;
1869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
18794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
1889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
190ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (cachedGlyph->mIsValid) {
191ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk            switch (mode) {
19210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case FRAMEBUFFER:
19310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
19410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
19510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case BITMAP:
19610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
19710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
19810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case MEASURE:
19910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
20010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
20110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            }
2029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        penX += (cachedGlyph->mAdvance.x >> 6);
2059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
207ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (numGlyphs > 0) {
2089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            glyphsLeft --;
2099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
21394bbccc36322168a596369c8341dad938c8f949fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
21494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
21594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
216ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (cachedGlyph == NULL) {
21794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
21894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
21994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Is the glyph still in texture cache?
220ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!cachedGlyph->mIsValid) {
22194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        updateGlyphCache(cachedGlyph);
22294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
22394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
22494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return cachedGlyph;
22594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
22694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
227ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph) {
228071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
229ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (error) {
230071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        LOGE("Couldn't load glyph.");
231071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        return;
232071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
2339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
234071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mAdvance = mFace->glyph->advance;
235071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
236071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
2379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
238071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
2399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
2419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
2429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
2439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
2459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
246071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
2479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
248ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!glyph->mIsValid) {
2499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
2509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
252071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
253071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
2549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinX = startX;
2569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinY = startY;
257071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
258071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
2599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
2619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
2629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
2649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
2659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
2669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
2679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
269ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
2709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
2719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
2729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
2749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mIsValid = false;
2759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    updateGlyphCache(newGlyph);
2779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return newGlyph;
2799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
281ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi) {
28227f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    rsc->mStateFont.checkInit();
2839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
2849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
285ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < activeFonts.size(); i ++) {
2869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        Font *ithFont = activeFonts[i];
287ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
2889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return ithFont;
2899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *newFont = new Font(rsc);
2939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi);
294ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (isInitialized) {
2959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        activeFonts.push(newFont);
29694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
2979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return newFont;
2989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
300b38d534873ca514f5a5230596c838aa37eca1568Jason Sams    ObjectBase::checkDelete(newFont);
3019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return NULL;
3029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
304ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFont::~Font() {
305ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mFace) {
3069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        FT_Done_Face(mFace);
3079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
3109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
3119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            mRSC->mStateFont.mActiveFonts.removeAt(ct);
3129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
3139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
316ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
3179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
3189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete glyph;
3199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
322ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFontState::FontState() {
3239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
3249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
3259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex = 0;
3269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC = NULL;
327b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mLibrary = NULL;
3283bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3293bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the renderer properties
3303bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
3313bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3323bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the gamma
3333bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    float gamma = DEFAULT_TEXT_GAMMA;
3343bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
3353bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Setting text gamma to %s", property);
3363bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        gamma = atof(property);
3373bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else {
3383bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
3393bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3403bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3413bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the black gamma threshold
34210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
3433bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
3443bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Setting text black gamma threshold to %s", property);
3453bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        blackThreshold = atoi(property);
3463bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else {
3473bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Using default text black gamma threshold of %d",
3483bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk                DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
3493bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3503bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mBlackThreshold = (float)(blackThreshold) / 255.0f;
3513bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3523bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the white gamma threshold
35310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
3543bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
3553bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Setting text white gamma threshold to %s", property);
3563bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        whiteThreshold = atoi(property);
3573bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else {
3583bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        LOGD("  Using default white black gamma threshold of %d",
3593bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk                DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
3603bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3613bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
3623bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3633bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Compute the gamma tables
3643bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mBlackGamma = gamma;
3653bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
366960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk
367960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
3689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
370ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFontState::~FontState() {
371ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
3729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete mCacheLines[i];
3739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
3769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
378ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFT_Library FontState::getLib() {
379ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!mLibrary) {
380071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
381ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (error) {
3829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Unable to initialize freetype");
383071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            return NULL;
3849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
386b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
387071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return mLibrary;
388071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk}
3899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
390ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::init(Context *rsc) {
391071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mRSC = rsc;
3929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
394ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::flushAllAndInvalidate() {
395ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mCurrentQuadIndex != 0) {
3969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
3979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
3989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
399ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
4009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
4019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
402ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
4049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
407ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
4089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the glyph is too tall, don't cache it
409ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
4109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
4119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
4129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
4159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
4169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
4179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool bitmapFit = false;
419ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
421ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (bitmapFit) {
4229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
4239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
427ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!bitmapFit) {
4289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        flushAllAndInvalidate();
4299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Try to fit it again
431ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
433ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk            if (bitmapFit) {
4349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                break;
4359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            }
4369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
439ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (!bitmapFit) {
4409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
4419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return false;
4429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginX = startX;
4469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginY = startY;
4479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
4499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
4509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
4529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
45310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
45410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
4559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
457ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
458ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
45910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
4609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
4619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // This will dirty the texture and the shader so next time
4659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // we draw it will upload the data
4669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
467b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
4689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Some debug code
470ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
4729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
4739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
4749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }*/
4769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
4789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
480ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::initRenderState() {
481d2091639be426574c04f74969fe553162d7a51c9Alex Sakhartchouk    String8 shaderString("varying vec2 varTex0;\n");
482c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("void main() {\n");
483c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
484c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
4853bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
486c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
487c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("}\n");
488c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
489c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
4903bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
491c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
492c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
4933bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
494c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
495c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
49631a7e42f4baa059352f0db119de38428e655eab2Jason Sams    Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
497c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
498c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    uint32_t tmp[4];
499c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
500c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[1] = (uint32_t)inputType;
501c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
502c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[3] = 1;
503c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
504c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    mFontShaderFConstant.set(new Allocation(mRSC, inputType));
505c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
506c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk                                              shaderString.length(), tmp, 4);
5079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontShaderF.set(pf);
508b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
5099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
5119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                                      RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
5129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSampler.set(sampler);
513b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, sampler);
5149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ProgramStore *fontStore = new ProgramStore(mRSC);
5169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore.set(fontStore);
5179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
5189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
5199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDitherEnable(false);
5209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontProgramStore->setDepthMask(false);
5219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
523ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::initTextTexture() {
5249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
5259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
52731a7e42f4baa059352f0db119de38428e655eab2Jason Sams    Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
5289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *cacheAlloc = new Allocation(mRSC, texType);
5309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
5319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture->deferedUploadToTexture(mRSC, false, 0);
5329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
53410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nextLine = 0;
5359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
5369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
5389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
53994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
54094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
5429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
5449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
5469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
5489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
551ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::initVertexArrayBuffers() {
5529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now lets write index data
5539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
5549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
55531a7e42f4baa059352f0db119de38428e655eab2Jason Sams    Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
5569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *indexAlloc = new Allocation(mRSC, indexType);
5589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
5599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
561ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
56210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        int32_t i6 = i * 6;
56310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        int32_t i4 = i * 4;
5649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
5669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
5679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
5689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
5709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
5719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
5729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
5739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    indexAlloc->deferedUploadToBufferObject(mRSC);
5759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer.set(indexAlloc);
5769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
5789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
5799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
58098bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    mRSC->mStateElement.elementBuilderBegin();
58198bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
58298bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
58398bfe5d02a81c15fff52570178a2edd830701665Alex Sakhartchouk    const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
5849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
58531a7e42f4baa059352f0db119de38428e655eab2Jason Sams    Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
58631a7e42f4baa059352f0db119de38428e655eab2Jason Sams                                         mMaxNumberOfQuads * 4,
58731a7e42f4baa059352f0db119de38428e655eab2Jason Sams                                         0, 0, false, false);
5889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
5909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
5919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mVertexArray.set(vertexAlloc);
5939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
596ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::checkInit() {
597ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mInitialized) {
5989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
5999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initTextTexture();
6029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initRenderState();
6039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initVertexArrayBuffers();
6059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
60627f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
60727f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
60827f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
60927f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
61027f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("0123456789");
61127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk
6129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
6139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::issueDrawCommand() {
6169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
6189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setVertex(mRSC->getDefaultProgramVertex());
6199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
62080a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
62180a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    mRSC->setRaster(mRSC->getDefaultProgramRaster());
62280a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk
6239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
6249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragment(mFontShaderF.get());
6259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
6279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragmentStore(mFontProgramStore.get());
6289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
629ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mConstantsDirty) {
6303bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
6313bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstantsDirty = false;
63255e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    }
63355e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
6349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if (!mRSC->setupCheck()) {
6359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setVertex((ProgramVertex *)tmpV.get());
63680a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk        mRSC->setRaster((ProgramRaster *)tmpR.get());
6379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setFragment((ProgramFragment *)tmpF.get());
6389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
6399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *vtx = (float*)mVertexArray->getPtr();
6439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *tex = vtx + 3;
6449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6459d71e2180062931416092f26276a07e55b318f62Alex Sakhartchouk    VertexArray::Attrib attribs[2];
6469d71e2180062931416092f26276a07e55b318f62Alex Sakhartchouk    attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
6479d71e2180062931416092f26276a07e55b318f62Alex Sakhartchouk    attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
6489d71e2180062931416092f26276a07e55b318f62Alex Sakhartchouk    VertexArray va(attribs, 2);
6499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
6509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mIndexBuffer->uploadCheck(mRSC);
6529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
6539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
6549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Reset the state
6569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setVertex((ProgramVertex *)tmpV.get());
65780a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41aeAlex Sakhartchouk    mRSC->setRaster((ProgramRaster *)tmpR.get());
6589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragment((ProgramFragment *)tmpF.get());
6599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
6609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
663ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u1, float v1,
664ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float x2, float y2, float z2,
665ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u2, float v2,
666ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float x3, float y3, float z3,
667ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u3, float v3,
668ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float x4, float y4, float z4,
669ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u4, float v4) {
6709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
6719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
6729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
6739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Cull things that are off the screen
6759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float width = (float)mRSC->getWidth();
6769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float height = (float)mRSC->getHeight();
6779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
678ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
6799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
6839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
6849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
6859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
6869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x1;
6889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y1;
6899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z1;
6909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u1;
6919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v1;
6929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x2;
6949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y2;
6959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z2;
6969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u2;
6979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v2;
6989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x3;
7009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y3;
7019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z3;
7029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u3;
7039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v3;
7049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x4;
7069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y4;
7079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z4;
7089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u4;
7099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v4;
7109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex ++;
7129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
713ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
7149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
7159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
7169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
71994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
72094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = 0;
72127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    uint32_t totalPixels = 0;
722ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
72394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
72494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
72594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
72694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
72794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return remainingCapacity;
72894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
72994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
73094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
73194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Remaining capacity is measured in %
73294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
73394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t precacheIdx = 0;
734ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
73594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
73694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
73794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        precacheIdx ++;
73894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
73994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
74094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
74194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
74210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
74310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
74410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           Font::RenderMode mode,
74510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           Font::Rect *bounds,
746ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
7479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    checkInit();
7489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Render code here
7509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
751ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!currentFont) {
752ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (!mDefault.get()) {
753071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
754071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        }
755071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        currentFont = mDefault.get();
756071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
757ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!currentFont) {
758b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        LOGE("Unable to initialize any fonts");
759b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        return;
760b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
761b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
76210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
76310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
7649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
765ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mCurrentQuadIndex != 0) {
7669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
7679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
7689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
77110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
77210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
7739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
775fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
7763bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[0] = r;
7773bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[1] = g;
7783bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[2] = b;
7793bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[3] = a;
7803bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
7813bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mGamma = 1.0f;
78276322af2a6c109a79431f019dcef6e038c030686Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
7833bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (luminance <= mBlackThreshold) {
7843bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstants.mGamma = mBlackGamma;
7853bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
7863bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
7873bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
788960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk
7893bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstantsDirty = true;
790fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk}
791fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk
79255e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
7933bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *r = mConstants.mFontColor[0];
7943bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *g = mConstants.mFontColor[1];
7953bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *b = mConstants.mFontColor[2];
7963bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *a = mConstants.mFontColor[3];
79755e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk}
79855e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
799ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::deinit(Context *rsc) {
800071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mInitialized = false;
801071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
80201f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines    mFontShaderFConstant.clear();
80301f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines
804071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mIndexBuffer.clear();
805071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mVertexArray.clear();
806071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
807071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontShaderF.clear();
808071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontSampler.clear();
809071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontProgramStore.clear();
810071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
811071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mTextTexture.clear();
812ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
813071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        delete mCacheLines[i];
8149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
815071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mCacheLines.clear();
8169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDefault.clear();
818071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
819b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    Vector<Font*> fontsToDereference = mActiveFonts;
820ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < fontsToDereference.size(); i ++) {
821b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        fontsToDereference[i]->zeroUserRef();
822b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
823b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
824ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mLibrary) {
825071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Done_FreeType( mLibrary );
826b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        mLibrary = NULL;
827071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
8289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace android {
8319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace renderscript {
8329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
833ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) {
834071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
835ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (newFont) {
836071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        newFont->incUserRef();
837071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
838071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return newFont;
8399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // renderscript
8429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // android
843