1d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
2d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk/*
3d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Copyright (C) 2009 The Android Open Source Project
4d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
5d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Licensed under the Apache License, Version 2.0 (the "License");
6d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * you may not use this file except in compliance with the License.
7d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * You may obtain a copy of the License at
8d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
9d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *      http://www.apache.org/licenses/LICENSE-2.0
10d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk *
11d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * Unless required by applicable law or agreed to in writing, software
12d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * distributed under the License is distributed on an "AS IS" BASIS,
13d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * See the License for the specific language governing permissions and
15d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk * limitations under the License.
16d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk */
17d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
18d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsContext.h"
19e23d239828a229eb7d4d33c9630070f0a87833e1Alex Sakhartchouk#include "rs.h"
20d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsFont.h"
21d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include "rsProgramFragment.h"
224edf030cbb7c6ac08dc563335c2af73c20f6e2e5Alex Sakhartchouk#include "rsMesh.h"
2302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
24b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
2502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk#include <ft2build.h>
2602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk#include FT_FREETYPE_H
27d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk#include FT_BITMAP_H
28b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
292a1576ff5147497b18f9f62b97a6c4fa40035e93Michael Butler#include <string.h>
30d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
3111496ac131bb691edf5bdcab3029dceef5c1e4e1Chih-Hung Hsiehnamespace android {
3211496ac131bb691edf5bdcab3029dceef5c1e4e1Chih-Hung Hsiehnamespace renderscript {
33d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
34b8353c5943f4038fd7f08db3d958390ce9418798Yang NiFont::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
35d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
36d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = false;
3744bef6fba6244292b751387f3d6c31cca96c28adChris Wailes    mFace = nullptr;
38d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
39d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
405224a27798f89093b13722b41143551a057ce550Alex Sakhartchoukbool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
41b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
42afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
43af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Reinitialization of fonts not supported");
44d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
45d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
46d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
475224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    FT_Error error = 0;
4844bef6fba6244292b751387f3d6c31cca96c28adChris Wailes    if (data != nullptr && dataLen > 0) {
495224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
505224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    } else {
515224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
525224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    }
535224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk
54afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
55af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to initialize font %s", name);
56d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
57d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
58d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
5948ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams    mFontName = rsuCopyString(name);
60d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontSize = fontSize;
61d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDpi = dpi;
62d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
63c17ace2391783dcabc6c1482edf0362654fd83e5Alex Sakhartchouk    error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
64afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
65af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to set font size on %s", name);
66d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
67d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
68d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
69d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mHasKerning = FT_HAS_KERNING(mFace);
70d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
71d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
72b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
73d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
74d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
75d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
762e8665de7c0eb4514c67baf8693d61c892e5303dJason Samsvoid Font::preDestroy() const {
7782e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    auto& activeFonts = mRSC->mStateFont.mActiveFonts;
7882e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    for (uint32_t ct = 0; ct < activeFonts.size(); ct++) {
7982e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang        if (activeFonts[ct] == this) {
8082e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang            activeFonts.erase(activeFonts.begin() + ct);
81b8353c5943f4038fd7f08db3d958390ce9418798Yang Ni            break;
822e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams        }
832e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams    }
842e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams}
852e8665de7c0eb4514c67baf8693d61c892e5303dJason Sams
86afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::invalidateTextureCache() {
87afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
88b8353c5943f4038fd7f08db3d958390ce9418798Yang Ni        mCachedGlyphs.valueAt(i)->mIsValid = false;
89d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
90d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
91d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
92afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
93d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
94d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
9509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
9609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
97d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
9809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float u1 = glyph->mBitmapMinU;
9909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float u2 = glyph->mBitmapMaxU;
10009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float v1 = glyph->mBitmapMinV;
10109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    float v2 = glyph->mBitmapMaxV;
102d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
10309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
10409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
105d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
10609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
10709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX + width, nPenY, 0, u2, v2,
10809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX + width, nPenY - height, 0, u2, v1,
10909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                          nPenX, nPenY - height, 0, u1, v1);
11009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk}
11109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
11309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
11409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
11509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y + glyph->mBitmapTop;
11609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
11709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
11809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
11909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
12009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
12109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
122a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    const uint8_t* cacheBuffer = state->mCacheBuffer;
12309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
12409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
12509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t bX = 0, bY = 0;
12609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
12709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
12809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
129af12ac6a08651464f8d823add667c706f993b587Steve Block                ALOGE("Skipping invalid index");
13009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                continue;
13109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            }
13209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
13309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
13409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        }
13509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
136d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
137d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
13809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
13909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenX = x + glyph->mBitmapLeft;
14009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
14109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
14209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t width = (int32_t) glyph->mBitmapWidth;
14309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t height = (int32_t) glyph->mBitmapHeight;
14409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
1455224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    // 0, 0 is top left, so bottom is a positive number
1465224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (bounds->bottom < nPenY) {
14709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->bottom = nPenY;
14809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
14909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->left > nPenX) {
15009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->left = nPenX;
15109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
15209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    if (bounds->right < nPenX + width) {
15309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        bounds->right = nPenX + width;
15409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
1555224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (bounds->top > nPenY - height) {
1565224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        bounds->top = nPenY - height;
15709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
15809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk}
15909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
16009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
16109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                     uint32_t start, int32_t numGlyphs,
16209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                     RenderMode mode, Rect *bounds,
163afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
16444bef6fba6244292b751387f3d6c31cca96c28adChris Wailes    if (!mInitialized || numGlyphs == 0 || text == nullptr || len == 0) {
165d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
166d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
167d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
168afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mode == Font::MEASURE) {
16944bef6fba6244292b751387f3d6c31cca96c28adChris Wailes        if (bounds == nullptr) {
170af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("No return rectangle provided to measure text");
17109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            return;
17209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        }
17309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        // Reset min and max of the bounding box to something large
1745224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        bounds->set(1e6, -1e6, 1e6, -1e6);
17509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    }
17609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk
17709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t penX = x, penY = y;
17809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t glyphsLeft = 1;
179afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (numGlyphs > 0) {
180d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        glyphsLeft = numGlyphs;
181d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
182d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
183d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t index = start;
184d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    size_t nextIndex = 0;
185d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
186d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    while (glyphsLeft > 0) {
187d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
188c9c38dd8508a2f805213abee1f9f44f103ac0a0dKenny Root        int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
189d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
190d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Reached the end of the string or encountered
191afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (utfChar < 0) {
192d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
193d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
194d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
195d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Move to the next character in the array
196d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        index = nextIndex;
197d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
19801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
199d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
200d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
201afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (cachedGlyph->mIsValid) {
202afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            switch (mode) {
20309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case FRAMEBUFFER:
20409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
20509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
20609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case BITMAP:
20709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
20809c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
20909c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            case MEASURE:
21009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
21109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                break;
21209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            }
213d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
214d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
21502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        penX += (cachedGlyph->mAdvanceX >> 6);
216d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
217d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // If we were given a specific number of glyphs, decrement
218afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (numGlyphs > 0) {
219d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            glyphsLeft --;
220d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
221d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
222d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
223d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
22401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
22501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
226b8353c5943f4038fd7f08db3d958390ce9418798Yang Ni    CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
22744bef6fba6244292b751387f3d6c31cca96c28adChris Wailes    if (cachedGlyph == nullptr) {
22801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        cachedGlyph = cacheGlyph((uint32_t)utfChar);
22901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
23001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Is the glyph still in texture cache?
231afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!cachedGlyph->mIsValid) {
23201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        updateGlyphCache(cachedGlyph);
23301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
23401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
23501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return cachedGlyph;
23601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
23701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
238afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid Font::updateGlyphCache(CachedGlyphInfo *glyph) {
239b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
240a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
241afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (error) {
242af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Couldn't load glyph.");
243a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        return;
244a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
245d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
24602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    glyph->mAdvanceX = mFace->glyph->advance.x;
24702000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    glyph->mAdvanceY = mFace->glyph->advance.y;
248a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapLeft = mFace->glyph->bitmap_left;
249a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapTop = mFace->glyph->bitmap_top;
250d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
251a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    FT_Bitmap *bitmap = &mFace->glyph->bitmap;
252d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
253d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
254d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
255d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
256d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
257d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Let the font state figure out where to put the bitmap
258d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    FontState *state = &mRSC->mStateFont;
259a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
260d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
261afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!glyph->mIsValid) {
262d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
263d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
264d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
265a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endX = startX + bitmap->width;
266a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
267d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
268d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinX = startX;
269d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinY = startY;
270a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapWidth = bitmap->width;
271a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    glyph->mBitmapHeight = bitmap->rows;
272d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
273d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
274d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
275d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
276d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
277d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
278d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
279d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
280b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
281d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
282d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
283afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
284d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
285b8353c5943f4038fd7f08db3d958390ce9418798Yang Ni    mCachedGlyphs.add(glyph, newGlyph);
286b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
287d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
288d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    newGlyph->mIsValid = false;
289b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
290d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    updateGlyphCache(newGlyph);
291d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
292d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return newGlyph;
293d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
294d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
2955224a27798f89093b13722b41143551a057ce550Alex SakhartchoukFont * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
2965224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk                    const void *data, uint32_t dataLen) {
29735b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    rsc->mStateFont.checkInit();
29882e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    auto& activeFonts = rsc->mStateFont.mActiveFonts;
299d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
300afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < activeFonts.size(); i ++) {
301d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        Font *ithFont = activeFonts[i];
302b8353c5943f4038fd7f08db3d958390ce9418798Yang Ni        if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
303d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return ithFont;
304d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
305d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
306d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
307d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *newFont = new Font(rsc);
3085224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
309afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (isInitialized) {
31082e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang        activeFonts.push_back(newFont);
31101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        rsc->mStateFont.precacheLatin(newFont);
312d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return newFont;
313d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
314d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
315225afd317e101a7be5fe02c0a86361146ea89f05Jason Sams    ObjectBase::checkDelete(newFont);
31644bef6fba6244292b751387f3d6c31cca96c28adChris Wailes    return nullptr;
317d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
318d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
319afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFont::~Font() {
320b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
321afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mFace) {
322d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        FT_Done_Face(mFace);
323d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
324b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif
325d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
326afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
327b8353c5943f4038fd7f08db3d958390ce9418798Yang Ni        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
328d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete glyph;
329d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
330d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
331d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
332afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::FontState() {
333d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = false;
334d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mMaxNumberOfQuads = 1024;
335d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex = 0;
33644bef6fba6244292b751387f3d6c31cca96c28adChris Wailes    mRSC = nullptr;
337b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
33844bef6fba6244292b751387f3d6c31cca96c28adChris Wailes    mLibrary = nullptr;
339b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
340c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
3417e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich    float gamma = DEFAULT_TEXT_GAMMA;
3427e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
3437e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
3447e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich
345e5e18cca3eefccf3a6aabd254ceb2c59f120a7d2Elliott Hughes#ifdef __ANDROID__
346c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the renderer properties
34782e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    char property[PROP_VALUE_MAX];
348c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
349c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the gamma
35044bef6fba6244292b751387f3d6c31cca96c28adChris Wailes    if (property_get(PROPERTY_TEXT_GAMMA, property, nullptr) > 0) {
351c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        gamma = atof(property);
352c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
353c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
354c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the black gamma threshold
35544bef6fba6244292b751387f3d6c31cca96c28adChris Wailes    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) {
356c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        blackThreshold = atoi(property);
357c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
358c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
359c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Get the white gamma threshold
36044bef6fba6244292b751387f3d6c31cca96c28adChris Wailes    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 0) {
361c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        whiteThreshold = atoi(property);
362c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
3637e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich#endif
3647e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich
3657e85ca20affa9655d9033ec2b0fdff034f19a9bfNick Kralevich    mBlackThreshold = (float)(blackThreshold) / 255.0f;
366c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
367c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
368c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    // Compute the gamma tables
369c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mBlackGamma = gamma;
370c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mWhiteGamma = 1.0f / gamma;
3714f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
3724f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk    setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
373d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
374d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
375afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFontState::~FontState() {
376afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
377d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        delete mCacheLines[i];
378d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
379d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
380d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    rsAssert(!mActiveFonts.size());
381d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
382b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
383afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex SakhartchoukFT_Library FontState::getLib() {
384afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!mLibrary) {
385a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Error error = FT_Init_FreeType(&mLibrary);
386afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (error) {
387af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("Unable to initialize freetype");
38844bef6fba6244292b751387f3d6c31cca96c28adChris Wailes            return nullptr;
389d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
390d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
3913659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
392a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return mLibrary;
393a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk}
394b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
395b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk
396d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
397afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::init(Context *rsc) {
398a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mRSC = rsc;
399d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
400d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
401afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::flushAllAndInvalidate() {
402afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
403d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
404d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
405d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
406afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
407d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mActiveFonts[i]->invalidateTextureCache();
408d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
409afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
410d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCacheLines[i]->mCurrentCol = 0;
411d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
412d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
413d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
414b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
415afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukbool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
416d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the glyph is too tall, don't cache it
417afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
418af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
419d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return false;
420d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
421d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
422d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now copy the bitmap into the cache texture
423d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startX = 0;
424d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t startY = 0;
425d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
426d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    bool bitmapFit = false;
427afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
428d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
429afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (bitmapFit) {
430d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            break;
431d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
432d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
433d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
434d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // If the new glyph didn't fit, flush the state so far and invalidate everything
435afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!bitmapFit) {
436d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        flushAllAndInvalidate();
437d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
438d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // Try to fit it again
439afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
440d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
441afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk            if (bitmapFit) {
442d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk                break;
443d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            }
444d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
445d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
446d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        // if we still don't fit, something is wrong and we shouldn't draw
447afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!bitmapFit) {
448af12ac6a08651464f8d823add667c706f993b587Steve Block            ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
449d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            return false;
450d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
451d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
452d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
453d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginX = startX;
454d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    *retOriginY = startY;
455d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
456d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endX = startX + bitmap->width;
457d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t endY = startY + bitmap->rows;
458d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
459d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheWidth = getCacheTextureType()->getDimX();
460d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
461a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    uint8_t *cacheBuffer = mCacheBuffer;
46209c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    uint8_t *bitmapBuffer = bitmap->buffer;
463d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
464d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
465afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
466afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
46709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
468d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
469d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        }
470d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
471d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
472d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // This will dirty the texture and the shader so next time
473d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // we draw it will upload the data
474eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams
475a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
476a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams        RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
477358747a3118301c5faeee73c98dd5f839bbfb54aTim Murray        mCacheBuffer, mCacheWidth*mCacheHeight, mCacheWidth);
478a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams
479383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
480d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
481d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Some debug code
482afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
483af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Cache Line: H: %u Empty Space: %f",
484d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk             mCacheLines[i]->mMaxHeight,
485d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk              (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
486d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
487d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }*/
488d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
489d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    return true;
490d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
491b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
492d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
493afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initRenderState() {
49448ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams    const char *shaderString = "varying vec2 varTex0;\n"
49548ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "void main() {\n"
49648ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "  lowp vec4 col = UNI_Color;\n"
49748ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"
49848ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "  col.a = pow(col.a, UNI_Gamma);\n"
49948ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "  gl_FragColor = col;\n"
50048ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams                               "}\n";
501e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
502748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    const char *textureNames[] = { "Tex0" };
503748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    const size_t textureNamesLengths[] = { 4 };
504748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
505748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk
506748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
507748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_USER, false, 4);
508748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
509748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_USER, false, 1);
510f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams
511f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    const char *ebn1[] = { "Color", "Gamma" };
512f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    const Element *ebe1[] = {colorElem.get(), gammaElem.get()};
513f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    ObjectBaseRef<const Element> constInput = Element::create(mRSC, 2, ebe1, ebn1);
514c7968a0ac24f05d978616a79a5068b6b16dbbda6Jason Sams    ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1);
515e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
516f8852d0494a260c583795a96a2a06c49b86a9b10Ian Rogers    uintptr_t tmp[4];
517e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk    tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
518f8852d0494a260c583795a96a2a06c49b86a9b10Ian Rogers    tmp[1] = (uintptr_t)inputType.get();
51984e4027f83b20af59f5b1fc52be6e45f159d3970Alex Sakhartchouk    tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
52084e4027f83b20af59f5b1fc52be6e45f159d3970Alex Sakhartchouk    tmp[3] = RS_TEXTURE_2D;
521e7ae69f4a70f1813cf8086ebd9714192c635300aAlex Sakhartchouk
522c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
523748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                          RS_ALLOCATION_USAGE_SCRIPT |
524748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                          RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
52548ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
526748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                              textureNames, numTextures, textureNamesLengths,
527748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                              tmp, 4);
528d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mFontShaderF.set(pf);
529383e5b1f68c321a77bfd7466fa1171a9bfab4a6fAlex Sakhartchouk    mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
530d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
531c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
532748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                         RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
533748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                         RS_SAMPLER_CLAMP).get());
534c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
535c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk
536c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
537c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        false, false,
538c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_BLEND_SRC_SRC_ALPHA,
539c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
540c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk                                                        RS_DEPTH_FUNC_ALWAYS).get());
5418feea4e0dec48ea03bd6d32706d058b86dddc5baJason Sams    mFontProgramStore->init();
542d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
543d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
544afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initTextTexture() {
545748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk    ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
546748eb07e805b93c2bf79340d4937963ab739d17cAlex Sakhartchouk                                                                RS_KIND_PIXEL_A, true, 1);
547d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
548d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // We will allocate a texture to initially hold 32 character bitmaps
549a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mCacheHeight = 256;
550a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mCacheWidth = 1024;
551c7968a0ac24f05d978616a79a5068b6b16dbbda6Jason Sams    ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), mCacheWidth, mCacheHeight);
55293d6bc872b7d9fba63abfa7513d56b38d9c3d371Chris Wailes
553a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
554a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams
555d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
556b8353c5943f4038fd7f08db3d958390ce9418798Yang Ni    Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
557b8353c5943f4038fd7f08db3d958390ce9418798Yang Ni                                RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
558d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mTextTexture.set(cacheAlloc);
559d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
560d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Split up our cache texture into lines of certain widths
56109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    int32_t nextLine = 0;
56282e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    mCacheLines.push_back(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
56382e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    nextLine += mCacheLines.back()->mMaxHeight;
56482e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    mCacheLines.push_back(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
56582e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    nextLine += mCacheLines.back()->mMaxHeight;
56682e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    mCacheLines.push_back(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
56782e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    nextLine += mCacheLines.back()->mMaxHeight;
56882e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    mCacheLines.push_back(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
56982e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    nextLine += mCacheLines.back()->mMaxHeight;
57082e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    mCacheLines.push_back(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
57182e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    nextLine += mCacheLines.back()->mMaxHeight;
57282e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    mCacheLines.push_back(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
57382e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    nextLine += mCacheLines.back()->mMaxHeight;
57482e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang    mCacheLines.push_back(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
575d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
576d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
577d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// Avoid having to reallocate memory and render quad by quad
578afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::initVertexArrayBuffers() {
579d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Now lets write index data
580c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
581c7968a0ac24f05d978616a79a5068b6b16dbbda6Jason Sams    ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), mMaxNumberOfQuads * 6);
582d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
583c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
584eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                          RS_ALLOCATION_USAGE_SCRIPT |
585eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                          RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
586a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
587d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
588d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Four verts, two triangles , six indices per quad
589afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
59009c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i6 = i * 6;
59109c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk        int32_t i4 = i * 4;
592d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
593d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 0] = i4 + 0;
594d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 1] = i4 + 1;
595d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 2] = i4 + 2;
596d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
597d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 3] = i4 + 0;
598d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 4] = i4 + 2;
599d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        indexPtr[i6 + 5] = i4 + 3;
600d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
601d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
602eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams    indexAlloc->sendDirty(mRSC);
603d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
604c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
605c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
606d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
607f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    const char *ebn1[] = { "position", "texture0" };
608f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    const Element *ebe1[] = {posElem.get(), texElem.get()};
609f313dc32d5ea68a7c48fb4ec6e131ec2fb97ce2dJason Sams    ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
610d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
611c7968a0ac24f05d978616a79a5068b6b16dbbda6Jason Sams    ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(), mMaxNumberOfQuads * 4);
612d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
613c700e649ca44d0dcff8b271e42d949ea72fe3c63Alex Sakhartchouk    Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
614eb4fe18dd88634330f9566cbb9e785d8c7ec5813Jason Sams                                                           RS_ALLOCATION_USAGE_SCRIPT);
615a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
616d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
617a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh.set(new Mesh(mRSC, 1, 1));
618a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->setVertexBuffer(vertexAlloc, 0);
619a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
620a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->init();
621a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
622a6dd823b9dcbd7ce7dfc34eda52a1e4104771f79Jason Sams    mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
623d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
624d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
625d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk// We don't want to allocate anything unless we actually draw text
626afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::checkInit() {
627afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mInitialized) {
628d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
629d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
630d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
631d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initTextTexture();
632d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initRenderState();
633d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
634d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    initVertexArrayBuffers();
635d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
63635b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
637a7f5e0406825151660c1c2e75c287e2fc8368023Jason Sams    mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
638a7f5e0406825151660c1c2e75c287e2fc8368023Jason Sams                     "EISARNTOLCDUGPMHBYFVKWZXJQ"
639a7f5e0406825151660c1c2e75c287e2fc8368023Jason Sams                     ",.?!()-+@;:`'0123456789";
640d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mInitialized = true;
641d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
642d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
643d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::issueDrawCommand() {
64460709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    Context::PushState ps(mRSC);
645d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
64660709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
64760709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
64860709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramFragment(mFontShaderF.get());
64960709257bbdeb0c50f39b9c8969dc76264d6e142Jason Sams    mRSC->setProgramStore(mFontProgramStore.get());
650d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
651afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mConstantsDirty) {
6524b45b8998e0d7038efaea80c70d23c086640b4e3Jason Sams        mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
653c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstantsDirty = false;
654ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk    }
655ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
656d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    if (!mRSC->setupCheck()) {
657d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
658d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
659d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
660a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
661d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
662d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
663d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchoukvoid FontState::appendMeshQuad(float x1, float y1, float z1,
664afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u1, float v1,
665afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x2, float y2, float z2,
666afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u2, float v2,
667afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x3, float y3, float z3,
668afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u3, float v3,
669afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float x4, float y4, float z4,
670afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                               float u4, float v4) {
671d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    const uint32_t vertsPerQuad = 4;
6722d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    const uint32_t floatsPerVert = 6;
673d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
674d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
675a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
676d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        return;
677d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
678d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
679d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
680af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
681af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
682af12ac6a08651464f8d823add667c706f993b587Steve Block    ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
683d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
684d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x1;
685d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y1;
686d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z1;
6872d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
688d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u1;
689d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v1;
690d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
691d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x2;
692d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y2;
693d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z2;
6942d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
695d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u2;
696d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v2;
697d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
698d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x3;
699d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y3;
700d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z3;
7012d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
702d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u3;
703d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v3;
704d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
705d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = x4;
706d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = y4;
707d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = z4;
7082d1220c27ae91f0b307f283fe66cb767b63dfe38Alex Sakhartchouk    (*currentPos++) = 0;
709d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = u4;
710d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    (*currentPos++) = v4;
711d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
712d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mCurrentQuadIndex ++;
713d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
714afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
715d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
716d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
717d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
718d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
719d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
72001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukuint32_t FontState::getRemainingCacheCapacity() {
72101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = 0;
72235b96445f8bb4536e29ace64417710ed90527a56Alex Sakhartchouk    uint32_t totalPixels = 0;
723afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
72401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
72501bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
72601bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
72701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
72801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    return remainingCapacity;
72901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
73001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
73101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchoukvoid FontState::precacheLatin(Font *font) {
73201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    // Remaining capacity is measured in %
73301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
73401bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    uint32_t precacheIdx = 0;
735a7f5e0406825151660c1c2e75c287e2fc8368023Jason Sams    const size_t l = strlen(mLatinPrecache);
736a7f5e0406825151660c1c2e75c287e2fc8368023Jason Sams    while ((remainingCapacity > 25) && (precacheIdx < l)) {
73701bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
73801bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
73901bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk        precacheIdx ++;
74001bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk    }
74101bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk}
74201bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
74301bcef6115dc6230b16d9d8e120e35279f46cfd5Alex Sakhartchouk
74409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
74509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           uint32_t startIndex, int32_t numGlyphs,
74609c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::RenderMode mode,
74709c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           Font::Rect *bounds,
748afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
749d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    checkInit();
750d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
751d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    // Render code here
752d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    Font *currentFont = mRSC->getFont();
753afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
754afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk        if (!mDefault.get()) {
75548ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams            char fullPath[1024];
75648ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams            const char * root = getenv("ANDROID_ROOT");
75748ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams            rsAssert(strlen(root) < 256);
7582a1576ff5147497b18f9f62b97a6c4fa40035e93Michael Butler            strlcpy(fullPath, root, sizeof(fullPath));
7592a1576ff5147497b18f9f62b97a6c4fa40035e93Michael Butler            strlcat(fullPath, "/fonts/Roboto-Regular.ttf", sizeof(fullPath));
7607305bb3390497843a6a530f68cc07be88adc7c52Michael Butler            fullPath[sizeof(fullPath)-1] = '\0';
76148ecf6a5e85a9a832f41393ed2802385bb8b5db8Jason Sams            mDefault.set(Font::create(mRSC, fullPath, 8, mRSC->getDPI()));
762a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        }
763a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        currentFont = mDefault.get();
764a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
765afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (!currentFont) {
766af12ac6a08651464f8d823add667c706f993b587Steve Block        ALOGE("Unable to initialize any fonts");
7673659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk        return;
7683659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk    }
7693659d94d345c333bf98070dbe7b6daee233225a9Alex Sakhartchouk
770a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    // Cull things that are off the screen
771a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
772a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk    mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
773a74a8f635ce4fae0a9d4b9c79e9fa412787bf6a2Alex Sakhartchouk
77409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
77509c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk                           mode, bounds, bitmap, bitmapW, bitmapH);
776d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
777afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mCurrentQuadIndex != 0) {
778d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        issueDrawCommand();
779d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk        mCurrentQuadIndex = 0;
780d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
781d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
782d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
78309c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchoukvoid FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
78409c67356bbeee0a97a20a06c95b66756838cb541Alex Sakhartchouk    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
7855224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bounds->bottom = - bounds->bottom;
7865224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    bounds->top = - bounds->top;
787d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
788d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
7899fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchoukvoid FontState::setFontColor(float r, float g, float b, float a) {
790c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[0] = r;
791c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[1] = g;
792c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[2] = b;
793c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mFontColor[3] = a;
794c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk
795c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstants.mGamma = 1.0f;
796c8fb69e4a3e01501a3d38a6d3ea185e583d3f493Alex Sakhartchouk    const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
797c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    if (luminance <= mBlackThreshold) {
798c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mBlackGamma;
799c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    } else if (luminance >= mWhiteThreshold) {
800c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk        mConstants.mGamma = mWhiteGamma;
801c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    }
8024f230b31d59b5f17100686bc1416b3b07a4a618dAlex Sakhartchouk
803c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    mConstantsDirty = true;
8049fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk}
8059fc9f0375a92fe22fecb3782b18a5c6060a07290Alex Sakhartchouk
806ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchoukvoid FontState::getFontColor(float *r, float *g, float *b, float *a) const {
807c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *r = mConstants.mFontColor[0];
808c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *g = mConstants.mFontColor[1];
809c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *b = mConstants.mFontColor[2];
810c9fa30536fb41f0166153561388b7c42f7cb85a0Alex Sakhartchouk    *a = mConstants.mFontColor[3];
811ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk}
812ca5a454e022caec6c6d3cbb404cc09ea095ba97aAlex Sakhartchouk
813afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchoukvoid FontState::deinit(Context *rsc) {
814a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mInitialized = false;
815a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
81601b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines    mFontShaderFConstant.clear();
81701b7d2995f9cbd33a9ccdf861fe959743a4b9954Stephen Hines
818a04e30dbb5ab11592b03666bb3d102070759c58eAlex Sakhartchouk    mMesh.clear();
819a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
820a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontShaderF.clear();
821a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontSampler.clear();
822a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mFontProgramStore.clear();
823a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk
824a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mTextTexture.clear();
825afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
826a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        delete mCacheLines[i];
827d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    }
828a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    mCacheLines.clear();
829d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
830d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk    mDefault.clear();
831b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
832afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (mLibrary) {
833a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        FT_Done_FreeType( mLibrary );
83444bef6fba6244292b751387f3d6c31cca96c28adChris Wailes        mLibrary = nullptr;
835a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
836b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
837d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
838d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
839b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#ifndef ANDROID_RS_SERIALIZE
84002000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchoukbool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
84102000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    if ((uint32_t)bitmap->rows > mMaxHeight) {
84202000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        return false;
84302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    }
84402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
84502000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
84602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        *retOriginX = mCurrentCol;
84702000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        *retOriginY = mCurrentRow;
84802000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        mCurrentCol += bitmap->width;
84902000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk        mDirty = true;
85002000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk       return true;
85102000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    }
85202000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
85302000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk    return false;
85402000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk}
855b81a0eb8180791e4eaab1253b59fa8bd562b046bAlex Sakhartchouk#endif //ANDROID_RS_SERIALIZE
85602000b3cdcb2ac369bd06313932b26d4b8e023a9Alex Sakhartchouk
85770b83c111beceaf8fbb700580833e7fec99272cfAlex SakhartchoukRsFont rsi_FontCreateFromFile(Context *rsc,
85870b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                              char const *name, size_t name_length,
85970b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                              float fontSize, uint32_t dpi) {
860a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi);
861afb743aca56c18beb7ab924e75cb6e070ef3e55aAlex Sakhartchouk    if (newFont) {
862a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk        newFont->incUserRef();
863a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    }
864a1ccecd965c07c2739f1258989526051a010bdabAlex Sakhartchouk    return newFont;
865d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk}
866d3e0ad43dc758c409fc23d1893dab67b18520c24Alex Sakhartchouk
86770b83c111beceaf8fbb700580833e7fec99272cfAlex SakhartchoukRsFont rsi_FontCreateFromMemory(Context *rsc,
86870b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                char const *name, size_t name_length,
86970b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                float fontSize, uint32_t dpi,
87070b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk                                const void *data, size_t data_length) {
87170b83c111beceaf8fbb700580833e7fec99272cfAlex Sakhartchouk    Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
8725224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    if (newFont) {
8735224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk        newFont->incUserRef();
8745224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    }
8755224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk    return newFont;
8765224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk}
8775224a27798f89093b13722b41143551a057ce550Alex Sakhartchouk
8787974fc03e11f3a8dd40f794f3b33b4889483090cRahul Chaudhry} // namespace renderscript
8797974fc03e11f3a8dd40f794f3b33b4889483090cRahul Chaudhry} // namespace android
880