FontRenderer.cpp revision 16c88085255c71a1a8fc034129aa2dcc61e1ddd0
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>
22e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guy
2351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include <utils/Log.h>
2451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
2515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy#include "Caches.h"
26c9855a53edfac818dc68714557185977556f849dRomain Guy#include "Debug.h"
2751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include "FontRenderer.h"
287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase#include "Caches.h"
2951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
30694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace android {
31694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace uirenderer {
32694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
33694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
3451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy// Defines
3551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy///////////////////////////////////////////////////////////////////////////////
3651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
3751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_WIDTH 1024
3851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_HEIGHT 256
3944984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase#define MAX_TEXT_CACHE_WIDTH 2048
407de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase#define TEXTURE_BORDER_SIZE 2
417de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy#define AUTO_KERN(prev, next) (((next) - (prev) + 32) >> 6 << 16)
439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
447de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase///////////////////////////////////////////////////////////////////////////////
457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase// CacheTextureLine
467de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase///////////////////////////////////////////////////////////////////////////////
477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasebool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
497de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) {
507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        return false;
517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
527de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
537de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (mCurrentCol + glyph.fWidth + TEXTURE_BORDER_SIZE < mMaxWidth) {
547de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        *retOriginX = mCurrentCol + 1;
557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        *retOriginY = mCurrentRow + 1;
567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mCurrentCol += glyph.fWidth + TEXTURE_BORDER_SIZE;
577de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mDirty = true;
587de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        return true;
597de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
607de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
617de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    return false;
627de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase}
6344984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase
6451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy///////////////////////////////////////////////////////////////////////////////
65694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Font
66694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
67694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
682577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize,
69bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        int flags, uint32_t italicStyle, uint32_t scaleX,
70bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        SkPaint::Style style, uint32_t strokeWidth) :
712577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy        mState(state), mFontId(fontId), mFontSize(fontSize),
72bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
73bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        mStyle(style), mStrokeWidth(mStrokeWidth) {
74694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
75694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
76694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
77694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::~Font() {
78694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) {
79694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (mState->mActiveFonts[ct] == this) {
80694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            mState->mActiveFonts.removeAt(ct);
81694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
82694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
83694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
84694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
85694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
86726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        delete mCachedGlyphs.valueAt(i);
87694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
88694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
89694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
909a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid Font::invalidateTextureCache(CacheTextureLine *cacheLine) {
91694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
929a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
939a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        if (cacheLine == NULL || cachedGlyph->mCachedTextureLine == cacheLine) {
949a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            cachedGlyph->mIsValid = false;
959a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        }
96694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
97694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
98694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
99671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
100671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
101f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int nPenX = x + glyph->mBitmapLeft;
102f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int nPenY = y + glyph->mBitmapTop;
103f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
104f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int width = (int) glyph->mBitmapWidth;
105f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int height = (int) glyph->mBitmapHeight;
106f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
10761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds->bottom > nPenY) {
108f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->bottom = nPenY;
109f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
11061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds->left > nPenX) {
111f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->left = nPenX;
112f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
11361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds->right < nPenX + width) {
114f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->right = nPenX + width;
115f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
11661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds->top < nPenY + height) {
117f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->top = nPenY + height;
118f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
119f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
120f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
121671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
122671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
123694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nPenX = x + glyph->mBitmapLeft;
124694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
125694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
12651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float u1 = glyph->mBitmapMinU;
12751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float u2 = glyph->mBitmapMaxU;
12851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float v1 = glyph->mBitmapMinV;
12951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float v2 = glyph->mBitmapMaxV;
13051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
13151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    int width = (int) glyph->mBitmapWidth;
13251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    int height = (int) glyph->mBitmapHeight;
13351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
134d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    mState->appendMeshQuad(nPenX, nPenY, u1, v2,
135d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy            nPenX + width, nPenY, u2, v2,
136d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy            nPenX + width, nPenY - height, u2, v1,
1377de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture);
138694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
139694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
140671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
141671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
14289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    int nPenX = x + glyph->mBitmapLeft;
14389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    int nPenY = y + glyph->mBitmapTop;
14489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
14589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
14689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
14789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture;
1497de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheWidth = cacheTexture->mWidth;
1507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    const uint8_t* cacheBuffer = cacheTexture->mTexture;
15189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
152f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
153f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int32_t bX = 0, bY = 0;
15489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
15589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
156b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy#if DEBUG_FONT_RENDERER
157b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
1583762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Skipping invalid index");
159f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                continue;
160f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            }
161b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy#endif
16289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
16389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
16489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
16589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
16689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
16789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
1699777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
1709777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    const float halfWidth = glyph->mBitmapWidth * 0.5f;
1719777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    const float height = glyph->mBitmapHeight;
1729777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
1739777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    vOffset += glyph->mBitmapTop + height;
1749777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
1759777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkPoint destination[4];
176dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    measure.getPosTan(x + hOffset +  glyph->mBitmapLeft + halfWidth, position, tangent);
1779777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
1789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    // Move along the tangent and offset by the normal
1799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
1809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            -tangent->fY * halfWidth + tangent->fX * vOffset);
1819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset,
1829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            tangent->fY * halfWidth + tangent->fX * vOffset);
1839777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[2].set(destination[1].fX + tangent->fY * height,
1849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            destination[1].fY - tangent->fX * height);
1859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[3].set(destination[0].fX + tangent->fY * height,
1869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            destination[0].fY - tangent->fX * height);
1879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
188dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    const float u1 = glyph->mBitmapMinU;
189dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    const float u2 = glyph->mBitmapMaxU;
190dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    const float v1 = glyph->mBitmapMinV;
191dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    const float v2 = glyph->mBitmapMaxV;
192dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy
1939777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    mState->appendRotatedMeshQuad(
1949777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[0].fX,
1959777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[0].fY, u1, v2,
1969777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[1].fX,
1979777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[1].fY, u2, v2,
1989777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[2].fX,
1999777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[2].fY, u2, v1,
2009777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[3].fX,
2019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[3].fY, u1, v1,
2029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            glyph->mCachedTextureLine->mCacheTexture);
2039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
2049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
2061e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    CachedGlyphInfo* cachedGlyph = NULL;
207726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
2081e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    if (index >= 0) {
2091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        cachedGlyph = mCachedGlyphs.valueAt(index);
2101e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    } else {
211726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        cachedGlyph = cacheGlyph(paint, textUnit);
21265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
21365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
21465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    // Is the glyph still in texture cache?
21565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    if (!cachedGlyph->mIsValid) {
216726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
21765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        updateGlyphCache(paint, skiaGlyph, cachedGlyph);
21865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
21965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
22065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    return cachedGlyph;
22165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk}
22265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
223726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
22461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
22561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
226726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
227671d6cf460531825a321edb200523d0faa7792c9Romain Guy                bitmapW, bitmapH, NULL, NULL);
22861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    } else {
229726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
230671d6cf460531825a321edb200523d0faa7792c9Romain Guy                0, 0, NULL, NULL);
231f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
232f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
233f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
234671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
235671d6cf460531825a321edb200523d0faa7792c9Romain Guy            int numGlyphs, int x, int y, const float* positions) {
236671d6cf460531825a321edb200523d0faa7792c9Romain Guy    render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
237671d6cf460531825a321edb200523d0faa7792c9Romain Guy            0, 0, NULL, positions);
238671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
239671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2409777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
2419777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        int numGlyphs, SkPath* path, float hOffset, float vOffset) {
2429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (numGlyphs == 0 || text == NULL || len == 0) {
2439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return;
2449777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
2459777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2469777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    text += start;
2479777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2489777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    int glyphsCount = 0;
2499777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkFixed prevRsbDelta = 0;
2509777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2519777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    float penX = 0.0f;
2529777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2539777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkPoint position;
2549777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkVector tangent;
2559777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2569777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkPathMeasure measure(*path, false);
2579777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    float pathLength = SkScalarToFloat(measure.getLength());
2589777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2599777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (paint->getTextAlign() != SkPaint::kLeft_Align) {
2609777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float textWidth = SkScalarToFloat(paint->measureText(text, len));
2619777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float pathOffset = pathLength;
2629777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (paint->getTextAlign() == SkPaint::kCenter_Align) {
2639777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            textWidth *= 0.5f;
2649777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            pathOffset *= 0.5f;
2659777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
2669777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        penX += pathOffset - textWidth;
2679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
2689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
269dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    while (glyphsCount < numGlyphs && penX < pathLength) {
2709777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        glyph_t glyph = GET_GLYPH(text);
2719777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2729777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (IS_END_OF_STRING(glyph)) {
2739777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            break;
2749777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
2759777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2769777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
2779777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
2789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        prevRsbDelta = cachedGlyph->mRsbDelta;
2799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (cachedGlyph->mIsValid) {
281dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy            drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent);
2829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
2839777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
2859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        glyphsCount++;
2879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
2889777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
2899777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
290726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
29161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        int numGlyphs, Rect *bounds) {
29261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds == NULL) {
2933762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("No return rectangle provided to measure text");
294f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        return;
295f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
296f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    bounds->set(1e6, -1e6, -1e6, 1e6);
297671d6cf460531825a321edb200523d0faa7792c9Romain Guy    render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, NULL);
298f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
299f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
300726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
30161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
3029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
303694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (numGlyphs == 0 || text == NULL || len == 0) {
304694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
305694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
306694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
307671d6cf460531825a321edb200523d0faa7792c9Romain Guy    static RenderGlyph gRenderGlyph[] = {
308671d6cf460531825a321edb200523d0faa7792c9Romain Guy            &android::uirenderer::Font::drawCachedGlyph,
309671d6cf460531825a321edb200523d0faa7792c9Romain Guy            &android::uirenderer::Font::drawCachedGlyphBitmap,
310671d6cf460531825a321edb200523d0faa7792c9Romain Guy            &android::uirenderer::Font::measureCachedGlyph
311671d6cf460531825a321edb200523d0faa7792c9Romain Guy    };
312671d6cf460531825a321edb200523d0faa7792c9Romain Guy    RenderGlyph render = gRenderGlyph[mode];
313694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
3149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    text += start;
3159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    int glyphsCount = 0;
3169777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
317b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy    if (CC_LIKELY(positions == NULL)) {
318671d6cf460531825a321edb200523d0faa7792c9Romain Guy        SkFixed prevRsbDelta = 0;
319694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
3209777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float penX = x + 0.5f;
321671d6cf460531825a321edb200523d0faa7792c9Romain Guy        int penY = y;
322694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
323671d6cf460531825a321edb200523d0faa7792c9Romain Guy        while (glyphsCount < numGlyphs) {
324671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyph_t glyph = GET_GLYPH(text);
325671d6cf460531825a321edb200523d0faa7792c9Romain Guy
326671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // Reached the end of the string
327671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (IS_END_OF_STRING(glyph)) {
328f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                break;
32989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
330671d6cf460531825a321edb200523d0faa7792c9Romain Guy
331671d6cf460531825a321edb200523d0faa7792c9Romain Guy            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
3329777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
333671d6cf460531825a321edb200523d0faa7792c9Romain Guy            prevRsbDelta = cachedGlyph->mRsbDelta;
334671d6cf460531825a321edb200523d0faa7792c9Romain Guy
335671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
336671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (cachedGlyph->mIsValid) {
337671d6cf460531825a321edb200523d0faa7792c9Romain Guy                (*this.*render)(cachedGlyph, (int) floorf(penX), penY,
338671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        bitmap, bitmapW, bitmapH, bounds, positions);
339671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
340671d6cf460531825a321edb200523d0faa7792c9Romain Guy
341671d6cf460531825a321edb200523d0faa7792c9Romain Guy            penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
342671d6cf460531825a321edb200523d0faa7792c9Romain Guy
343671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyphsCount++;
344694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
345671d6cf460531825a321edb200523d0faa7792c9Romain Guy    } else {
346671d6cf460531825a321edb200523d0faa7792c9Romain Guy        const SkPaint::Align align = paint->getTextAlign();
347694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
348671d6cf460531825a321edb200523d0faa7792c9Romain Guy        // This is for renderPosText()
349671d6cf460531825a321edb200523d0faa7792c9Romain Guy        while (glyphsCount < numGlyphs) {
350671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyph_t glyph = GET_GLYPH(text);
351694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
352671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // Reached the end of the string
353671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (IS_END_OF_STRING(glyph)) {
354671d6cf460531825a321edb200523d0faa7792c9Romain Guy                break;
355671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
356671d6cf460531825a321edb200523d0faa7792c9Romain Guy
357671d6cf460531825a321edb200523d0faa7792c9Romain Guy            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
358671d6cf460531825a321edb200523d0faa7792c9Romain Guy
359671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
360671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (cachedGlyph->mIsValid) {
361671d6cf460531825a321edb200523d0faa7792c9Romain Guy                int penX = x + positions[(glyphsCount << 1)];
362671d6cf460531825a321edb200523d0faa7792c9Romain Guy                int penY = y + positions[(glyphsCount << 1) + 1];
363671d6cf460531825a321edb200523d0faa7792c9Romain Guy
364671d6cf460531825a321edb200523d0faa7792c9Romain Guy                switch (align) {
365671d6cf460531825a321edb200523d0faa7792c9Romain Guy                    case SkPaint::kRight_Align:
366671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX);
367671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY);
368671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        break;
369671d6cf460531825a321edb200523d0faa7792c9Romain Guy                    case SkPaint::kCenter_Align:
370671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1);
371671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1);
372671d6cf460531825a321edb200523d0faa7792c9Romain Guy                    default:
373671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        break;
374671d6cf460531825a321edb200523d0faa7792c9Romain Guy                }
375671d6cf460531825a321edb200523d0faa7792c9Romain Guy
376671d6cf460531825a321edb200523d0faa7792c9Romain Guy                (*this.*render)(cachedGlyph, penX, penY,
377671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        bitmap, bitmapW, bitmapH, bounds, positions);
378671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
379671d6cf460531825a321edb200523d0faa7792c9Romain Guy
380671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyphsCount++;
381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
38551769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) {
386694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mAdvanceX = skiaGlyph.fAdvanceX;
387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mAdvanceY = skiaGlyph.fAdvanceY;
388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapLeft = skiaGlyph.fLeft;
389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapTop = skiaGlyph.fTop;
3902bffd268f135df8308c9e67af110525a5c463424Romain Guy    glyph->mLsbDelta = skiaGlyph.fLsbDelta;
3912bffd268f135df8308c9e67af110525a5c463424Romain Guy    glyph->mRsbDelta = skiaGlyph.fRsbDelta;
392694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
393694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
394694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
395694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
396694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Get the bitmap for the glyph
397694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    paint->findImage(skiaGlyph);
3987de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY);
399694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
400694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!glyph->mIsValid) {
401694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
403694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + skiaGlyph.fWidth;
405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + skiaGlyph.fHeight;
406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
40789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    glyph->mStartX = startX;
40889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    glyph->mStartY = startY;
409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapWidth = skiaGlyph.fWidth;
410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapHeight = skiaGlyph.fHeight;
411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4127de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth;
4137de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight;
414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMinU = (float) startX / (float) cacheWidth;
416694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMinV = (float) startY / (float) cacheHeight;
417694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMaxU = (float) endX / (float) cacheWidth;
418694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMaxV = (float) endY / (float) cacheHeight;
419694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
42051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mState->mUploadTexture = true;
421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4237de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) {
42451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCachedGlyphs.add(glyph, newGlyph);
426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
427726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    newGlyph->mGlyphIndex = skiaGlyph.fID;
429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    newGlyph->mIsValid = false;
430694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    updateGlyphCache(paint, skiaGlyph, newGlyph);
432694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return newGlyph;
434694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
435694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4362577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
437bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        int flags, uint32_t italicStyle, uint32_t scaleX,
438bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        SkPaint::Style style, uint32_t strokeWidth) {
439694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Vector<Font*> &activeFonts = state->mActiveFonts;
440694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
441694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < activeFonts.size(); i++) {
44251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        Font* font = activeFonts[i];
4432577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy        if (font->mFontId == fontId && font->mFontSize == fontSize &&
4448668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase                font->mFlags == flags && font->mItalicStyle == italicStyle &&
445bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy                font->mScaleX == scaleX && font->mStyle == style &&
446bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy                (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
44751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy            return font;
448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
451bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
452bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy            scaleX, style, strokeWidth);
453694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    activeFonts.push(newFont);
454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return newFont;
455694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
458694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer
459694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
461514fb18827186591d66973c2362c859b64b63556Romain Guystatic bool sLogFontRendererCreate = true;
462514fb18827186591d66973c2362c859b64b63556Romain Guy
463694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() {
464c9855a53edfac818dc68714557185977556f849dRomain Guy    if (sLogFontRendererCreate) {
465c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("Creating FontRenderer");
466c9855a53edfac818dc68714557185977556f849dRomain Guy    }
46751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
468b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy    mGammaTable = NULL;
469694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = false;
470694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mMaxNumberOfQuads = 1024;
471694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentQuadIndex = 0;
472694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4739cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    mTextMeshPtr = NULL;
4747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCurrentCacheTexture = NULL;
4757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mLastCacheTexture = NULL;
4767de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTextureSmall = NULL;
4777de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture128 = NULL;
4787de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture256 = NULL;
4797de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture512 = NULL;
4809cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy
4812a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    mLinearFiltering = false;
4822a47c14e2a6f152496b43104bc785c488583fd59Chet Haase
483694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mIndexBufferID = 0;
484694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4857de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
4867de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT;
48751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
48851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    char property[PROPERTY_VALUE_MAX];
48951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) {
490c9855a53edfac818dc68714557185977556f849dRomain Guy        if (sLogFontRendererCreate) {
491c9855a53edfac818dc68714557185977556f849dRomain Guy            INIT_LOGD("  Setting text cache width to %s pixels", property);
492c9855a53edfac818dc68714557185977556f849dRomain Guy        }
4937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mSmallCacheWidth = atoi(property);
49451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    } else {
495514fb18827186591d66973c2362c859b64b63556Romain Guy        if (sLogFontRendererCreate) {
4967de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            INIT_LOGD("  Using default text cache width of %i pixels", mSmallCacheWidth);
497514fb18827186591d66973c2362c859b64b63556Romain Guy        }
49851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    }
49951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
50051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) {
501c9855a53edfac818dc68714557185977556f849dRomain Guy        if (sLogFontRendererCreate) {
502c9855a53edfac818dc68714557185977556f849dRomain Guy            INIT_LOGD("  Setting text cache width to %s pixels", property);
503c9855a53edfac818dc68714557185977556f849dRomain Guy        }
5047de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mSmallCacheHeight = atoi(property);
50551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    } else {
506514fb18827186591d66973c2362c859b64b63556Romain Guy        if (sLogFontRendererCreate) {
5077de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            INIT_LOGD("  Using default text cache height of %i pixels", mSmallCacheHeight);
508514fb18827186591d66973c2362c859b64b63556Romain Guy        }
50951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    }
510514fb18827186591d66973c2362c859b64b63556Romain Guy
511514fb18827186591d66973c2362c859b64b63556Romain Guy    sLogFontRendererCreate = false;
512694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
513694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
514694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() {
515694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
516694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete mCacheLines[i];
517694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
518694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.clear();
519694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5209cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    if (mInitialized) {
521a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy        // Unbinding the buffer shouldn't be necessary but it crashes with some drivers
522a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy        Caches::getInstance().unbindIndicesBuffer();
523b0317984d34da99b614597ad0a8b39268eacb783Romain Guy        glDeleteBuffers(1, &mIndexBufferID);
524b0317984d34da99b614597ad0a8b39268eacb783Romain Guy
5259cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy        delete[] mTextMeshPtr;
5267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTextureSmall;
5277de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture128;
5287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture256;
5297de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture512;
5309b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
531694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
532694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Vector<Font*> fontsToDereference = mActiveFonts;
533694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < fontsToDereference.size(); i++) {
534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete fontsToDereference[i];
535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
537694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
538694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() {
539694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex != 0) {
540694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
541694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
542694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
5439d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
544694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
545694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mActiveFonts[i]->invalidateTextureCache();
546694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
5479d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
548694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
549694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCacheLines[i]->mCurrentCol = 0;
550694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
551694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
552694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5539a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) {
5549a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    if (cacheTexture && cacheTexture->mTexture) {
5559a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        glDeleteTextures(1, &cacheTexture->mTextureId);
5569d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete[] cacheTexture->mTexture;
5579a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        cacheTexture->mTexture = NULL;
55899a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy        cacheTexture->mTextureId = 0;
5599a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    }
5609a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase}
5619a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
5629a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::flushLargeCaches() {
5639a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    if ((!mCacheTexture128 || !mCacheTexture128->mTexture) &&
5649a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            (!mCacheTexture256 || !mCacheTexture256->mTexture) &&
5659a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            (!mCacheTexture512 || !mCacheTexture512->mTexture)) {
5669a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        // Typical case; no large glyph caches allocated
5679a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        return;
5689a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    }
5699a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
5709a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
5719a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        CacheTextureLine* cacheLine = mCacheLines[i];
5729a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        if ((cacheLine->mCacheTexture == mCacheTexture128 ||
5739a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                cacheLine->mCacheTexture == mCacheTexture256 ||
5749a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                cacheLine->mCacheTexture == mCacheTexture512) &&
5759a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                cacheLine->mCacheTexture->mTexture != NULL) {
5769a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            cacheLine->mCurrentCol = 0;
5779a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
5789a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                mActiveFonts[i]->invalidateTextureCache(cacheLine);
5799a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            }
5809a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        }
5819a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    }
5829a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
5839a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    deallocateTextureMemory(mCacheTexture128);
5849a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    deallocateTextureMemory(mCacheTexture256);
5859a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    deallocateTextureMemory(mCacheTexture512);
5869a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase}
5879a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
5889d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guyvoid FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
5892a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    int width = cacheTexture->mWidth;
5902a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    int height = cacheTexture->mHeight;
5919d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
5922a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    cacheTexture->mTexture = new uint8_t[width * height];
59399a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy#if DEBUG_FONT_RENDERER
5942a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    memset(cacheTexture->mTexture, 0, width * height * sizeof(uint8_t));
59599a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy#endif
59699a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy
59799a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy    if (!cacheTexture->mTextureId) {
59899a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy        glGenTextures(1, &cacheTexture->mTextureId);
59999a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy    }
6009d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
60116c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy    Caches::getInstance().activeTexture(0);
6022a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
6032a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
6042a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    // Initialize texture dimensions
6052a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
6062a47c14e2a6f152496b43104bc785c488583fd59Chet Haase            GL_ALPHA, GL_UNSIGNED_BYTE, 0);
6072a47c14e2a6f152496b43104bc785c488583fd59Chet Haase
6082a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    const GLenum filtering = cacheTexture->mLinearFiltering ? GL_LINEAR : GL_NEAREST;
6092a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
6102a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
6117de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
6122a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6132a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase}
6157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
6167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
6177de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        uint32_t* retOriginX, uint32_t* retOriginY) {
6187de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mIsValid = false;
619694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the glyph is too tall, don't cache it
6207de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (glyph.fHeight + TEXTURE_BORDER_SIZE > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
6213762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Font size to large to fit in cache. width, height = %i, %i",
6227de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase                (int) glyph.fWidth, (int) glyph.fHeight);
6237de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        return;
624694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
625694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
626694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Now copy the bitmap into the cache texture
627694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
628694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
629694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
630694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    bool bitmapFit = false;
6317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    CacheTextureLine *cacheLine;
632694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
633694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
634694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (bitmapFit) {
6357de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            cacheLine = mCacheLines[i];
636694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
637694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
638694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
639694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
640694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the new glyph didn't fit, flush the state so far and invalidate everything
641694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!bitmapFit) {
642694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        flushAllAndInvalidate();
643694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
644694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // Try to fit it again
645694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        for (uint32_t i = 0; i < mCacheLines.size(); i++) {
646694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
647694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            if (bitmapFit) {
6487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase                cacheLine = mCacheLines[i];
649694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                break;
650694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            }
651694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
652694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
653694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // if we still don't fit, something is wrong and we shouldn't draw
654694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (!bitmapFit) {
6557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            return;
656694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
657694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
658694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6597de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mCachedTextureLine = cacheLine;
6607de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
661694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginX = startX;
662694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginY = startY;
663694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
664694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + glyph.fWidth;
665694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + glyph.fHeight;
666694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6677de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheWidth = cacheLine->mMaxWidth;
668694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6699d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    CacheTexture* cacheTexture = cacheLine->mCacheTexture;
6709d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    if (!cacheTexture->mTexture) {
6717de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        // Large-glyph texture memory is allocated only as needed
6722a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        allocateTextureMemory(cacheTexture);
6737de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
6749d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
6757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint8_t* cacheBuffer = cacheTexture->mTexture;
67689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
677694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    unsigned int stride = glyph.rowBytes();
678694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
679694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
680694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
681694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
68289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * stride + bX];
683b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy            cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
684694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
685694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
6869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
6877de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mIsValid = true;
688694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
689694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6907de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
6919d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    uint8_t* textureMemory = NULL;
69299a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy    CacheTexture* cacheTexture = new CacheTexture(textureMemory, width, height);
6939d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
6942a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    if (allocate) {
6952a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        allocateTextureMemory(cacheTexture);
6962a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    }
6979d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
6982a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    return cacheTexture;
6997de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase}
7007de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
7017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::initTextTexture() {
7029d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
7039d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete mCacheLines[i];
7049d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    }
7057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.clear();
7067de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
7079d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    if (mCacheTextureSmall) {
7089d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete mCacheTextureSmall;
7099d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete mCacheTexture128;
7109d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete mCacheTexture256;
7119d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete mCacheTexture512;
7129d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    }
7139d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
7147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    // Next, use other, separate caches for large glyphs.
7157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint16_t maxWidth = 0;
7167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (Caches::hasInstance()) {
7177de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        maxWidth = Caches::getInstance().maxTextureSize;
7187de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
7199d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
7207de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) {
7217de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        maxWidth = MAX_TEXT_CACHE_WIDTH;
7227de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
7239d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
7247de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true);
7257de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture128 = createCacheTexture(maxWidth, 256, false);
7267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture256 = createCacheTexture(maxWidth, 256, false);
7277de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture512 = createCacheTexture(maxWidth, 512, false);
7287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCurrentCacheTexture = mCacheTextureSmall;
7297de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
7307de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mUploadTexture = false;
7317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    // Split up our default cache texture into lines of certain widths
732694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nextLine = 0;
7337de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, 0, mCacheTextureSmall));
734694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
7357de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall));
736694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
7377de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall));
73865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
7397de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall));
740694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
7417de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall));
742694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
7437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, 0, mCacheTextureSmall));
744694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
7457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine,
7467de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            nextLine, 0, mCacheTextureSmall));
7477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
7487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    //  The first cache is split into 2 lines of height 128, the rest have just one cache line.
7497de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, 0, mCacheTexture128));
7507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, 0, mCacheTexture128));
7517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, 0, mCacheTexture256));
7527de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, 0, mCacheTexture512));
753694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
754694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
755694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad
756694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() {
757d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    uint32_t numIndices = mMaxNumberOfQuads * 6;
758d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t);
75951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
760694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
761694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Four verts, two triangles , six indices per quad
762694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) {
763694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int i6 = i * 6;
764694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int i4 = i * 4;
765694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
766694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 0] = i4 + 0;
767694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 1] = i4 + 1;
768694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 2] = i4 + 2;
769694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
770694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 3] = i4 + 0;
771694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 4] = i4 + 2;
772694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 5] = i4 + 3;
773694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
774694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
775694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glGenBuffers(1, &mIndexBufferID);
77615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    Caches::getInstance().bindIndicesBuffer(mIndexBufferID);
7775d794412e3e429e47404395badcd11b0b8639e8bRomain Guy    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW);
778694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
779694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    free(indexBufferData);
780694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
781d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    uint32_t coordSize = 2;
782694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t uvSize = 2;
783694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t vertsPerQuad = 4;
7849b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize;
7859b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mTextMeshPtr = new float[vertexBufferSize];
786694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
787694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
788694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text
789694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() {
790694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mInitialized) {
791694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
792694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
793694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
794694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initTextTexture();
795694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initVertexArrayBuffers();
796694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
797694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = true;
798694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
799694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8009b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() {
8017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) {
8029b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        return;
8039b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
8049b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
8052d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    Caches& caches = Caches::getInstance();
8062d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    GLuint lastTextureId = 0;
8079b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    // Iterate over all the cache lines and see which ones need to be updated
8089b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
8099b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        CacheTextureLine* cl = mCacheLines[i];
8107de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) {
8117de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            CacheTexture* cacheTexture = cl->mCacheTexture;
8129b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t xOffset = 0;
8139b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t yOffset = cl->mCurrentRow;
8147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            uint32_t width   = cl->mMaxWidth;
8159b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t height  = cl->mMaxHeight;
8167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            void* textureData = cacheTexture->mTexture + (yOffset * width);
8179b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
8182d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy            if (cacheTexture->mTextureId != lastTextureId) {
8192d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy                caches.activeTexture(0);
8202d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy                glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
8212d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy                lastTextureId = cacheTexture->mTextureId;
8222d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy            }
8239b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
8241e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy                    GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
8259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
8269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            cl->mDirty = false;
8279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        }
828694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
829694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
83016c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy    caches.activeTexture(0);
8317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId);
8322a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    if (mLinearFiltering != mCurrentCacheTexture->mLinearFiltering) {
8332a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        const GLenum filtering = mLinearFiltering ? GL_LINEAR : GL_NEAREST;
8342a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
8352a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
8362a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        mCurrentCacheTexture->mLinearFiltering = mLinearFiltering;
8372a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    }
8387de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mLastCacheTexture = mCurrentCacheTexture;
8397de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
8409b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mUploadTexture = false;
8419b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk}
8429b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
8439b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() {
8449b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    checkTextureUpdate();
8459b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
84615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    Caches& caches = Caches::getInstance();
8472d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    caches.bindIndicesBuffer(mIndexBufferID);
84815bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    if (!mDrawn) {
84915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        float* buffer = mTextMeshPtr;
85015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        int offset = 2;
85115bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
85215bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        bool force = caches.unbindMeshBuffer();
85315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        caches.bindPositionVertexPointer(force, caches.currentProgram->position, buffer);
85415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        caches.bindTexCoordsVertexPointer(force, caches.currentProgram->texCoords,
85515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy                buffer + offset);
85615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    }
85715bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
858694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
8595b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
8605b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mDrawn = true;
861694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
862694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8639777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
8649777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
8657de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        float x4, float y4, float u4, float v4, CacheTexture* texture) {
8667de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (texture != mCurrentCacheTexture) {
8677de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        if (mCurrentQuadIndex != 0) {
8687de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            // First, draw everything stored already which uses the previous texture
8697de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            issueDrawCommand();
8707de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            mCurrentQuadIndex = 0;
8717de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        }
8727de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        // Now use the new texture id
8737de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mCurrentCacheTexture = texture;
8747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
87509147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy
876694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    const uint32_t vertsPerQuad = 4;
877d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    const uint32_t floatsPerVert = 4;
87851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
879694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
880694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x1;
881694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y1;
882694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u1;
883694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v1;
884694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
885694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x2;
886694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y2;
887694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u2;
888694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v2;
889694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
890694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x3;
891694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y3;
892694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u3;
893694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v3;
894694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
895694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x4;
896694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y4;
897694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u4;
898694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v4;
899694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
900694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentQuadIndex++;
9019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
9029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
9039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
9049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
9059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x4, float y4, float u4, float v4, CacheTexture* texture) {
9069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
9079777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mClip &&
9089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
9099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return;
9109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
9119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
9129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
913694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
9145b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    if (mBounds) {
9155b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->left = fmin(mBounds->left, x1);
9165b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->top = fmin(mBounds->top, y3);
9175b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->right = fmax(mBounds->right, x3);
9185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->bottom = fmax(mBounds->bottom, y1);
9195b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
9205b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
921694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
922694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
923694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
924694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
925694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
926694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
9279777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
9289777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
9299777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x4, float y4, float u4, float v4, CacheTexture* texture) {
9309777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
9319777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
9329777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
9339777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mBounds) {
9349777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
9359777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
9369777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
9379777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
9389777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
9399777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
9409777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
9419777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        issueDrawCommand();
9429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mCurrentQuadIndex = 0;
9439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
9449777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
9459777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
94665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukuint32_t FontRenderer::getRemainingCacheCapacity() {
94765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t remainingCapacity = 0;
94865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    float totalPixels = 0;
94965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
95065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
95165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
95265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
95365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
95465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    return remainingCapacity;
95565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk}
95665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
95765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::precacheLatin(SkPaint* paint) {
95865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    // Remaining capacity is measured in %
95965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
960ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy    uint32_t precacheIndex = 0;
961ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy
962ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy    // We store a string with letters in a rough frequency of occurrence
963ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy    String16 l("eisarntolcdugpmhbyfvkwzxjq EISARNTOLCDUGPMHBYFVKWZXJQ,.?!()-+@;:'0123456789");
964ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy
965ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy    size_t size = l.size();
966ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy    uint16_t latin[size];
967ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy    paint->utfToGlyphs(l.string(), SkPaint::kUTF16_TextEncoding, size * sizeof(char16_t), latin);
968ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy
969ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy    while (remainingCapacity > 25 && precacheIndex < size) {
970ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy        mCurrentFont->getCachedGlyph(paint, TO_GLYPH(latin[precacheIndex]));
97165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
972ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy        precacheIndex++;
97365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
97465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk}
97565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
97665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) {
97765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t currentNumFonts = mActiveFonts.size();
978325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    int flags = 0;
979325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    if (paint->isFakeBoldText()) {
980325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy        flags |= Font::kFakeBold;
981325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    }
9822577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy
9832577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy    const float skewX = paint->getTextSkewX();
9842577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy    uint32_t italicStyle = *(uint32_t*) &skewX;
9858668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase    const float scaleXFloat = paint->getTextScaleX();
9868668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase    uint32_t scaleX = *(uint32_t*) &scaleXFloat;
987bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    SkPaint::Style style = paint->getStyle();
988bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    const float strokeWidthFloat = paint->getStrokeWidth();
989bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
990bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle,
991bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy            scaleX, style, strokeWidth);
99265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
99365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    const float maxPrecacheFontSize = 40.0f;
99465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    bool isNewFont = currentNumFonts != mActiveFonts.size();
99565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
9962bffd268f135df8308c9e67af110525a5c463424Romain Guy    if (isNewFont && fontSize <= maxPrecacheFontSize) {
99765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        precacheLatin(paint);
99865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
999694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
10007975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy
1001f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
10021e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) {
10031e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    checkInit();
10041e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
10051e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    if (!mCurrentFont) {
10061e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        DropShadow image;
10071e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.width = 0;
10081e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.height = 0;
10091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.image = NULL;
10101e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.penX = 0;
10111e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.penY = 0;
10121e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        return image;
10131e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    }
1014f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
10152d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    mDrawn = false;
1016ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy    mClip = NULL;
1017ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy    mBounds = NULL;
1018ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
1019f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    Rect bounds;
1020726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds);
1021ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
10221e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
10231e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
1024f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight];
1025ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
10261e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) {
1027f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        dataBuffer[i] = 0;
1028f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
10291e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
1030f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int penX = radius - bounds.left;
1031f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int penY = radius - bounds.bottom;
1032f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
1033726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
10341e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy            dataBuffer, paddedWidth, paddedHeight);
1035f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    blurImage(dataBuffer, paddedWidth, paddedHeight, radius);
1036f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
1037f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    DropShadow image;
1038f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.width = paddedWidth;
1039f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.height = paddedHeight;
1040f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.image = dataBuffer;
1041f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.penX = penX;
1042f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.penY = penY;
10432d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy
1044f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    return image;
1045f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
1046694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1047671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::initRender(const Rect* clip, Rect* bounds) {
1048694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    checkInit();
1049694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
10505b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mDrawn = false;
10515b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mBounds = bounds;
105209147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy    mClip = clip;
1053671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
1054ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
1055671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::finishRender() {
10565b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mBounds = NULL;
1057ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy    mClip = NULL;
1058694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1059694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex != 0) {
1060694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
1061694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
1062694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
1063671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
1064671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1065671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
1066671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) {
1067671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (!mCurrentFont) {
1068671d6cf460531825a321edb200523d0faa7792c9Romain Guy        ALOGE("No font set");
1069671d6cf460531825a321edb200523d0faa7792c9Romain Guy        return false;
1070671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
1071671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1072671d6cf460531825a321edb200523d0faa7792c9Romain Guy    initRender(clip, bounds);
1073671d6cf460531825a321edb200523d0faa7792c9Romain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y);
1074671d6cf460531825a321edb200523d0faa7792c9Romain Guy    finishRender();
1075671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1076671d6cf460531825a321edb200523d0faa7792c9Romain Guy    return mDrawn;
1077671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
1078671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1079671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
1080671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
1081671d6cf460531825a321edb200523d0faa7792c9Romain Guy        const float* positions, Rect* bounds) {
1082671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (!mCurrentFont) {
1083671d6cf460531825a321edb200523d0faa7792c9Romain Guy        ALOGE("No font set");
1084671d6cf460531825a321edb200523d0faa7792c9Romain Guy        return false;
1085671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
1086671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1087671d6cf460531825a321edb200523d0faa7792c9Romain Guy    initRender(clip, bounds);
1088671d6cf460531825a321edb200523d0faa7792c9Romain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
1089671d6cf460531825a321edb200523d0faa7792c9Romain Guy    finishRender();
10905b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
10915b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    return mDrawn;
10929777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
10939777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
10949777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guybool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text,
10959777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path,
10969777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float hOffset, float vOffset, Rect* bounds) {
10979777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (!mCurrentFont) {
10989777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        ALOGE("No font set");
10999777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return false;
11009777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
11019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
11029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    initRender(clip, bounds);
11039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
11049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    finishRender();
11059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
11069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    return mDrawn;
1107694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
1108694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
110989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
111089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Compute gaussian weights for the blur
111189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // e is the euler's number
111289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float e = 2.718281828459045f;
111389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float pi = 3.1415926535897932f;
111489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
111589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // x is of the form [-radius .. 0 .. radius]
111689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // and sigma varies with radius.
111789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Based on some experimental radius values and sigma's
111889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // we approximately fit sigma = f(radius) as
1119f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    // sigma = radius * 0.3  + 0.6
112089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // The larger the radius gets, the more our gaussian blur
112189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // will resemble a box blur since with large sigma
112289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // the gaussian curve begins to lose its shape
1123325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    float sigma = 0.3f * (float) radius + 0.6f;
112489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
112589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Now compute the coefficints
112689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // We will store some redundant values to save some math during
112789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // the blur calculations
112889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // precompute some values
112989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
113089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
113189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
113289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float normalizeFactor = 0.0f;
1133325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t r = -radius; r <= radius; r ++) {
11347975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy        float floatR = (float) r;
113589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
113689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        normalizeFactor += weights[r + radius];
113789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
113889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
113989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    //Now we need to normalize the weights because all our coefficients need to add up to one
114089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    normalizeFactor = 1.0f / normalizeFactor;
1141325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t r = -radius; r <= radius; r ++) {
114289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        weights[r + radius] *= normalizeFactor;
114389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
114489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
114589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
114689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius,
11471e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
114889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float blurredPixel = 0.0f;
114989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float currentPixel = 0.0f;
115089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1151325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t y = 0; y < height; y ++) {
115289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
115389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        const uint8_t* input = source + y * width;
115489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        uint8_t* output = dest + y * width;
115589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1156325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy        for (int32_t x = 0; x < width; x ++) {
115789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            blurredPixel = 0.0f;
115889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const float* gPtr = weights;
115989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            // Optimization for non-border pixels
1160325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy            if (x > radius && x < (width - radius)) {
116189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                const uint8_t *i = input + (x - radius);
1162325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int r = -radius; r <= radius; r ++) {
11637975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy                    currentPixel = (float) (*i);
116489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
116589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
116689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    i++;
116789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
116889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            } else {
1169325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int32_t r = -radius; r <= radius; r ++) {
117089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    // Stepping left and right away from the pixel
117189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    int validW = x + r;
1172325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validW < 0) {
117389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validW = 0;
117489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
1175325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validW > width - 1) {
117689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validW = width - 1;
117789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
117889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1179325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    currentPixel = (float) input[validW];
118089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
118189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
118289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
118389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
118489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            *output = (uint8_t)blurredPixel;
118589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            output ++;
118689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
118789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
118889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
118989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
119089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius,
11911e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
119289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float blurredPixel = 0.0f;
119389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float currentPixel = 0.0f;
119489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1195325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t y = 0; y < height; y ++) {
119689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
119789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        uint8_t* output = dest + y * width;
119889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1199325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy        for (int32_t x = 0; x < width; x ++) {
120089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            blurredPixel = 0.0f;
120189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const float* gPtr = weights;
120289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const uint8_t* input = source + x;
120389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            // Optimization for non-border pixels
1204325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy            if (y > radius && y < (height - radius)) {
120589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                const uint8_t *i = input + ((y - radius) * width);
1206325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int32_t r = -radius; r <= radius; r ++) {
120789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    currentPixel = (float)(*i);
120889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
120989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
121089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    i += width;
121189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
121289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            } else {
1213325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int32_t r = -radius; r <= radius; r ++) {
121489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    int validH = y + r;
121589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    // Clamp to zero and width
1216325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validH < 0) {
121789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validH = 0;
121889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
1219325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validH > height - 1) {
122089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validH = height - 1;
122189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
122289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
122389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    const uint8_t *i = input + validH * width;
1224325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    currentPixel = (float) (*i);
122589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
122689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
122789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
122889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
1229325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy            *output = (uint8_t) blurredPixel;
123089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            output ++;
123189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
123289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
123389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
123489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
123589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
123689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) {
123789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float *gaussian = new float[2 * radius + 1];
123889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    computeGaussianWeights(gaussian, radius);
1239d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
124089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint8_t* scratch = new uint8_t[width * height];
1241d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
124289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    horizontalBlur(gaussian, radius, image, scratch, width, height);
124389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    verticalBlur(gaussian, radius, scratch, image, width, height);
1244d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
124589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    delete[] gaussian;
124689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    delete[] scratch;
124789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
124889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer
1250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android
1251