FontRenderer.cpp revision 9777173eb6c9eb97c7921c8288ebc65e3ab3ce6f
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    float nPenX = glyph->mBitmapLeft;
1749777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    vOffset += glyph->mBitmapTop + height;
1759777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
1769777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    const float u1 = glyph->mBitmapMinU;
1779777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    const float u2 = glyph->mBitmapMaxU;
1789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    const float v1 = glyph->mBitmapMinV;
1799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    const float v2 = glyph->mBitmapMaxV;
1809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
1819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkPoint destination[4];
1829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    measure.getPosTan(x + hOffset + nPenX + halfWidth, position, tangent);
1839777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
1849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    // Move along the tangent and offset by the normal
1859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
1869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            -tangent->fY * halfWidth + tangent->fX * vOffset);
1879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset,
1889777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            tangent->fY * halfWidth + tangent->fX * vOffset);
1899777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[2].set(destination[1].fX + tangent->fY * height,
1909777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            destination[1].fY - tangent->fX * height);
1919777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[3].set(destination[0].fX + tangent->fY * height,
1929777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            destination[0].fY - tangent->fX * height);
1939777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
1949777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    mState->appendRotatedMeshQuad(
1959777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[0].fX,
1969777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[0].fY, u1, v2,
1979777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[1].fX,
1989777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[1].fY, u2, v2,
1999777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[2].fX,
2009777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[2].fY, u2, v1,
2019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[3].fX,
2029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[3].fY, u1, v1,
2039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            glyph->mCachedTextureLine->mCacheTexture);
2049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
2059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2067de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
2071e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    CachedGlyphInfo* cachedGlyph = NULL;
208726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
2091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    if (index >= 0) {
2101e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        cachedGlyph = mCachedGlyphs.valueAt(index);
2111e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    } else {
212726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        cachedGlyph = cacheGlyph(paint, textUnit);
21365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
21465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
21565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    // Is the glyph still in texture cache?
21665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    if (!cachedGlyph->mIsValid) {
217726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
21865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        updateGlyphCache(paint, skiaGlyph, cachedGlyph);
21965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
22065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
22165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    return cachedGlyph;
22265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk}
22365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
224726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
22561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
22661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
227726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
228671d6cf460531825a321edb200523d0faa7792c9Romain Guy                bitmapW, bitmapH, NULL, NULL);
22961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    } else {
230726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
231671d6cf460531825a321edb200523d0faa7792c9Romain Guy                0, 0, NULL, NULL);
232f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
233f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
234f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
235671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
236671d6cf460531825a321edb200523d0faa7792c9Romain Guy            int numGlyphs, int x, int y, const float* positions) {
237671d6cf460531825a321edb200523d0faa7792c9Romain Guy    render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
238671d6cf460531825a321edb200523d0faa7792c9Romain Guy            0, 0, NULL, positions);
239671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
240671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2419777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
2429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        int numGlyphs, SkPath* path, float hOffset, float vOffset) {
2439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (numGlyphs == 0 || text == NULL || len == 0) {
2449777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return;
2459777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
2469777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2479777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    text += start;
2489777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2499777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    int glyphsCount = 0;
2509777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkFixed prevRsbDelta = 0;
2519777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2529777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    float penX = 0.0f;
2539777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2549777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkPoint position;
2559777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkVector tangent;
2569777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2579777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkPathMeasure measure(*path, false);
2589777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    float pathLength = SkScalarToFloat(measure.getLength());
2599777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2609777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (paint->getTextAlign() != SkPaint::kLeft_Align) {
2619777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float textWidth = SkScalarToFloat(paint->measureText(text, len));
2629777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float pathOffset = pathLength;
2639777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (paint->getTextAlign() == SkPaint::kCenter_Align) {
2649777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            textWidth *= 0.5f;
2659777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            pathOffset *= 0.5f;
2669777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
2679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        penX += pathOffset - textWidth;
2689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
2699777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2709777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    while (glyphsCount < numGlyphs && penX <= pathLength) {
2719777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        glyph_t glyph = GET_GLYPH(text);
2729777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2739777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (IS_END_OF_STRING(glyph)) {
2749777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            break;
2759777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
2769777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2779777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
2789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
2799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        prevRsbDelta = cachedGlyph->mRsbDelta;
2809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (cachedGlyph->mIsValid) {
2829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            drawCachedGlyph(cachedGlyph, roundf(penX), hOffset, vOffset, measure, &position, &tangent);
2839777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
2849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
2869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        glyphsCount++;
2889777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
2899777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
2909777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
291726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
29261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        int numGlyphs, Rect *bounds) {
29361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds == NULL) {
2943762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("No return rectangle provided to measure text");
295f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        return;
296f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
297f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    bounds->set(1e6, -1e6, -1e6, 1e6);
298671d6cf460531825a321edb200523d0faa7792c9Romain Guy    render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, NULL);
299f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
300f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
301726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
30261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
3039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
304694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (numGlyphs == 0 || text == NULL || len == 0) {
305694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
306694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
307694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
308671d6cf460531825a321edb200523d0faa7792c9Romain Guy    static RenderGlyph gRenderGlyph[] = {
309671d6cf460531825a321edb200523d0faa7792c9Romain Guy            &android::uirenderer::Font::drawCachedGlyph,
310671d6cf460531825a321edb200523d0faa7792c9Romain Guy            &android::uirenderer::Font::drawCachedGlyphBitmap,
311671d6cf460531825a321edb200523d0faa7792c9Romain Guy            &android::uirenderer::Font::measureCachedGlyph
312671d6cf460531825a321edb200523d0faa7792c9Romain Guy    };
313671d6cf460531825a321edb200523d0faa7792c9Romain Guy    RenderGlyph render = gRenderGlyph[mode];
314694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
3159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    text += start;
3169777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    int glyphsCount = 0;
3179777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
318b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy    if (CC_LIKELY(positions == NULL)) {
319671d6cf460531825a321edb200523d0faa7792c9Romain Guy        SkFixed prevRsbDelta = 0;
320694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
3219777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float penX = x + 0.5f;
322671d6cf460531825a321edb200523d0faa7792c9Romain Guy        int penY = y;
323694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
324671d6cf460531825a321edb200523d0faa7792c9Romain Guy        while (glyphsCount < numGlyphs) {
325671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyph_t glyph = GET_GLYPH(text);
326671d6cf460531825a321edb200523d0faa7792c9Romain Guy
327671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // Reached the end of the string
328671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (IS_END_OF_STRING(glyph)) {
329f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                break;
33089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
331671d6cf460531825a321edb200523d0faa7792c9Romain Guy
332671d6cf460531825a321edb200523d0faa7792c9Romain Guy            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
3339777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
334671d6cf460531825a321edb200523d0faa7792c9Romain Guy            prevRsbDelta = cachedGlyph->mRsbDelta;
335671d6cf460531825a321edb200523d0faa7792c9Romain Guy
336671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
337671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (cachedGlyph->mIsValid) {
338671d6cf460531825a321edb200523d0faa7792c9Romain Guy                (*this.*render)(cachedGlyph, (int) floorf(penX), penY,
339671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        bitmap, bitmapW, bitmapH, bounds, positions);
340671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
341671d6cf460531825a321edb200523d0faa7792c9Romain Guy
342671d6cf460531825a321edb200523d0faa7792c9Romain Guy            penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
343671d6cf460531825a321edb200523d0faa7792c9Romain Guy
344671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyphsCount++;
345694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
346671d6cf460531825a321edb200523d0faa7792c9Romain Guy    } else {
347671d6cf460531825a321edb200523d0faa7792c9Romain Guy        const SkPaint::Align align = paint->getTextAlign();
348694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
349671d6cf460531825a321edb200523d0faa7792c9Romain Guy        // This is for renderPosText()
350671d6cf460531825a321edb200523d0faa7792c9Romain Guy        while (glyphsCount < numGlyphs) {
351671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyph_t glyph = GET_GLYPH(text);
352694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
353671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // Reached the end of the string
354671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (IS_END_OF_STRING(glyph)) {
355671d6cf460531825a321edb200523d0faa7792c9Romain Guy                break;
356671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
357671d6cf460531825a321edb200523d0faa7792c9Romain Guy
358671d6cf460531825a321edb200523d0faa7792c9Romain Guy            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
359671d6cf460531825a321edb200523d0faa7792c9Romain Guy
360671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
361671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (cachedGlyph->mIsValid) {
362671d6cf460531825a321edb200523d0faa7792c9Romain Guy                int penX = x + positions[(glyphsCount << 1)];
363671d6cf460531825a321edb200523d0faa7792c9Romain Guy                int penY = y + positions[(glyphsCount << 1) + 1];
364671d6cf460531825a321edb200523d0faa7792c9Romain Guy
365671d6cf460531825a321edb200523d0faa7792c9Romain Guy                switch (align) {
366671d6cf460531825a321edb200523d0faa7792c9Romain Guy                    case SkPaint::kRight_Align:
367671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX);
368671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY);
369671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        break;
370671d6cf460531825a321edb200523d0faa7792c9Romain Guy                    case SkPaint::kCenter_Align:
371671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1);
372671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1);
373671d6cf460531825a321edb200523d0faa7792c9Romain Guy                    default:
374671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        break;
375671d6cf460531825a321edb200523d0faa7792c9Romain Guy                }
376671d6cf460531825a321edb200523d0faa7792c9Romain Guy
377671d6cf460531825a321edb200523d0faa7792c9Romain Guy                (*this.*render)(cachedGlyph, penX, penY,
378671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        bitmap, bitmapW, bitmapH, bounds, positions);
379671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
380671d6cf460531825a321edb200523d0faa7792c9Romain Guy
381671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyphsCount++;
382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
38651769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) {
387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mAdvanceX = skiaGlyph.fAdvanceX;
388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mAdvanceY = skiaGlyph.fAdvanceY;
389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapLeft = skiaGlyph.fLeft;
390694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapTop = skiaGlyph.fTop;
3912bffd268f135df8308c9e67af110525a5c463424Romain Guy    glyph->mLsbDelta = skiaGlyph.fLsbDelta;
3922bffd268f135df8308c9e67af110525a5c463424Romain Guy    glyph->mRsbDelta = skiaGlyph.fRsbDelta;
393694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
394694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
395694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
396694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
397694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Get the bitmap for the glyph
398694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    paint->findImage(skiaGlyph);
3997de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY);
400694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
401694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!glyph->mIsValid) {
402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
403694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + skiaGlyph.fWidth;
406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + skiaGlyph.fHeight;
407694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
40889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    glyph->mStartX = startX;
40989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    glyph->mStartY = startY;
410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapWidth = skiaGlyph.fWidth;
411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapHeight = skiaGlyph.fHeight;
412694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4137de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth;
4147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight;
415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
416694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMinU = (float) startX / (float) cacheWidth;
417694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMinV = (float) startY / (float) cacheHeight;
418694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMaxU = (float) endX / (float) cacheWidth;
419694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMaxV = (float) endY / (float) cacheHeight;
420694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
42151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mState->mUploadTexture = true;
422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
423694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4247de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) {
42551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCachedGlyphs.add(glyph, newGlyph);
427694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
428726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    newGlyph->mGlyphIndex = skiaGlyph.fID;
430694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    newGlyph->mIsValid = false;
431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
432694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    updateGlyphCache(paint, skiaGlyph, newGlyph);
433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
434694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return newGlyph;
435694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
436694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4372577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
438bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        int flags, uint32_t italicStyle, uint32_t scaleX,
439bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        SkPaint::Style style, uint32_t strokeWidth) {
440694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Vector<Font*> &activeFonts = state->mActiveFonts;
441694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
442694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < activeFonts.size(); i++) {
44351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        Font* font = activeFonts[i];
4442577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy        if (font->mFontId == fontId && font->mFontSize == fontSize &&
4458668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase                font->mFlags == flags && font->mItalicStyle == italicStyle &&
446bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy                font->mScaleX == scaleX && font->mStyle == style &&
447bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy                (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
44851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy            return font;
449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
451694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
452bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
453bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy            scaleX, style, strokeWidth);
454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    activeFonts.push(newFont);
455694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return newFont;
456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
458694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
459694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer
460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
461694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
462514fb18827186591d66973c2362c859b64b63556Romain Guystatic bool sLogFontRendererCreate = true;
463514fb18827186591d66973c2362c859b64b63556Romain Guy
464694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() {
465c9855a53edfac818dc68714557185977556f849dRomain Guy    if (sLogFontRendererCreate) {
466c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("Creating FontRenderer");
467c9855a53edfac818dc68714557185977556f849dRomain Guy    }
46851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
469b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy    mGammaTable = NULL;
470694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = false;
471694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mMaxNumberOfQuads = 1024;
472694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentQuadIndex = 0;
473694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4749cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    mTextMeshPtr = NULL;
4757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCurrentCacheTexture = NULL;
4767de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mLastCacheTexture = NULL;
4777de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTextureSmall = NULL;
4787de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture128 = NULL;
4797de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture256 = NULL;
4807de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture512 = NULL;
4819cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy
4822a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    mLinearFiltering = false;
4832a47c14e2a6f152496b43104bc785c488583fd59Chet Haase
484694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mIndexBufferID = 0;
485694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4867de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
4877de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT;
48851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
48951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    char property[PROPERTY_VALUE_MAX];
49051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) {
491c9855a53edfac818dc68714557185977556f849dRomain Guy        if (sLogFontRendererCreate) {
492c9855a53edfac818dc68714557185977556f849dRomain Guy            INIT_LOGD("  Setting text cache width to %s pixels", property);
493c9855a53edfac818dc68714557185977556f849dRomain Guy        }
4947de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mSmallCacheWidth = atoi(property);
49551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    } else {
496514fb18827186591d66973c2362c859b64b63556Romain Guy        if (sLogFontRendererCreate) {
4977de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            INIT_LOGD("  Using default text cache width of %i pixels", mSmallCacheWidth);
498514fb18827186591d66973c2362c859b64b63556Romain Guy        }
49951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    }
50051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
50151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) {
502c9855a53edfac818dc68714557185977556f849dRomain Guy        if (sLogFontRendererCreate) {
503c9855a53edfac818dc68714557185977556f849dRomain Guy            INIT_LOGD("  Setting text cache width to %s pixels", property);
504c9855a53edfac818dc68714557185977556f849dRomain Guy        }
5057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mSmallCacheHeight = atoi(property);
50651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    } else {
507514fb18827186591d66973c2362c859b64b63556Romain Guy        if (sLogFontRendererCreate) {
5087de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            INIT_LOGD("  Using default text cache height of %i pixels", mSmallCacheHeight);
509514fb18827186591d66973c2362c859b64b63556Romain Guy        }
51051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    }
511514fb18827186591d66973c2362c859b64b63556Romain Guy
512514fb18827186591d66973c2362c859b64b63556Romain Guy    sLogFontRendererCreate = false;
513694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
514694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
515694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() {
516694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
517694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete mCacheLines[i];
518694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
519694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.clear();
520694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5219cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    if (mInitialized) {
5229cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy        delete[] mTextMeshPtr;
5237de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTextureSmall;
5247de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture128;
5257de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture256;
5267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture512;
5279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
528694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
529694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Vector<Font*> fontsToDereference = mActiveFonts;
530694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < fontsToDereference.size(); i++) {
531694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete fontsToDereference[i];
532694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
533694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() {
536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex != 0) {
537694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
538694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
539694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
540694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
541694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mActiveFonts[i]->invalidateTextureCache();
542694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
543694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
544694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCacheLines[i]->mCurrentCol = 0;
545694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
546694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
547694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5489a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) {
5499a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    if (cacheTexture && cacheTexture->mTexture) {
5509a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        glDeleteTextures(1, &cacheTexture->mTextureId);
5519a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        delete cacheTexture->mTexture;
5529a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        cacheTexture->mTexture = NULL;
5539a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    }
5549a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase}
5559a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
5569a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::flushLargeCaches() {
5579a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    if ((!mCacheTexture128 || !mCacheTexture128->mTexture) &&
5589a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            (!mCacheTexture256 || !mCacheTexture256->mTexture) &&
5599a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            (!mCacheTexture512 || !mCacheTexture512->mTexture)) {
5609a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        // Typical case; no large glyph caches allocated
5619a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        return;
5629a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    }
5639a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
5649a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
5659a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        CacheTextureLine* cacheLine = mCacheLines[i];
5669a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        if ((cacheLine->mCacheTexture == mCacheTexture128 ||
5679a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                cacheLine->mCacheTexture == mCacheTexture256 ||
5689a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                cacheLine->mCacheTexture == mCacheTexture512) &&
5699a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                cacheLine->mCacheTexture->mTexture != NULL) {
5709a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            cacheLine->mCurrentCol = 0;
5719a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
5729a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                mActiveFonts[i]->invalidateTextureCache(cacheLine);
5739a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            }
5749a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        }
5759a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    }
5769a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
5779a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    deallocateTextureMemory(mCacheTexture128);
5789a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    deallocateTextureMemory(mCacheTexture256);
5799a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    deallocateTextureMemory(mCacheTexture512);
5809a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase}
5819a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
5822a47c14e2a6f152496b43104bc785c488583fd59Chet Haasevoid FontRenderer::allocateTextureMemory(CacheTexture *cacheTexture) {
5832a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    int width = cacheTexture->mWidth;
5842a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    int height = cacheTexture->mHeight;
5852a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    cacheTexture->mTexture = new uint8_t[width * height];
5862a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    memset(cacheTexture->mTexture, 0, width * height * sizeof(uint8_t));
5872a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
5882a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
5892a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    // Initialize texture dimensions
5902a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
5912a47c14e2a6f152496b43104bc785c488583fd59Chet Haase            GL_ALPHA, GL_UNSIGNED_BYTE, 0);
5922a47c14e2a6f152496b43104bc785c488583fd59Chet Haase
5932a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    const GLenum filtering = cacheTexture->mLinearFiltering ? GL_LINEAR : GL_NEAREST;
5942a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
5952a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
5967de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
5972a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
5982a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5997de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase}
6007de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
6017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
6027de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        uint32_t* retOriginX, uint32_t* retOriginY) {
6037de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mIsValid = false;
604694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the glyph is too tall, don't cache it
6057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (glyph.fHeight + TEXTURE_BORDER_SIZE > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
6063762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Font size to large to fit in cache. width, height = %i, %i",
6077de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase                (int) glyph.fWidth, (int) glyph.fHeight);
6087de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        return;
609694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
610694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
611694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Now copy the bitmap into the cache texture
612694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
613694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
614694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
615694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    bool bitmapFit = false;
6167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    CacheTextureLine *cacheLine;
617694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
618694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
619694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (bitmapFit) {
6207de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            cacheLine = mCacheLines[i];
621694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
622694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
623694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
624694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
625694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the new glyph didn't fit, flush the state so far and invalidate everything
626694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!bitmapFit) {
627694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        flushAllAndInvalidate();
628694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
629694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // Try to fit it again
630694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        for (uint32_t i = 0; i < mCacheLines.size(); i++) {
631694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
632694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            if (bitmapFit) {
6337de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase                cacheLine = mCacheLines[i];
634694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                break;
635694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            }
636694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
637694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
638694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // if we still don't fit, something is wrong and we shouldn't draw
639694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (!bitmapFit) {
6407de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            return;
641694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
642694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
643694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6447de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mCachedTextureLine = cacheLine;
6457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
646694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginX = startX;
647694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginY = startY;
648694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
649694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + glyph.fWidth;
650694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + glyph.fHeight;
651694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6527de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheWidth = cacheLine->mMaxWidth;
653694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6547de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    CacheTexture *cacheTexture = cacheLine->mCacheTexture;
6557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (cacheTexture->mTexture == NULL) {
6567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        // Large-glyph texture memory is allocated only as needed
6572a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        allocateTextureMemory(cacheTexture);
6587de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
6597de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint8_t* cacheBuffer = cacheTexture->mTexture;
66089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
661694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    unsigned int stride = glyph.rowBytes();
662694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
663694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
664694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
665694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
66689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            uint8_t tempCol = bitmapBuffer[bY * stride + bX];
667b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy            cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
668694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
669694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
6709777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
6717de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mIsValid = true;
672694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
673694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
6757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    GLuint textureId;
6767de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    glGenTextures(1, &textureId);
6772a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    uint8_t* textureMemory = NULL;
678694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6792a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    CacheTexture* cacheTexture = new CacheTexture(textureMemory, textureId, width, height);
6802a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    if (allocate) {
6812a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        allocateTextureMemory(cacheTexture);
6822a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    }
6832a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    return cacheTexture;
6847de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase}
6857de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
6867de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::initTextTexture() {
6877de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.clear();
6887de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
6897de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    // Next, use other, separate caches for large glyphs.
6907de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint16_t maxWidth = 0;
6917de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (Caches::hasInstance()) {
6927de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        maxWidth = Caches::getInstance().maxTextureSize;
6937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
6947de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) {
6957de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        maxWidth = MAX_TEXT_CACHE_WIDTH;
6967de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
6977de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (mCacheTextureSmall != NULL) {
6987de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTextureSmall;
6997de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture128;
7007de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture256;
7017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture512;
7027de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
7037de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true);
7047de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture128 = createCacheTexture(maxWidth, 256, false);
7057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture256 = createCacheTexture(maxWidth, 256, false);
7067de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture512 = createCacheTexture(maxWidth, 512, false);
7077de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCurrentCacheTexture = mCacheTextureSmall;
7087de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
7097de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mUploadTexture = false;
7107de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    // Split up our default cache texture into lines of certain widths
711694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nextLine = 0;
7127de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, 0, mCacheTextureSmall));
713694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
7147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall));
715694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
7167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall));
71765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
7187de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall));
719694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
7207de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall));
721694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
7227de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, 0, mCacheTextureSmall));
723694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
7247de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine,
7257de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            nextLine, 0, mCacheTextureSmall));
7267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
7277de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    //  The first cache is split into 2 lines of height 128, the rest have just one cache line.
7287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, 0, mCacheTexture128));
7297de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, 0, mCacheTexture128));
7307de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, 0, mCacheTexture256));
7317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, 0, mCacheTexture512));
732694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
733694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
734694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad
735694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() {
736d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    uint32_t numIndices = mMaxNumberOfQuads * 6;
737d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t);
73851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
739694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
740694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Four verts, two triangles , six indices per quad
741694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) {
742694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int i6 = i * 6;
743694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int i4 = i * 4;
744694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
745694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 0] = i4 + 0;
746694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 1] = i4 + 1;
747694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 2] = i4 + 2;
748694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
749694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 3] = i4 + 0;
750694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 4] = i4 + 2;
751694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 5] = i4 + 3;
752694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
753694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
754694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glGenBuffers(1, &mIndexBufferID);
75515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    Caches::getInstance().bindIndicesBuffer(mIndexBufferID);
7565d794412e3e429e47404395badcd11b0b8639e8bRomain Guy    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW);
757694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
758694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    free(indexBufferData);
759694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
760d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    uint32_t coordSize = 2;
761694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t uvSize = 2;
762694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t vertsPerQuad = 4;
7639b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize;
7649b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mTextMeshPtr = new float[vertexBufferSize];
765694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
766694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
767694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text
768694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() {
769694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mInitialized) {
770694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
771694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
772694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
773694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initTextTexture();
774694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initVertexArrayBuffers();
775694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
77665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    // We store a string with letters in a rough frequency of occurrence
77765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq ");
77865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ");
77965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    mLatinPrecache += String16(",.?!()-+@;:`'");
78065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    mLatinPrecache += String16("0123456789");
78165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
782694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = true;
783694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
784694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
7859b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() {
7867de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) {
7879b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        return;
7889b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
7899b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
7902d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    Caches& caches = Caches::getInstance();
7912d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    GLuint lastTextureId = 0;
7929b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    // Iterate over all the cache lines and see which ones need to be updated
7939b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
7949b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        CacheTextureLine* cl = mCacheLines[i];
7957de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) {
7967de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            CacheTexture* cacheTexture = cl->mCacheTexture;
7979b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t xOffset = 0;
7989b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t yOffset = cl->mCurrentRow;
7997de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            uint32_t width   = cl->mMaxWidth;
8009b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t height  = cl->mMaxHeight;
8017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            void* textureData = cacheTexture->mTexture + (yOffset * width);
8029b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
8032d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy            if (cacheTexture->mTextureId != lastTextureId) {
8042d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy                caches.activeTexture(0);
8052d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy                glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
8062d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy                lastTextureId = cacheTexture->mTextureId;
8072d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy            }
8089b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
8091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy                    GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
8109b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
8119b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            cl->mDirty = false;
8129b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        }
813694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
814694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId);
8162a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    if (mLinearFiltering != mCurrentCacheTexture->mLinearFiltering) {
8172a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        const GLenum filtering = mLinearFiltering ? GL_LINEAR : GL_NEAREST;
8182a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
8192a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
8202a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        mCurrentCacheTexture->mLinearFiltering = mLinearFiltering;
8212a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    }
8227de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mLastCacheTexture = mCurrentCacheTexture;
8237de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
8249b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mUploadTexture = false;
8259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk}
8269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
8279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() {
8289b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    checkTextureUpdate();
8299b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
83015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    Caches& caches = Caches::getInstance();
8312d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    caches.bindIndicesBuffer(mIndexBufferID);
83215bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    if (!mDrawn) {
83315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        float* buffer = mTextMeshPtr;
83415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        int offset = 2;
83515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
83615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        bool force = caches.unbindMeshBuffer();
83715bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        caches.bindPositionVertexPointer(force, caches.currentProgram->position, buffer);
83815bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        caches.bindTexCoordsVertexPointer(force, caches.currentProgram->texCoords,
83915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy                buffer + offset);
84015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    }
84115bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
842694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
8435b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
8445b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mDrawn = true;
845694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
846694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8479777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
8489777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
8497de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        float x4, float y4, float u4, float v4, CacheTexture* texture) {
8507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (texture != mCurrentCacheTexture) {
8517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        if (mCurrentQuadIndex != 0) {
8527de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            // First, draw everything stored already which uses the previous texture
8537de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            issueDrawCommand();
8547de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            mCurrentQuadIndex = 0;
8557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        }
8567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        // Now use the new texture id
8577de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mCurrentCacheTexture = texture;
8587de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
85909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy
860694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    const uint32_t vertsPerQuad = 4;
861d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    const uint32_t floatsPerVert = 4;
86251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
863694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
864694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x1;
865694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y1;
866694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u1;
867694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v1;
868694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
869694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x2;
870694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y2;
871694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u2;
872694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v2;
873694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
874694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x3;
875694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y3;
876694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u3;
877694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v3;
878694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
879694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x4;
880694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y4;
881694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u4;
882694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v4;
883694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
884694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentQuadIndex++;
8859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
8869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
8879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
8889777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
8899777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x4, float y4, float u4, float v4, CacheTexture* texture) {
8909777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
8919777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mClip &&
8929777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
8939777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return;
8949777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
8959777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
8969777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
897694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8985b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    if (mBounds) {
8995b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->left = fmin(mBounds->left, x1);
9005b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->top = fmin(mBounds->top, y3);
9015b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->right = fmax(mBounds->right, x3);
9025b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->bottom = fmax(mBounds->bottom, y1);
9035b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
9045b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
905694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
906694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
907694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
908694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
909694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
910694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
9119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
9129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
9139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x4, float y4, float u4, float v4, CacheTexture* texture) {
9149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
9159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
9169777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
9179777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mBounds) {
9189777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
9199777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
9209777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
9219777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
9229777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
9239777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
9249777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
9259777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        issueDrawCommand();
9269777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mCurrentQuadIndex = 0;
9279777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
9289777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
9299777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
93065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukuint32_t FontRenderer::getRemainingCacheCapacity() {
93165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t remainingCapacity = 0;
93265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    float totalPixels = 0;
93365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
93465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
93565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk         totalPixels += mCacheLines[i]->mMaxWidth;
93665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
93765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    remainingCapacity = (remainingCapacity * 100) / totalPixels;
93865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    return remainingCapacity;
93965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk}
94065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
94165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::precacheLatin(SkPaint* paint) {
94265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    // Remaining capacity is measured in %
94365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t remainingCapacity = getRemainingCacheCapacity();
94465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t precacheIdx = 0;
945054dc1840941665e32036f9523df51720ad069c8Romain Guy    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
946726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        mCurrentFont->getCachedGlyph(paint, (int32_t) mLatinPrecache[precacheIdx]);
94765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        remainingCapacity = getRemainingCacheCapacity();
94865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        precacheIdx ++;
94965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
95065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk}
95165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
95265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) {
95365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    uint32_t currentNumFonts = mActiveFonts.size();
954325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    int flags = 0;
955325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    if (paint->isFakeBoldText()) {
956325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy        flags |= Font::kFakeBold;
957325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    }
9582577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy
9592577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy    const float skewX = paint->getTextSkewX();
9602577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy    uint32_t italicStyle = *(uint32_t*) &skewX;
9618668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase    const float scaleXFloat = paint->getTextScaleX();
9628668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase    uint32_t scaleX = *(uint32_t*) &scaleXFloat;
963bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    SkPaint::Style style = paint->getStyle();
964bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    const float strokeWidthFloat = paint->getStrokeWidth();
965bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
966bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle,
967bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy            scaleX, style, strokeWidth);
96865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
96965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    const float maxPrecacheFontSize = 40.0f;
97065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    bool isNewFont = currentNumFonts != mActiveFonts.size();
97165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
9722bffd268f135df8308c9e67af110525a5c463424Romain Guy    if (isNewFont && fontSize <= maxPrecacheFontSize) {
97365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        precacheLatin(paint);
97465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
975694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
9767975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy
977f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
9781e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) {
9791e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    checkInit();
9801e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
9811e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    if (!mCurrentFont) {
9821e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        DropShadow image;
9831e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.width = 0;
9841e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.height = 0;
9851e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.image = NULL;
9861e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.penX = 0;
9871e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.penY = 0;
9881e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        return image;
9891e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    }
990f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
9912d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    mDrawn = false;
992ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy    mClip = NULL;
993ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy    mBounds = NULL;
994ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
995f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    Rect bounds;
996726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds);
997ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
9981e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
9991e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
1000f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight];
1001ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
10021e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) {
1003f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        dataBuffer[i] = 0;
1004f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
10051e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
1006f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int penX = radius - bounds.left;
1007f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int penY = radius - bounds.bottom;
1008f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
1009726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
10101e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy            dataBuffer, paddedWidth, paddedHeight);
1011f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    blurImage(dataBuffer, paddedWidth, paddedHeight, radius);
1012f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
1013f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    DropShadow image;
1014f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.width = paddedWidth;
1015f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.height = paddedHeight;
1016f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.image = dataBuffer;
1017f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.penX = penX;
1018f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.penY = penY;
10192d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy
1020f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    return image;
1021f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
1022694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1023671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::initRender(const Rect* clip, Rect* bounds) {
1024694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    checkInit();
1025694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
10265b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mDrawn = false;
10275b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mBounds = bounds;
102809147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy    mClip = clip;
1029671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
1030ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
1031671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::finishRender() {
10325b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mBounds = NULL;
1033ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy    mClip = NULL;
1034694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1035694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex != 0) {
1036694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
1037694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
1038694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
1039671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
1040671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1041671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
1042671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) {
1043671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (!mCurrentFont) {
1044671d6cf460531825a321edb200523d0faa7792c9Romain Guy        ALOGE("No font set");
1045671d6cf460531825a321edb200523d0faa7792c9Romain Guy        return false;
1046671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
1047671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1048671d6cf460531825a321edb200523d0faa7792c9Romain Guy    initRender(clip, bounds);
1049671d6cf460531825a321edb200523d0faa7792c9Romain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y);
1050671d6cf460531825a321edb200523d0faa7792c9Romain Guy    finishRender();
1051671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1052671d6cf460531825a321edb200523d0faa7792c9Romain Guy    return mDrawn;
1053671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
1054671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1055671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
1056671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
1057671d6cf460531825a321edb200523d0faa7792c9Romain Guy        const float* positions, Rect* bounds) {
1058671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (!mCurrentFont) {
1059671d6cf460531825a321edb200523d0faa7792c9Romain Guy        ALOGE("No font set");
1060671d6cf460531825a321edb200523d0faa7792c9Romain Guy        return false;
1061671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
1062671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1063671d6cf460531825a321edb200523d0faa7792c9Romain Guy    initRender(clip, bounds);
1064671d6cf460531825a321edb200523d0faa7792c9Romain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
1065671d6cf460531825a321edb200523d0faa7792c9Romain Guy    finishRender();
10665b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
10675b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    return mDrawn;
10689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
10699777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
10709777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guybool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text,
10719777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path,
10729777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float hOffset, float vOffset, Rect* bounds) {
10739777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (!mCurrentFont) {
10749777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        ALOGE("No font set");
10759777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return false;
10769777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
10779777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
10789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    initRender(clip, bounds);
10799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
10809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    finishRender();
10819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
10829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    return mDrawn;
1083694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
1084694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
108589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
108689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Compute gaussian weights for the blur
108789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // e is the euler's number
108889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float e = 2.718281828459045f;
108989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float pi = 3.1415926535897932f;
109089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
109189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // x is of the form [-radius .. 0 .. radius]
109289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // and sigma varies with radius.
109389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Based on some experimental radius values and sigma's
109489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // we approximately fit sigma = f(radius) as
1095f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    // sigma = radius * 0.3  + 0.6
109689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // The larger the radius gets, the more our gaussian blur
109789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // will resemble a box blur since with large sigma
109889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // the gaussian curve begins to lose its shape
1099325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    float sigma = 0.3f * (float) radius + 0.6f;
110089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
110189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Now compute the coefficints
110289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // We will store some redundant values to save some math during
110389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // the blur calculations
110489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // precompute some values
110589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
110689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
110789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
110889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float normalizeFactor = 0.0f;
1109325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t r = -radius; r <= radius; r ++) {
11107975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy        float floatR = (float) r;
111189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
111289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        normalizeFactor += weights[r + radius];
111389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
111489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
111589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    //Now we need to normalize the weights because all our coefficients need to add up to one
111689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    normalizeFactor = 1.0f / normalizeFactor;
1117325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t r = -radius; r <= radius; r ++) {
111889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        weights[r + radius] *= normalizeFactor;
111989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
112089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
112189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
112289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius,
11231e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
112489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float blurredPixel = 0.0f;
112589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float currentPixel = 0.0f;
112689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1127325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t y = 0; y < height; y ++) {
112889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
112989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        const uint8_t* input = source + y * width;
113089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        uint8_t* output = dest + y * width;
113189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1132325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy        for (int32_t x = 0; x < width; x ++) {
113389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            blurredPixel = 0.0f;
113489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const float* gPtr = weights;
113589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            // Optimization for non-border pixels
1136325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy            if (x > radius && x < (width - radius)) {
113789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                const uint8_t *i = input + (x - radius);
1138325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int r = -radius; r <= radius; r ++) {
11397975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy                    currentPixel = (float) (*i);
114089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
114189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
114289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    i++;
114389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
114489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            } else {
1145325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int32_t r = -radius; r <= radius; r ++) {
114689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    // Stepping left and right away from the pixel
114789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    int validW = x + r;
1148325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validW < 0) {
114989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validW = 0;
115089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
1151325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validW > width - 1) {
115289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validW = width - 1;
115389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
115489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1155325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    currentPixel = (float) input[validW];
115689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
115789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
115889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
115989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
116089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            *output = (uint8_t)blurredPixel;
116189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            output ++;
116289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
116389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
116489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
116589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
116689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius,
11671e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
116889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float blurredPixel = 0.0f;
116989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float currentPixel = 0.0f;
117089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1171325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t y = 0; y < height; y ++) {
117289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
117389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        uint8_t* output = dest + y * width;
117489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1175325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy        for (int32_t x = 0; x < width; x ++) {
117689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            blurredPixel = 0.0f;
117789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const float* gPtr = weights;
117889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const uint8_t* input = source + x;
117989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            // Optimization for non-border pixels
1180325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy            if (y > radius && y < (height - radius)) {
118189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                const uint8_t *i = input + ((y - radius) * width);
1182325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int32_t r = -radius; r <= radius; r ++) {
118389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    currentPixel = (float)(*i);
118489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
118589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
118689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    i += width;
118789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
118889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            } else {
1189325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int32_t r = -radius; r <= radius; r ++) {
119089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    int validH = y + r;
119189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    // Clamp to zero and width
1192325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validH < 0) {
119389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validH = 0;
119489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
1195325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validH > height - 1) {
119689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validH = height - 1;
119789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
119889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
119989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    const uint8_t *i = input + validH * width;
1200325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    currentPixel = (float) (*i);
120189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
120289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
120389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
120489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
1205325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy            *output = (uint8_t) blurredPixel;
120689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            output ++;
120789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
120889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
120989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
121089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
121189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
121289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) {
121389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float *gaussian = new float[2 * radius + 1];
121489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    computeGaussianWeights(gaussian, radius);
1215d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
121689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint8_t* scratch = new uint8_t[width * height];
1217d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
121889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    horizontalBlur(gaussian, radius, image, scratch, width, height);
121989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    verticalBlur(gaussian, radius, scratch, image, width, height);
1220d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
122189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    delete[] gaussian;
122289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    delete[] scratch;
122389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
122489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1225694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer
1226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android
1227