FontRenderer.cpp revision f18136cb3c881a9d16c1a4f0f341732c276936bf
1694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/*
2694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Copyright (C) 2010 The Android Open Source Project
3694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *
4694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * you may not use this file except in compliance with the License.
6694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * You may obtain a copy of the License at
7694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *
8694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *
10694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Unless required by applicable law or agreed to in writing, software
11694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * See the License for the specific language governing permissions and
14694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * limitations under the License.
15694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy */
16694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
17694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#define LOG_TAG "OpenGLRenderer"
18694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
19694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#include <SkUtils.h>
20694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
2151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include <cutils/properties.h>
2251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include <utils/Log.h>
2351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
2451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include "FontRenderer.h"
2551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
26694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace android {
27694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace uirenderer {
28694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
29694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
3051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy// Defines
3151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy///////////////////////////////////////////////////////////////////////////////
3251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
3351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_WIDTH 1024
3451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_HEIGHT 256
3551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
3651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy///////////////////////////////////////////////////////////////////////////////
37694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Font
38694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
39694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
40694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize) :
41694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mState(state), mFontId(fontId), mFontSize(fontSize) {
42694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
43694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
44694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
45694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::~Font() {
46694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) {
47694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (mState->mActiveFonts[ct] == this) {
48694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            mState->mActiveFonts.removeAt(ct);
49694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
50694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
51694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
52694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
53694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
5451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        CachedGlyphInfo* glyph = mCachedGlyphs.valueAt(i);
55694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete glyph;
56694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
57694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
58694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
59694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::invalidateTextureCache() {
60694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
61694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCachedGlyphs.valueAt(i)->mIsValid = false;
62694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
63694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
64694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
65f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds) {
66f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int nPenX = x + glyph->mBitmapLeft;
67f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int nPenY = y + glyph->mBitmapTop;
68f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
69f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int width = (int) glyph->mBitmapWidth;
70f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int height = (int) glyph->mBitmapHeight;
71f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
72f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    if(bounds->bottom > nPenY) {
73f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->bottom = nPenY;
74f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
75f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    if(bounds->left > nPenX) {
76f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->left = nPenX;
77f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
78f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    if(bounds->right < nPenX + width) {
79f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->right = nPenX + width;
80f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
81f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    if(bounds->top < nPenY + height) {
82f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->top = nPenY + height;
83f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
84f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
85f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
86694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) {
87694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nPenX = x + glyph->mBitmapLeft;
88694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
89694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
9051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float u1 = glyph->mBitmapMinU;
9151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float u2 = glyph->mBitmapMaxU;
9251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float v1 = glyph->mBitmapMinV;
9351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float v2 = glyph->mBitmapMaxV;
9451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
9551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    int width = (int) glyph->mBitmapWidth;
9651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    int height = (int) glyph->mBitmapHeight;
9751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
9851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mState->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
9951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy            nPenX + width, nPenY, 0, u2, v2,
10051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy            nPenX + width, nPenY - height, 0, u2, v1,
10151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy            nPenX, nPenY - height, 0, u1, v1);
102694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
103694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
10489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
10589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                             uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
10689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    int nPenX = x + glyph->mBitmapLeft;
10789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    int nPenY = y + glyph->mBitmapTop;
10889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
10989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
11089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
11189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
11289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint32_t cacheWidth = mState->getCacheWidth();
11389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    const uint8_t* cacheBuffer = mState->getTextTextureData();
11489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
115f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
116f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int32_t bX = 0, bY = 0;
11789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
11889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
119f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            if(bX < 0 || bY < 0 || bX >= (int32_t)bitmapW || bY >= (int32_t)bitmapH) {
120f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                LOGE("Skipping invalid index");
121f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                continue;
122f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            }
12389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
12489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
12589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
12689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
12789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
12889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
12989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
13065ef909776c03417d8b597738da54ca211e37e4fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) {
13165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueFor(utfChar);
13265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    if (cachedGlyph == NULL) {
13365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        cachedGlyph = cacheGlyph(paint, utfChar);
13465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
13565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
13665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    // Is the glyph still in texture cache?
13765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    if (!cachedGlyph->mIsValid) {
13865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar);
13965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        updateGlyphCache(paint, skiaGlyph, cachedGlyph);
14065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
14165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
14265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    return cachedGlyph;
14365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk}
14465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
14551769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
146f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                       int numGlyphs, int x, int y,
147f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                       uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
148f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    if(bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
149f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        renderUTF(paint, text, start, len, numGlyphs, x, y, BITMAP,
150f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                   bitmap, bitmapW, bitmapH, NULL);
151f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
152f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    else {
153f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        renderUTF(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER,
154f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                   NULL, 0, 0, NULL);
155f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
156f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
157f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
158f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
159f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
160f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                       int numGlyphs, Rect *bounds) {
161f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    if(bounds == NULL) {
162f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        LOGE("No return rectangle provided to measure text");
163f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        return;
164f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
165f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    bounds->set(1e6, -1e6, -1e6, 1e6);
166f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    renderUTF(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds);
167f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
168f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
169f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
170f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                       int numGlyphs, int x, int y, RenderMode mode,
171f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                       uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
172f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                       Rect *bounds) {
173694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (numGlyphs == 0 || text == NULL || len == 0) {
174694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
175694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
176694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
177694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int penX = x, penY = y;
178694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int glyphsLeft = 1;
179694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (numGlyphs > 0) {
180694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        glyphsLeft = numGlyphs;
181694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
182694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
183694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    text += start;
184694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
185694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    while (glyphsLeft > 0) {
186694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int32_t utfChar = SkUTF16_NextUnichar((const uint16_t**) &text);
187694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
188694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // Reached the end of the string or encountered
189694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (utfChar < 0) {
190694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
191694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
192694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
19365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        CachedGlyphInfo* cachedGlyph = getCachedUTFChar(paint, utfChar);
194694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
195694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
196694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (cachedGlyph->mIsValid) {
197f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            switch(mode) {
198f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            case FRAMEBUFFER:
19989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY);
200f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                break;
201f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            case BITMAP:
202f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
203f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                break;
204f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            case MEASURE:
205f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
206f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                break;
20789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
208694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
209694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
21009147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy        penX += SkFixedFloor(cachedGlyph->mAdvanceX);
211694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
212694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // If we were given a specific number of glyphs, decrement
213694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (numGlyphs > 0) {
214694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            glyphsLeft--;
215694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
216694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
217694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
218694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
21951769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) {
220694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mAdvanceX = skiaGlyph.fAdvanceX;
221694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mAdvanceY = skiaGlyph.fAdvanceY;
222694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapLeft = skiaGlyph.fLeft;
223694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapTop = skiaGlyph.fTop;
224694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
225694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
227694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
228694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Get the bitmap for the glyph
229694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    paint->findImage(skiaGlyph);
23051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY);
231694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
232694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!glyph->mIsValid) {
233694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
234694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
235694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
236694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + skiaGlyph.fWidth;
237694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + skiaGlyph.fHeight;
238694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
23989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    glyph->mStartX = startX;
24089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    glyph->mStartY = startY;
241694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapWidth = skiaGlyph.fWidth;
242694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapHeight = skiaGlyph.fHeight;
243694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
24451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    uint32_t cacheWidth = mState->getCacheWidth();
24551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    uint32_t cacheHeight = mState->getCacheHeight();
246694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
247694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMinU = (float) startX / (float) cacheWidth;
248694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMinV = (float) startY / (float) cacheHeight;
249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMaxU = (float) endX / (float) cacheWidth;
250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMaxV = (float) endY / (float) cacheHeight;
251694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
25251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mState->mUploadTexture = true;
253694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
254694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
25551769a68a5cb34e9564740c6a854fcb93018789dRomain GuyFont::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, int32_t glyph) {
25651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
257694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCachedGlyphs.add(glyph, newGlyph);
258694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
259694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    const SkGlyph& skiaGlyph = paint->getUnicharMetrics(glyph);
260694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    newGlyph->mGlyphIndex = skiaGlyph.fID;
261694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    newGlyph->mIsValid = false;
262694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
263694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    updateGlyphCache(paint, skiaGlyph, newGlyph);
264694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
265694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return newGlyph;
266694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
267694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
268694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize) {
269694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Vector<Font*> &activeFonts = state->mActiveFonts;
270694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
271694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < activeFonts.size(); i++) {
27251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        Font* font = activeFonts[i];
27351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        if (font->mFontId == fontId && font->mFontSize == fontSize) {
27451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy            return font;
275694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
276694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
277694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
278694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Font* newFont = new Font(state, fontId, fontSize);
279694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    activeFonts.push(newFont);
280694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return newFont;
281694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
282694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
283694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
284694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer
285694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
286694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
287694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() {
28851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    LOGD("Creating FontRenderer");
28951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
290694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = false;
291694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mMaxNumberOfQuads = 1024;
292694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentQuadIndex = 0;
2939b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mTextureId = 0;
294694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
295694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mIndexBufferID = 0;
296694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
29751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
2989b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT;
29951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
30051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    char property[PROPERTY_VALUE_MAX];
30151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) {
30251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        LOGD("  Setting text cache width to %s pixels", property);
30351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        mCacheWidth = atoi(property);
30451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    } else {
30551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        LOGD("  Using default text cache width of %i pixels", mCacheWidth);
30651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    }
30751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
30851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) {
30951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        LOGD("  Setting text cache width to %s pixels", property);
31051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        mCacheHeight = atoi(property);
31151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    } else {
31251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        LOGD("  Using default text cache height of %i pixels", mCacheHeight);
31351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    }
314694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
315694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
316694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() {
317694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
318694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete mCacheLines[i];
319694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
320694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.clear();
321694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
32289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    delete[] mTextMeshPtr;
32389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    delete[] mTextTexture;
3249b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
3259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    if(mTextureId) {
3269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        glDeleteTextures(1, &mTextureId);
3279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
328694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
329694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Vector<Font*> fontsToDereference = mActiveFonts;
330694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < fontsToDereference.size(); i++) {
331694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete fontsToDereference[i];
332694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
333694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
334694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
335694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() {
336694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex != 0) {
337694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
338694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
339694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
340694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
341694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mActiveFonts[i]->invalidateTextureCache();
342694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
343694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
344694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCacheLines[i]->mCurrentCol = 0;
345694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
346694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
347694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
34851769a68a5cb34e9564740c6a854fcb93018789dRomain Guybool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
349694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the glyph is too tall, don't cache it
350694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (glyph.fWidth > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
351694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        LOGE("Font size to large to fit in cache. width, height = %i, %i",
352694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                (int) glyph.fWidth, (int) glyph.fHeight);
353694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return false;
354694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
355694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
356694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Now copy the bitmap into the cache texture
357694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
358694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
359694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
360694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    bool bitmapFit = false;
361694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
362694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
363694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (bitmapFit) {
364694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
365694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
366694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
367694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
368694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the new glyph didn't fit, flush the state so far and invalidate everything
369694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!bitmapFit) {
370694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        flushAllAndInvalidate();
371694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
372694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // Try to fit it again
373694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        for (uint32_t i = 0; i < mCacheLines.size(); i++) {
374694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
375694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            if (bitmapFit) {
376694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                break;
377694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            }
378694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
379694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
380694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // if we still don't fit, something is wrong and we shouldn't draw
381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (!bitmapFit) {
382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i",
383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    (int) glyph.fWidth, (int) glyph.fHeight);
384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            return false;
385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
386694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginX = startX;
389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginY = startY;
390694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
391694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + glyph.fWidth;
392694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + glyph.fHeight;
393694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
394694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t cacheWidth = mCacheWidth;
395694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
39689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint8_t* cacheBuffer = mTextTexture;
39789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
398694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    unsigned int stride = glyph.rowBytes();
399694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
400694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
401694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
40389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * stride + bX];
404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol;
405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
407694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
408694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return true;
409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initTextTexture() {
41289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    mTextTexture = new uint8_t[mCacheWidth * mCacheHeight];
413694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mUploadTexture = false;
414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glGenTextures(1, &mTextureId);
416694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBindTexture(GL_TEXTURE_2D, mTextureId);
417694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
4189b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    // Initialize texture dimentions
4199b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0,
4209b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk                  GL_ALPHA, GL_UNSIGNED_BYTE, 0);
421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
423694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
424694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
427694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Split up our cache texture into lines of certain widths
429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nextLine = 0;
43051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mCacheLines.push(new CacheTextureLine(mCacheWidth, 16, nextLine, 0));
431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
43251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mCacheLines.push(new CacheTextureLine(mCacheWidth, 24, nextLine, 0));
433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
43465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    mCacheLines.push(new CacheTextureLine(mCacheWidth, 24, nextLine, 0));
43565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
43651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mCacheLines.push(new CacheTextureLine(mCacheWidth, 32, nextLine, 0));
437694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
43851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mCacheLines.push(new CacheTextureLine(mCacheWidth, 32, nextLine, 0));
439694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
44051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mCacheLines.push(new CacheTextureLine(mCacheWidth, 40, nextLine, 0));
441694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
44251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0));
443694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
444694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
445694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad
446694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() {
447694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t numIndicies = mMaxNumberOfQuads * 6;
448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t);
44951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
451694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Four verts, two triangles , six indices per quad
452694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) {
453694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int i6 = i * 6;
454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int i4 = i * 4;
455694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 0] = i4 + 0;
457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 1] = i4 + 1;
458694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 2] = i4 + 2;
459694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 3] = i4 + 0;
461694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 4] = i4 + 2;
462694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 5] = i4 + 3;
463694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
464694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
465694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glGenBuffers(1, &mIndexBufferID);
466694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBindBuffer(GL_ARRAY_BUFFER, mIndexBufferID);
467694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBufferData(GL_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_DYNAMIC_DRAW);
468694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBindBuffer(GL_ARRAY_BUFFER, 0);
469694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
470694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    free(indexBufferData);
471694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
472694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t coordSize = 3;
473694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t uvSize = 2;
474694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t vertsPerQuad = 4;
4759b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize;
4769b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mTextMeshPtr = new float[vertexBufferSize];
477694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
478694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
479694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text
480694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() {
481694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mInitialized) {
482694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
483694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
484694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
485694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initTextTexture();
486694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initVertexArrayBuffers();
487694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
48865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
48965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq ");
49065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ");
49165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    mLatinPrecache += String16(",.?!()-+@;:`'");
49265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    mLatinPrecache += String16("0123456789");
49365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
494694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = true;
495694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
496694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4979b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() {
4989b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    if (!mUploadTexture) {
4999b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        return;
5009b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
5019b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5029b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    glBindTexture(GL_TEXTURE_2D, mTextureId);
5039b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5049b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    // Iterate over all the cache lines and see which ones need to be updated
5059b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
5069b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        CacheTextureLine* cl = mCacheLines[i];
5079b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        if(cl->mDirty) {
5089b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t xOffset = 0;
5099b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t yOffset = cl->mCurrentRow;
5109b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t width   = mCacheWidth;
5119b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t height  = cl->mMaxHeight;
5129b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            void*    textureData = mTextTexture + yOffset*width;
5139b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5149b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
5159b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk                             GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
5169b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5179b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            cl->mDirty = false;
5189b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        }
519694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
520694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5219b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mUploadTexture = false;
5229b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk}
5239b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5249b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() {
5259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    checkTextureUpdate();
5279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
52851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float* vtx = mTextMeshPtr;
52951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float* tex = vtx + 3;
530694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
531694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // position is slot 0
532694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t slot = 0;
533694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glVertexAttribPointer(slot, 3, GL_FLOAT, false, 20, vtx);
534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // texture0 is slot 1
536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    slot = 1;
537694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glVertexAttribPointer(slot, 2, GL_FLOAT, false, 20, tex);
538694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
539694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
540694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
541694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
542694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
543694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2,
544694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3,
545694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        float x4, float y4, float z4, float u4, float v4) {
54609147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy    if (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom) {
54709147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy        return;
54809147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy    }
54909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy
550694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    const uint32_t vertsPerQuad = 4;
551694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    const uint32_t floatsPerVert = 5;
55251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
553694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
554694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x1;
555694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y1;
556694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = z1;
557694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u1;
558694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v1;
559694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
560694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x2;
561694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y2;
562694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = z2;
563694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u2;
564694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v2;
565694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
566694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x3;
567694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y3;
568694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = z3;
569694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u3;
570694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v3;
571694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
572694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x4;
573694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y4;
574694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = z4;
575694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u4;
576694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v4;
577694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
578694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentQuadIndex++;
579694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
580694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
581694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
582694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
583694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
584694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
585694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
58665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukuint32_t FontRenderer::getRemainingCacheCapacity() {
58765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t remainingCapacity = 0;
58865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    float totalPixels = 0;
58965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
59065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
59165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
59265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
59365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
59465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    return remainingCapacity;
59565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk}
59665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
59765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::precacheLatin(SkPaint* paint) {
59865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    // Remaining capacity is measured in %
59965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
60065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t precacheIdx = 0;
60165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
60265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        mCurrentFont->getCachedUTFChar(paint, (int32_t)mLatinPrecache[precacheIdx]);
60365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
60465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        precacheIdx ++;
60565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
60665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk}
60765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
60865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) {
60965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t currentNumFonts = mActiveFonts.size();
610694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentFont = Font::create(this, fontId, fontSize);
61165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
61265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    const float maxPrecacheFontSize = 40.0f;
61365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    bool isNewFont = currentNumFonts != mActiveFonts.size();
61465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
61565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    if(isNewFont && fontSize <= maxPrecacheFontSize ){
61665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        precacheLatin(paint);
61765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
618694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
619f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
620f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                                uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) {
621f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
622f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    Rect bounds;
623f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    mCurrentFont->measureUTF(paint, text, startIndex, len, numGlyphs, &bounds);
624f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    uint32_t paddedWidth = (uint32_t)(bounds.right - bounds.left) + 2*radius;
625f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    uint32_t paddedHeight = (uint32_t)(bounds.top - bounds.bottom) + 2*radius;
626f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight];
627f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    for(uint32_t i = 0; i < paddedWidth * paddedHeight; i ++) {
628f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        dataBuffer[i] = 0;
629f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
630f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int penX = radius - bounds.left;
631f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int penY = radius - bounds.bottom;
632f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
633f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, penX, penY,
634f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                              dataBuffer, paddedWidth, paddedHeight);
635f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    blurImage(dataBuffer, paddedWidth, paddedHeight, radius);
636f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
637f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    DropShadow image;
638f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.width = paddedWidth;
639f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.height = paddedHeight;
640f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.image = dataBuffer;
641f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.penX = penX;
642f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.penY = penY;
643f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    return image;
644f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
645694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
64651769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
64751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y) {
648694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    checkInit();
649694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
65009147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy    if (!mCurrentFont) {
65109147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy        LOGE("No font set");
652694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
653694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
654694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
65509147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy    mClip = clip;
65651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y);
657694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
658694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex != 0) {
659694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
660694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
661694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
662694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
663694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
66489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
66589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Compute gaussian weights for the blur
66689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // e is the euler's number
66789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float e = 2.718281828459045f;
66889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float pi = 3.1415926535897932f;
66989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
67089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // x is of the form [-radius .. 0 .. radius]
67189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // and sigma varies with radius.
67289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Based on some experimental radius values and sigma's
67389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // we approximately fit sigma = f(radius) as
674f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    // sigma = radius * 0.3  + 0.6
67589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // The larger the radius gets, the more our gaussian blur
67689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // will resemble a box blur since with large sigma
67789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // the gaussian curve begins to lose its shape
678f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    float sigma = 0.3f * (float)radius + 0.6f;
67989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
68089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Now compute the coefficints
68189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // We will store some redundant values to save some math during
68289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // the blur calculations
68389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // precompute some values
68489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
68589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
68689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
68789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float normalizeFactor = 0.0f;
68889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    for(int32_t r = -radius; r <= radius; r ++) {
68989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        float floatR = (float)r;
69089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
69189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        normalizeFactor += weights[r + radius];
69289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
69389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
69489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    //Now we need to normalize the weights because all our coefficients need to add up to one
69589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    normalizeFactor = 1.0f / normalizeFactor;
69689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    for(int32_t r = -radius; r <= radius; r ++) {
69789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        weights[r + radius] *= normalizeFactor;
69889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
69989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
70089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
70189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius,
70289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                                    const uint8_t* source, uint8_t* dest,
70389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                                    int32_t width, int32_t height) {
70489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float blurredPixel = 0.0f;
70589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float currentPixel = 0.0f;
70689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
70789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    for(int32_t y = 0; y < height; y ++) {
70889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
70989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        const uint8_t* input = source + y * width;
71089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        uint8_t* output = dest + y * width;
71189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
71289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        for(int32_t x = 0; x < width; x ++) {
71389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            blurredPixel = 0.0f;
71489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const float* gPtr = weights;
71589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            // Optimization for non-border pixels
71689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            if ((x > radius) && (x < (width - radius))) {
71789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                const uint8_t *i = input + (x - radius);
71889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                for(int r = -radius; r <= radius; r ++) {
71989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    currentPixel = (float)(*i);
72089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
72189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
72289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    i++;
72389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
72489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            } else {
72589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                for(int32_t r = -radius; r <= radius; r ++) {
72689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    // Stepping left and right away from the pixel
72789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    int validW = x + r;
72889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    if(validW < 0) {
72989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validW = 0;
73089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
73189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    if(validW > width - 1) {
73289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validW = width - 1;
73389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
73489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
73589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    currentPixel = (float)(input[validW]);
73689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
73789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
73889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
73989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
74089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            *output = (uint8_t)blurredPixel;
74189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            output ++;
74289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
74389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
74489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
74589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
74689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius,
74789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                                  const uint8_t* source, uint8_t* dest,
74889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                                  int32_t width, int32_t height) {
74989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float blurredPixel = 0.0f;
75089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float currentPixel = 0.0f;
75189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
75289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    for(int32_t y = 0; y < height; y ++) {
75389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
75489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        uint8_t* output = dest + y * width;
75589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
75689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        for(int32_t x = 0; x < width; x ++) {
75789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            blurredPixel = 0.0f;
75889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const float* gPtr = weights;
75989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const uint8_t* input = source + x;
76089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            // Optimization for non-border pixels
76189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            if ((y > radius) && (y < (height - radius))) {
76289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                const uint8_t *i = input + ((y - radius) * width);
76389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                for(int32_t r = -radius; r <= radius; r ++) {
76489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    currentPixel = (float)(*i);
76589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
76689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
76789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    i += width;
76889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
76989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            } else {
77089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                for(int32_t r = -radius; r <= radius; r ++) {
77189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    int validH = y + r;
77289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    // Clamp to zero and width
77389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    if(validH < 0) {
77489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validH = 0;
77589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
77689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    if(validH > height - 1) {
77789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validH = height - 1;
77889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
77989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
78089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    const uint8_t *i = input + validH * width;
78189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    currentPixel = (float)(*i);
78289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
78389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
78489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
78589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
78689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            *output = (uint8_t)blurredPixel;
78789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            output ++;
78889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
78989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
79089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
79189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
79289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
79389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) {
79489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float *gaussian = new float[2 * radius + 1];
79589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    computeGaussianWeights(gaussian, radius);
79689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint8_t* scratch = new uint8_t[width * height];
79789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    horizontalBlur(gaussian, radius, image, scratch, width, height);
79889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    verticalBlur(gaussian, radius, scratch, image, width, height);
79989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    delete[] gaussian;
80089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    delete[] scratch;
80189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
80289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
803694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer
804694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android
805