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#include "rsContext.h"
199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsFont.h"
219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include "rsProgramFragment.h"
223bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk#include <cutils/properties.h>
23ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk
2417a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
25ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk#include <ft2build.h>
26ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk#include FT_FREETYPE_H
279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk#include FT_BITMAP_H
2817a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukusing namespace android;
319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukusing namespace android::renderscript;
329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
33ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = false;
36b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mFace = NULL;
379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
39b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchoukbool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
4017a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
41ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mInitialized) {
429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Reinitialization of fonts not supported");
439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
46b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    FT_Error error = 0;
47b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    if (data != NULL && dataLen > 0) {
48b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk        error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
49b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    } else {
50b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk        error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
51b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    }
52b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk
53ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (error) {
54e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk        LOGE("Unable to initialize font %s", name);
559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontName = name;
599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontSize = fontSize;
609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDpi = dpi;
619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
62e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
63ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (error) {
64e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk        LOGE("Unable to set font size on %s", name);
659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
7117a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7538f8d9d7a17037a34f4df229b1089536a6cdc8dcJason Samsvoid Font::preDestroy() const {
7638f8d9d7a17037a34f4df229b1089536a6cdc8dcJason Sams    for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
7738f8d9d7a17037a34f4df229b1089536a6cdc8dcJason Sams        if (mRSC->mStateFont.mActiveFonts[ct] == this) {
7838f8d9d7a17037a34f4df229b1089536a6cdc8dcJason Sams            mRSC->mStateFont.mActiveFonts.removeAt(ct);
7938f8d9d7a17037a34f4df229b1089536a6cdc8dcJason Sams            break;
8038f8d9d7a17037a34f4df229b1089536a6cdc8dcJason Sams        }
8138f8d9d7a17037a34f4df229b1089536a6cdc8dcJason Sams    }
8238f8d9d7a17037a34f4df229b1089536a6cdc8dcJason Sams}
8338f8d9d7a17037a34f4df229b1089536a6cdc8dcJason Sams
84ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid Font::invalidateTextureCache() {
85ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCachedGlyphs.valueAt(i)->mIsValid = false;
879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
90ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
9310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
9410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
9610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float u1 = glyph->mBitmapMinU;
9710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float u2 = glyph->mBitmapMaxU;
9810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float v1 = glyph->mBitmapMinV;
9910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    float v2 = glyph->mBitmapMaxV;
1009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
10110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
10210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
1039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
10410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
10510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX + width, nPenY, 0, u2, v2,
10610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX + width, nPenY - height, 0, u2, v1,
10710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                          nPenX, nPenY - height, 0, u1, v1);
10810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk}
10910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
11010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
11110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
11210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
11310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y + glyph->mBitmapTop;
11410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
11510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
11610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
11710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
11810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
11910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
12010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    const uint8_t* cacheBuffer = state->getTextTextureData();
12110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
12210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
12310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t bX = 0, bY = 0;
12410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
12510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
12610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
12710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                LOGE("Skipping invalid index");
12810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                continue;
12910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            }
13010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
13110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
13210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        }
13310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
1349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
1359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
13610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
13710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
13810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
13910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
14010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
14110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
14210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
143b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    // 0, 0 is top left, so bottom is a positive number
144b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    if (bounds->bottom < nPenY) {
14510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->bottom = nPenY;
14610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
14710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->left > nPenX) {
14810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->left = nPenX;
14910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
15010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    if (bounds->right < nPenX + width) {
15110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        bounds->right = nPenX + width;
15210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
153b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    if (bounds->top > nPenY - height) {
154b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk        bounds->top = nPenY - height;
15510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
15610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk}
15710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
15810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
15910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     uint32_t start, int32_t numGlyphs,
16010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                     RenderMode mode, Rect *bounds,
161ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
162ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
1639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
1649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
166ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mode == Font::MEASURE) {
16710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        if (bounds == NULL) {
16810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            LOGE("No return rectangle provided to measure text");
16910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            return;
17010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        }
17110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        // Reset min and max of the bounding box to something large
172b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk        bounds->set(1e6, -1e6, 1e6, -1e6);
17310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    }
17410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk
17510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t penX = x, penY = y;
17610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t glyphsLeft = 1;
177ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (numGlyphs > 0) {
1789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        glyphsLeft = numGlyphs;
1799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
1809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t index = start;
1829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    size_t nextIndex = 0;
1839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    while (glyphsLeft > 0) {
1859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
186300ba6846949f5b21c6d93d7698dbc39716cf832Kenny Root        int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
1879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Reached the end of the string or encountered
189ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (utfChar < 0) {
1909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
1919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
1929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Move to the next character in the array
1949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        index = nextIndex;
1959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
19694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
1979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
1989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
199ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (cachedGlyph->mIsValid) {
200ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk            switch (mode) {
20110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case FRAMEBUFFER:
20210825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
20310825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
20410825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case BITMAP:
20510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
20610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
20710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            case MEASURE:
20810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
20910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                break;
21010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            }
2119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
213ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk        penX += (cachedGlyph->mAdvanceX >> 6);
2149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
216ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (numGlyphs > 0) {
2179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            glyphsLeft --;
2189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
2199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
22294bbccc36322168a596369c8341dad938c8f949fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
22394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
22494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
225ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (cachedGlyph == NULL) {
22694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
22794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
22894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Is the glyph still in texture cache?
229ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!cachedGlyph->mIsValid) {
23094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        updateGlyphCache(cachedGlyph);
23194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
23294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
23394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return cachedGlyph;
23494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
23594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
236ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph) {
23717a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
238071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
239ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (error) {
240071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        LOGE("Couldn't load glyph.");
241071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        return;
242071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
2439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
244ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk    glyph->mAdvanceX = mFace->glyph->advance.x;
245ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk    glyph->mAdvanceY = mFace->glyph->advance.y;
246071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
247071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
2489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
249071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
2509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
2529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
2539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
2549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
2569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
257071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
2589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
259ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!glyph->mIsValid) {
2609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
2619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
2629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
263071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
264071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
2659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinX = startX;
2679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinY = startY;
268071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
269071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
2709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
2729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
2739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
2759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
2769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
2779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
27817a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
2799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
281ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
2829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
2839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCachedGlyphs.add(glyph, newGlyph);
28417a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
2859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
2869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    newGlyph->mIsValid = false;
28717a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
2889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    updateGlyphCache(newGlyph);
2899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
2909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return newGlyph;
2919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
2929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
293b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex SakhartchoukFont * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
294b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk                    const void *data, uint32_t dataLen) {
29527f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    rsc->mStateFont.checkInit();
2969b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
2979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
298ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < activeFonts.size(); i ++) {
2999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        Font *ithFont = activeFonts[i];
300ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
3019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return ithFont;
3029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *newFont = new Font(rsc);
306b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
307ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (isInitialized) {
3089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        activeFonts.push(newFont);
30994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
3109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return newFont;
3119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
313b38d534873ca514f5a5230596c838aa37eca1568Jason Sams    ObjectBase::checkDelete(newFont);
3149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return NULL;
3159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
317ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFont::~Font() {
31817a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
319ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mFace) {
3209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        FT_Done_Face(mFace);
3219b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
32217a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#endif
3239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
324ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
3259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
3269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete glyph;
3279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
330ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFontState::FontState() {
3319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = false;
3329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
3339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex = 0;
3349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mRSC = NULL;
33517a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
336b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    mLibrary = NULL;
33717a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
3383bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3393bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the renderer properties
3403bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    char property[PROPERTY_VALUE_MAX];
3413bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3423bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the gamma
3433bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    float gamma = DEFAULT_TEXT_GAMMA;
3443bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
3453bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        gamma = atof(property);
3463bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3473bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3483bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the black gamma threshold
34910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
3503bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
3513bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        blackThreshold = atoi(property);
3523bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3533bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mBlackThreshold = (float)(blackThreshold) / 255.0f;
3543bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3553bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Get the white gamma threshold
35610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
3573bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
3583bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        whiteThreshold = atoi(property);
3593bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
3603bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
3613bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
3623bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    // Compute the gamma tables
3633bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mBlackGamma = gamma;
3643bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
365960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk
366960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
3679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
369ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFontState::~FontState() {
370ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
3719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        delete mCacheLines[i];
3729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
3739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
3749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
3759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
37617a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
377ed9f210568082dd6d1d8a0c92c693d574d87d545Alex SakhartchoukFT_Library FontState::getLib() {
378ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!mLibrary) {
379071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
380ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (error) {
3819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Unable to initialize freetype");
382071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk            return NULL;
3839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
3849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
385b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
386071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return mLibrary;
387071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk}
38817a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
38917a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk
3909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
391ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::init(Context *rsc) {
392071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mRSC = rsc;
3939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
3949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
395ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::flushAllAndInvalidate() {
396ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mCurrentQuadIndex != 0) {
3979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
3989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
3999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
400ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
4019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
4029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
403ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
4059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4069b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
4079b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
40817a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
409ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
4109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the glyph is too tall, don't cache it
411ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
4129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
4139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return false;
4149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4169b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now copy the bitmap into the cache texture
4179b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startX = 0;
4189b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t startY = 0;
4199b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4209b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    bool bitmapFit = false;
421ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
423ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (bitmapFit) {
4249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            break;
4259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4289b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
429ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!bitmapFit) {
4309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        flushAllAndInvalidate();
4319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // Try to fit it again
433ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
435ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk            if (bitmapFit) {
4369b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk                break;
4379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            }
4389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
441ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (!bitmapFit) {
4429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
4439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            return false;
4449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginX = startX;
4489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    *retOriginY = startY;
4499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
4519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
4529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
4549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
45510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
45610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
4579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
459ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
460ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
46110825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
4629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
4639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        }
4649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
4659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // This will dirty the texture and the shader so next time
4679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // we draw it will upload the data
4687e8aae7f76f221905fba7ccbcb3442c6f96dfad2Jason Sams
4697e8aae7f76f221905fba7ccbcb3442c6f96dfad2Jason Sams    mTextTexture->sendDirty(mRSC);
470b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
4719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Some debug code
473ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
4749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        LOGE("Cache Line: H: %u Empty Space: %f",
4759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
4769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
4779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }*/
4799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
4809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    return true;
4819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
48217a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
4839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
484ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::initRenderState() {
485d2091639be426574c04f74969fe553162d7a51c9Alex Sakhartchouk    String8 shaderString("varying vec2 varTex0;\n");
486c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("void main() {\n");
487c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  lowp vec4 col = UNI_Color;\n");
488c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
4893bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    shaderString.append("  col.a = pow(col.a, UNI_Gamma);\n");
490c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("  gl_FragColor = col;\n");
491c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    shaderString.append("}\n");
492c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
493117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
494117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
495117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    Element::Builder builder;
496117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    builder.add(colorElem.get(), "Color", 1);
497117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    builder.add(gammaElem.get(), "Gamma", 1);
498117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<const Element> constInput = builder.create(mRSC);
499c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
500117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false);
501c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
502c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    uint32_t tmp[4];
503c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
504117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    tmp[1] = (uint32_t)inputType.get();
50567f2e442a31b8395e3c1951f8e91139ec7f2be99Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
50667f2e442a31b8395e3c1951f8e91139ec7f2be99Alex Sakhartchouk    tmp[3] = RS_TEXTURE_2D;
507c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk
508117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
5095476b450e50939940dcf3f15c92335cee2fc572dJason Sams                                            RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
510c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
511c984dd73c6f96d16e11813ae433ef70f7648ae77Alex Sakhartchouk                                              shaderString.length(), tmp, 4);
5129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mFontShaderF.set(pf);
513b89aaacb2ca9d062e0a17a32e3d4dbf3f6948a17Alex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
5149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
515117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
516117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk                                         RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP).get());
517117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
518117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk
519117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
520117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk                                                        false, false,
521117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk                                                        RS_BLEND_SRC_SRC_ALPHA,
522117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk                                                        RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
523117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk                                                        RS_DEPTH_FUNC_ALWAYS).get());
52448f505657adba4d9156856e7d5593f23af5d5d5aJason Sams    mFontProgramStore->init();
5259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5269b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
527ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::initTextTexture() {
528117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
5299b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
531117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), 1024, 256, 0, false, false);
5329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
533117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
5347e8aae7f76f221905fba7ccbcb3442c6f96dfad2Jason Sams                                RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
5359b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
5366d8eb266dd398abf0511685fdaf98abba3396174Jason Sams    mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
5379b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
53910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    int32_t nextLine = 0;
5409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
5419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5429b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
5439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
54494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
54594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5469b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
5479b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5489b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
5499b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5509b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
5519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
5529b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
5539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
5549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
556ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::initVertexArrayBuffers() {
5579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Now lets write index data
558117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
5599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint32_t numIndicies = mMaxNumberOfQuads * 6;
560117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false);
5619b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
562117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
5637e8aae7f76f221905fba7ccbcb3442c6f96dfad2Jason Sams                                                          RS_ALLOCATION_USAGE_SCRIPT |
5647e8aae7f76f221905fba7ccbcb3442c6f96dfad2Jason Sams                                                          RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
5659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
5669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
568ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
56910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        int32_t i6 = i * 6;
57010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk        int32_t i4 = i * 4;
5719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
5739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
5749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
5759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
5779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
5789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
5799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
5809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5817e8aae7f76f221905fba7ccbcb3442c6f96dfad2Jason Sams    indexAlloc->sendDirty(mRSC);
5829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
583117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
584117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
5859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
586117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    Element::Builder builder;
587117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    builder.add(posElem.get(), "position", 1);
588117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    builder.add(texElem.get(), "texture0", 1);
589117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<const Element> vertexDataElem = builder.create(mRSC);
5909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
591117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
592117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk                                                          mMaxNumberOfQuads * 4,
593117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk                                                          0, 0, false, false);
5949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
595117abdbc67123654d0754b686c5bbdee6b44bcddAlex Sakhartchouk    Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
5967e8aae7f76f221905fba7ccbcb3442c6f96dfad2Jason Sams                                                           RS_ALLOCATION_USAGE_SCRIPT);
5979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mTextMeshPtr = (float*)vertexAlloc->getPtr();
5989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
5994a36b45c72b91045db49c54d33fd7a05fc5a7a3dAlex Sakhartchouk    mMesh.set(new Mesh(mRSC, 1, 1));
6004a36b45c72b91045db49c54d33fd7a05fc5a7a3dAlex Sakhartchouk    mMesh->setVertexBuffer(vertexAlloc, 0);
6014a36b45c72b91045db49c54d33fd7a05fc5a7a3dAlex Sakhartchouk    mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
6024a36b45c72b91045db49c54d33fd7a05fc5a7a3dAlex Sakhartchouk    mMesh->init();
6039b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
606ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::checkInit() {
607ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mInitialized) {
6089b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6099b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6109b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6119b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initTextTexture();
6129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initRenderState();
6139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6149b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    initVertexArrayBuffers();
6159b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
61627f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
61727f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
61827f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
61927f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8(",.?!()-+@;:`'");
62027f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    mLatinPrecache += String8("0123456789");
62127f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk
6229b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mInitialized = true;
6239b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6249b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6259b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::issueDrawCommand() {
626a17af04e62a3f40f729e7ebb8bd868d192e18405Jason Sams    Context::PushState ps(mRSC);
6279b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
628a17af04e62a3f40f729e7ebb8bd868d192e18405Jason Sams    mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
629a17af04e62a3f40f729e7ebb8bd868d192e18405Jason Sams    mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
630a17af04e62a3f40f729e7ebb8bd868d192e18405Jason Sams    mRSC->setProgramFragment(mFontShaderF.get());
631a17af04e62a3f40f729e7ebb8bd868d192e18405Jason Sams    mRSC->setProgramStore(mFontProgramStore.get());
6329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
633ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mConstantsDirty) {
63449a05d7b82956009f03acbb92a064eed054eb031Jason Sams        mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
6353bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstantsDirty = false;
63655e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk    }
63755e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
6389b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    if (!mRSC->setupCheck()) {
6399b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6409b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6419b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6424a36b45c72b91045db49c54d33fd7a05fc5a7a3dAlex Sakhartchouk    mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
6439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
6449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6459b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
646ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u1, float v1,
647ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float x2, float y2, float z2,
648ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u2, float v2,
649ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float x3, float y3, float z3,
650ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u3, float v3,
651ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float x4, float y4, float z4,
652ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                               float u4, float v4) {
6539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
6549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    const uint32_t floatsPerVert = 5;
6559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
6569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Cull things that are off the screen
6589b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float width = (float)mRSC->getWidth();
6599b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    float height = (float)mRSC->getHeight();
6609b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
661ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
6629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        return;
6639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
6649b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6659b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
6669b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
6679b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
6689b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
6699b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6709b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x1;
6719b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y1;
6729b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z1;
6739b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u1;
6749b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v1;
6759b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6769b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x2;
6779b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y2;
6789b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z2;
6799b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u2;
6809b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v2;
6819b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6829b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x3;
6839b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y3;
6849b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z3;
6859b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u3;
6869b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v3;
6879b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6889b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = x4;
6899b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = y4;
6909b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = z4;
6919b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = u4;
6929b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    (*currentPos++) = v4;
6939b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
6949b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mCurrentQuadIndex ++;
6959b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
696ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
6979b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
6989b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
6999b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7009b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7019b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
70294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
70394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = 0;
70427f50523a45100f3b4861762b6263e0b9ba6e22eAlex Sakhartchouk    uint32_t totalPixels = 0;
705ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
70694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
70794bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
70894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
70994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
71094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    return remainingCapacity;
71194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
71294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
71394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
71494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    // Remaining capacity is measured in %
71594bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
71694bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    uint32_t precacheIdx = 0;
717ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
71894bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
71994bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
72094bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk        precacheIdx ++;
72194bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk    }
72294bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk}
72394bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
72494bbccc36322168a596369c8341dad938c8f949fAlex Sakhartchouk
72510825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
72610825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
72710825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           Font::RenderMode mode,
72810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           Font::Rect *bounds,
729ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
7309b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    checkInit();
7319b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
7329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    // Render code here
7339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
734ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!currentFont) {
735ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk        if (!mDefault.get()) {
736beb2b5cfdb79ac9147296e3a6bd21970a947a6f4Christian Robertson            String8 fontsDir("/fonts/Roboto-Regular.ttf");
737e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk            String8 fullPath(getenv("ANDROID_ROOT"));
738e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk            fullPath += fontsDir;
739e27cdeeecba5b445e307d653d9cb7da007adfac3Alex Sakhartchouk
7402c74ad9aae29cc64fece926f353825a7925792c2Alex Sakhartchouk            mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
741071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        }
742071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        currentFont = mDefault.get();
743071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
744ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (!currentFont) {
745b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        LOGE("Unable to initialize any fonts");
746b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        return;
747b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk    }
748b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk
74910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
75010825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
7519b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
752ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mCurrentQuadIndex != 0) {
7539b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        issueDrawCommand();
7549b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk        mCurrentQuadIndex = 0;
7559b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
7569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
75810825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
75910825a07ae3a7520110a5fb642a6c8745d7b3956Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
760b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    bounds->bottom = - bounds->bottom;
761b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    bounds->top = - bounds->top;
7629b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
7639b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
764fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
7653bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[0] = r;
7663bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[1] = g;
7673bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[2] = b;
7683bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mFontColor[3] = a;
7693bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk
7703bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstants.mGamma = 1.0f;
77176322af2a6c109a79431f019dcef6e038c030686Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
7723bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    if (luminance <= mBlackThreshold) {
7733bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstants.mGamma = mBlackGamma;
7743bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
7753bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
7763bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    }
777960ae15cf37fe31790e255521ee2045312e82d36Alex Sakhartchouk
7783bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    mConstantsDirty = true;
779fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk}
780fb10c16a0528a418053e4b8e75eebe57476b86efAlex Sakhartchouk
78155e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
7823bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *r = mConstants.mFontColor[0];
7833bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *g = mConstants.mFontColor[1];
7843bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *b = mConstants.mFontColor[2];
7853bf3ea0d839010cc9e0e5a6bd51c325d375f679dAlex Sakhartchouk    *a = mConstants.mFontColor[3];
78655e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk}
78755e81983562ca507883f32f817e9d24e1c49b909Alex Sakhartchouk
788ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchoukvoid FontState::deinit(Context *rsc) {
789071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mInitialized = false;
790071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
79101f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines    mFontShaderFConstant.clear();
79201f0ad7c13b8878c2167bff10ea875d7509edca5Stephen Hines
7934a36b45c72b91045db49c54d33fd7a05fc5a7a3dAlex Sakhartchouk    mMesh.clear();
794071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
795071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontShaderF.clear();
796071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontSampler.clear();
797071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mFontProgramStore.clear();
798071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk
799071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mTextTexture.clear();
800ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
801071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        delete mCacheLines[i];
8029b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    }
803071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    mCacheLines.clear();
8049b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
8059b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk    mDefault.clear();
80617a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
807ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (mLibrary) {
808071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        FT_Done_FreeType( mLibrary );
809b6b34891fa7f76c99f5e9a3096576ada86c99f1eAlex Sakhartchouk        mLibrary = NULL;
810071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
81117a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
8129b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8139b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
81417a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
815ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchoukbool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
816ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk    if ((uint32_t)bitmap->rows > mMaxHeight) {
817ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk        return false;
818ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk    }
819ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk
820ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk    if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
821ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk        *retOriginX = mCurrentCol;
822ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk        *retOriginY = mCurrentRow;
823ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk        mCurrentCol += bitmap->width;
824ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk        mDirty = true;
825ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk       return true;
826ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk    }
827ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk
828ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk    return false;
829ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk}
83017a8a1939d4cbc74de54954c67f3dd61882420aaAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
831ebd65bbb848b2f3ee8dc55e485d201c681361d15Alex Sakhartchouk
8329b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace android {
8339b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouknamespace renderscript {
8349b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
835e7c4a7565c7f8c8fc1ec92dc0692577fcc474750Alex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc,
836e7c4a7565c7f8c8fc1ec92dc0692577fcc474750Alex Sakhartchouk                              char const *name, size_t name_length,
837e7c4a7565c7f8c8fc1ec92dc0692577fcc474750Alex Sakhartchouk                              float fontSize, uint32_t dpi) {
838071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
839ed9f210568082dd6d1d8a0c92c693d574d87d545Alex Sakhartchouk    if (newFont) {
840071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk        newFont->incUserRef();
841071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    }
842071508d9f3d1c004cd9ef8d5329949e7a8a949c8Alex Sakhartchouk    return newFont;
8439b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk}
8449b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk
845e7c4a7565c7f8c8fc1ec92dc0692577fcc474750Alex SakhartchoukRsFont rsi_FontCreateFromMemory(Context *rsc,
846e7c4a7565c7f8c8fc1ec92dc0692577fcc474750Alex Sakhartchouk                                char const *name, size_t name_length,
847e7c4a7565c7f8c8fc1ec92dc0692577fcc474750Alex Sakhartchouk                                float fontSize, uint32_t dpi,
848e7c4a7565c7f8c8fc1ec92dc0692577fcc474750Alex Sakhartchouk                                const void *data, size_t data_length) {
849e7c4a7565c7f8c8fc1ec92dc0692577fcc474750Alex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
850b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    if (newFont) {
851b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk        newFont->incUserRef();
852b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    }
853b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk    return newFont;
854b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk}
855b0253ea6969bdd27bf574e0da7fa91aa6d09f44fAlex Sakhartchouk
8569b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // renderscript
8579b949fce39f0f39ce9275b71d7c347210775e7a8Alex Sakhartchouk} // android
858