FontRenderer.cpp revision e816baea651476aca4407200d4a5e629b9ab8dfa
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
40e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#define CACHE_BLOCK_ROUNDING_SIZE 4
417de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy#define AUTO_KERN(prev, next) (((next) - (prev) + 32) >> 6 << 16)
439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
447de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase///////////////////////////////////////////////////////////////////////////////
45e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase// CacheBlock
46e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase///////////////////////////////////////////////////////////////////////////////
47e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
48e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase/**
49e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase * Insert new block into existing linked list of blocks. Blocks are sorted in increasing-width
50e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase * order, except for the final block (the remainder space at the right, since we fill from the
51e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase * left).
52e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase */
53e816baea651476aca4407200d4a5e629b9ab8dfaChet HaaseCacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock *newBlock) {
54e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER
55e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
56e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            newBlock, newBlock->mX, newBlock->mY,
57e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            newBlock->mWidth, newBlock->mHeight);
58e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif
59e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    CacheBlock *currBlock = head;
60e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    CacheBlock *prevBlock = NULL;
61e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) {
62e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        if (newBlock->mWidth < currBlock->mWidth) {
63e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            newBlock->mNext = currBlock;
64e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            newBlock->mPrev = prevBlock;
65e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            currBlock->mPrev = newBlock;
66e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            if (prevBlock) {
67e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                prevBlock->mNext = newBlock;
68e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                return head;
69e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            } else {
70e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                return newBlock;
71e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            }
72e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        }
73e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        prevBlock = currBlock;
74e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        currBlock = currBlock->mNext;
75e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
76e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    // new block larger than all others - insert at end (but before the remainder space, if there)
77e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    newBlock->mNext = currBlock;
78e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    newBlock->mPrev = prevBlock;
79e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (currBlock) {
80e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        currBlock->mPrev = newBlock;
81e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
82e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (prevBlock) {
83e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        prevBlock->mNext = newBlock;
84e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        return head;
85e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    } else {
86e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        return newBlock;
87e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
88e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase}
89e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
90e816baea651476aca4407200d4a5e629b9ab8dfaChet HaaseCacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock *blockToRemove) {
91e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER
92e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
93e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            blockToRemove, blockToRemove->mX, blockToRemove->mY,
94e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            blockToRemove->mWidth, blockToRemove->mHeight);
95e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif
96e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    CacheBlock* newHead = head;
97e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    CacheBlock* nextBlock = blockToRemove->mNext;
98e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    CacheBlock* prevBlock = blockToRemove->mPrev;
99e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (prevBlock) {
100e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        prevBlock->mNext = nextBlock;
101e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    } else {
102e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        newHead = nextBlock;
103e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
104e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (nextBlock) {
105e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        nextBlock->mPrev = prevBlock;
106e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
107e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    delete blockToRemove;
108e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    return newHead;
109e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase}
110e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
111e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase///////////////////////////////////////////////////////////////////////////////
1127de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase// CacheTextureLine
1137de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase///////////////////////////////////////////////////////////////////////////////
1147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
1157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasebool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
1167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) {
1177de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        return false;
1187de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
1197de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
120e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    uint16_t glyphW = glyph.fWidth + TEXTURE_BORDER_SIZE;
121e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    uint16_t glyphH = glyph.fHeight + TEXTURE_BORDER_SIZE;
122e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    // roundedUpW equals glyphW to the next multiple of CACHE_BLOCK_ROUNDING_SIZE.
123e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    // This columns for glyphs that are close but not necessarily exactly the same size. It trades
124e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    // off the loss of a few pixels for some glyphs against the ability to store more glyphs
125e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    // of varying sizes in one block.
126e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    uint16_t roundedUpW =
127e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            (glyphW + CACHE_BLOCK_ROUNDING_SIZE - 1) & -CACHE_BLOCK_ROUNDING_SIZE;
128e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    CacheBlock *cacheBlock = mCacheBlocks;
129e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    while (cacheBlock) {
130e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        // Store glyph in this block iff: it fits the block's remaining space and:
131e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        // it's the remainder space (mY == 0) or there's only enough height for this one glyph
132e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        // or it's within ROUNDING_SIZE of the block width
133e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight &&
134e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
135e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                        (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
136e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            if (cacheBlock->mHeight - glyphH < glyphH) {
137e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                // Only enough space for this glyph - don't bother rounding up the width
138e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                roundedUpW = glyphW;
139e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            }
140e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            *retOriginX = cacheBlock->mX;
141e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            *retOriginY = mCurrentRow + cacheBlock->mY;
142e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            // If this is the remainder space, create a new cache block for this column. Otherwise,
143e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            // adjust the info about this column.
144e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            if (cacheBlock->mY == TEXTURE_BORDER_SIZE) {
145e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                uint16_t oldX = cacheBlock->mX;
146e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                // Adjust remainder space dimensions
147e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                cacheBlock->mWidth -= roundedUpW;
148e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                cacheBlock->mX += roundedUpW;
149e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                if (mMaxHeight - glyphH >= glyphH) {
150e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                    // There's enough height left over to create a new CacheBlock
151e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                    CacheBlock *newBlock = new CacheBlock(oldX, glyphH, roundedUpW,
152e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                            mMaxHeight - glyphH);
153e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER
154e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                    ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
155e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                            newBlock, newBlock->mX, newBlock->mY,
156e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                            newBlock->mWidth, newBlock->mHeight);
157e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif
158e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                    mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock);
159e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                }
160e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            } else {
161e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                // Insert into current column and adjust column dimensions
162e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                cacheBlock->mY += glyphH;
163e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                cacheBlock->mHeight -= glyphH;
164e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER
165e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d",
166e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                        cacheBlock, cacheBlock->mX, cacheBlock->mY,
167e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                        cacheBlock->mWidth, cacheBlock->mHeight);
168e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif
169e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            }
170e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            if (cacheBlock->mHeight < fmin(glyphH, glyphW)) {
171e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                // If remaining space in this block is too small to be useful, remove it
172e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                mCacheBlocks = CacheBlock::removeBlock(mCacheBlocks, cacheBlock);
173e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            }
174e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            mDirty = true;
175e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER
176e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            ALOGD("fitBitmap: current block list:");
177e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            mCacheBlocks->output();
178e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif
179e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            ++mNumGlyphs;
180e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            return true;
181e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        }
182e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        cacheBlock = cacheBlock->mNext;
1837de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
184e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER
185e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    ALOGD("fitBitmap: returning false for glyph of size %d, %d", glyphW, glyphH);
186e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif
1877de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    return false;
1887de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase}
18944984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase
19051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy///////////////////////////////////////////////////////////////////////////////
191694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Font
192694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
193694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1942577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize,
195bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        int flags, uint32_t italicStyle, uint32_t scaleX,
196bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        SkPaint::Style style, uint32_t strokeWidth) :
1972577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy        mState(state), mFontId(fontId), mFontSize(fontSize),
198bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
199bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        mStyle(style), mStrokeWidth(mStrokeWidth) {
200694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
201694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
202694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
203694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::~Font() {
204694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) {
205694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (mState->mActiveFonts[ct] == this) {
206694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            mState->mActiveFonts.removeAt(ct);
207694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
208694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
209694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
210694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
211694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
212726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        delete mCachedGlyphs.valueAt(i);
213694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
214694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
215694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
2169a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid Font::invalidateTextureCache(CacheTextureLine *cacheLine) {
217694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
2189a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
2199a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        if (cacheLine == NULL || cachedGlyph->mCachedTextureLine == cacheLine) {
2209a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            cachedGlyph->mIsValid = false;
2219a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        }
222694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
223694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
224694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
225671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
226671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
227f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int nPenX = x + glyph->mBitmapLeft;
228f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int nPenY = y + glyph->mBitmapTop;
229f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
230f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int width = (int) glyph->mBitmapWidth;
231f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int height = (int) glyph->mBitmapHeight;
232f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
23361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds->bottom > nPenY) {
234f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->bottom = nPenY;
235f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
23661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds->left > nPenX) {
237f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->left = nPenX;
238f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
23961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds->right < nPenX + width) {
240f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->right = nPenX + width;
241f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
24261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds->top < nPenY + height) {
243f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        bounds->top = nPenY + height;
244f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
245f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
246f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
247671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
248671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nPenX = x + glyph->mBitmapLeft;
250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
251694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
25251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float u1 = glyph->mBitmapMinU;
25351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float u2 = glyph->mBitmapMaxU;
25451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float v1 = glyph->mBitmapMinV;
25551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float v2 = glyph->mBitmapMaxV;
25651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
25751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    int width = (int) glyph->mBitmapWidth;
25851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    int height = (int) glyph->mBitmapHeight;
25951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
260d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    mState->appendMeshQuad(nPenX, nPenY, u1, v2,
261d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy            nPenX + width, nPenY, u2, v2,
262d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy            nPenX + width, nPenY - height, u2, v1,
2637de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture);
264694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
265694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
266671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
267671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
26889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    int nPenX = x + glyph->mBitmapLeft;
26989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    int nPenY = y + glyph->mBitmapTop;
27089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
27189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
27289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
27389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
2747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture;
2757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheWidth = cacheTexture->mWidth;
2767de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    const uint8_t* cacheBuffer = cacheTexture->mTexture;
27789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
278f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    uint32_t cacheX = 0, cacheY = 0;
279f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int32_t bX = 0, bY = 0;
28089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
28189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
282b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy#if DEBUG_FONT_RENDERER
283b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
2843762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Skipping invalid index");
285f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                continue;
286f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            }
287b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy#endif
28889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
28989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            bitmap[bY * bitmapW + bX] = tempCol;
29089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
29189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
29289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
29389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
2949777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
2959777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
2969777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    const float halfWidth = glyph->mBitmapWidth * 0.5f;
2979777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    const float height = glyph->mBitmapHeight;
2989777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
2999777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    vOffset += glyph->mBitmapTop + height;
3009777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkPoint destination[4];
302dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    measure.getPosTan(x + hOffset +  glyph->mBitmapLeft + halfWidth, position, tangent);
3039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    // Move along the tangent and offset by the normal
3059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
3069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            -tangent->fY * halfWidth + tangent->fX * vOffset);
3079777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset,
3089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            tangent->fY * halfWidth + tangent->fX * vOffset);
3099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[2].set(destination[1].fX + tangent->fY * height,
3109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            destination[1].fY - tangent->fX * height);
3119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    destination[3].set(destination[0].fX + tangent->fY * height,
3129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            destination[0].fY - tangent->fX * height);
3139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
314dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    const float u1 = glyph->mBitmapMinU;
315dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    const float u2 = glyph->mBitmapMaxU;
316dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    const float v1 = glyph->mBitmapMinV;
317dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    const float v2 = glyph->mBitmapMaxV;
318dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy
3199777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    mState->appendRotatedMeshQuad(
3209777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[0].fX,
3219777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[0].fY, u1, v2,
3229777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[1].fX,
3239777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[1].fY, u2, v2,
3249777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[2].fX,
3259777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[2].fY, u2, v1,
3269777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fX + destination[3].fX,
3279777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            position->fY + destination[3].fY, u1, v1,
3289777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            glyph->mCachedTextureLine->mCacheTexture);
3299777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
3309777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
3321e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    CachedGlyphInfo* cachedGlyph = NULL;
333726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
3341e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    if (index >= 0) {
3351e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        cachedGlyph = mCachedGlyphs.valueAt(index);
3361e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    } else {
337726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        cachedGlyph = cacheGlyph(paint, textUnit);
33865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
33965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
34065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    // Is the glyph still in texture cache?
34165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    if (!cachedGlyph->mIsValid) {
342726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
34365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        updateGlyphCache(paint, skiaGlyph, cachedGlyph);
34465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
34565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
34665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    return cachedGlyph;
34765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk}
34865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
349726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
35061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
35161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
352726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
353671d6cf460531825a321edb200523d0faa7792c9Romain Guy                bitmapW, bitmapH, NULL, NULL);
35461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    } else {
355726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
356671d6cf460531825a321edb200523d0faa7792c9Romain Guy                0, 0, NULL, NULL);
357f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
358f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
359f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
360671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
361671d6cf460531825a321edb200523d0faa7792c9Romain Guy            int numGlyphs, int x, int y, const float* positions) {
362671d6cf460531825a321edb200523d0faa7792c9Romain Guy    render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
363671d6cf460531825a321edb200523d0faa7792c9Romain Guy            0, 0, NULL, positions);
364671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
365671d6cf460531825a321edb200523d0faa7792c9Romain Guy
3669777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
3679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        int numGlyphs, SkPath* path, float hOffset, float vOffset) {
3689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (numGlyphs == 0 || text == NULL || len == 0) {
3699777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return;
3709777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
3719777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3729777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    text += start;
3739777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3749777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    int glyphsCount = 0;
3759777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkFixed prevRsbDelta = 0;
3769777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3779777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    float penX = 0.0f;
3789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkPoint position;
3809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkVector tangent;
3819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    SkPathMeasure measure(*path, false);
3839777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    float pathLength = SkScalarToFloat(measure.getLength());
3849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (paint->getTextAlign() != SkPaint::kLeft_Align) {
3869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float textWidth = SkScalarToFloat(paint->measureText(text, len));
3879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float pathOffset = pathLength;
3889777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (paint->getTextAlign() == SkPaint::kCenter_Align) {
3899777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            textWidth *= 0.5f;
3909777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            pathOffset *= 0.5f;
3919777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
3929777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        penX += pathOffset - textWidth;
3939777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
3949777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
395dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy    while (glyphsCount < numGlyphs && penX < pathLength) {
3969777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        glyph_t glyph = GET_GLYPH(text);
3979777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3989777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (IS_END_OF_STRING(glyph)) {
3999777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            break;
4009777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
4019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
4029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
4039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
4049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        prevRsbDelta = cachedGlyph->mRsbDelta;
4059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
4069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (cachedGlyph->mIsValid) {
407dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy            drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent);
4089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
4099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
4109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
4119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
4129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        glyphsCount++;
4139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
4149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
4159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
416726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
417416a847633680d94efb926837efdc18726d54918Raph Levien        int numGlyphs, Rect *bounds, const float* positions) {
41861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    if (bounds == NULL) {
4193762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("No return rectangle provided to measure text");
420f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        return;
421f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
422f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    bounds->set(1e6, -1e6, -1e6, 1e6);
423416a847633680d94efb926837efdc18726d54918Raph Levien    render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions);
424f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
425f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
426e816baea651476aca4407200d4a5e629b9ab8dfaChet Haasevoid Font::precache(SkPaint* paint, const char* text, int numGlyphs) {
427e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
428e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (numGlyphs == 0 || text == NULL) {
429e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        return;
430e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
431e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    int glyphsCount = 0;
432e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
433e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    while (glyphsCount < numGlyphs) {
434e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        glyph_t glyph = GET_GLYPH(text);
435e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
436e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        // Reached the end of the string
437e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        if (IS_END_OF_STRING(glyph)) {
438e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            break;
439e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        }
440e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
441e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
442e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
443e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        glyphsCount++;
444e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
445e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase}
446e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
447726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
44861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
4499777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (numGlyphs == 0 || text == NULL || len == 0) {
451694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
452694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
453694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
454671d6cf460531825a321edb200523d0faa7792c9Romain Guy    static RenderGlyph gRenderGlyph[] = {
455671d6cf460531825a321edb200523d0faa7792c9Romain Guy            &android::uirenderer::Font::drawCachedGlyph,
456671d6cf460531825a321edb200523d0faa7792c9Romain Guy            &android::uirenderer::Font::drawCachedGlyphBitmap,
457671d6cf460531825a321edb200523d0faa7792c9Romain Guy            &android::uirenderer::Font::measureCachedGlyph
458671d6cf460531825a321edb200523d0faa7792c9Romain Guy    };
459671d6cf460531825a321edb200523d0faa7792c9Romain Guy    RenderGlyph render = gRenderGlyph[mode];
460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4619777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    text += start;
4629777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    int glyphsCount = 0;
4639777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
464b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy    if (CC_LIKELY(positions == NULL)) {
465671d6cf460531825a321edb200523d0faa7792c9Romain Guy        SkFixed prevRsbDelta = 0;
466694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float penX = x + 0.5f;
468671d6cf460531825a321edb200523d0faa7792c9Romain Guy        int penY = y;
469694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
470671d6cf460531825a321edb200523d0faa7792c9Romain Guy        while (glyphsCount < numGlyphs) {
471671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyph_t glyph = GET_GLYPH(text);
472671d6cf460531825a321edb200523d0faa7792c9Romain Guy
473671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // Reached the end of the string
474671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (IS_END_OF_STRING(glyph)) {
475f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                break;
47689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
477671d6cf460531825a321edb200523d0faa7792c9Romain Guy
478671d6cf460531825a321edb200523d0faa7792c9Romain Guy            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
4799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
480671d6cf460531825a321edb200523d0faa7792c9Romain Guy            prevRsbDelta = cachedGlyph->mRsbDelta;
481671d6cf460531825a321edb200523d0faa7792c9Romain Guy
482671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
483671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (cachedGlyph->mIsValid) {
484671d6cf460531825a321edb200523d0faa7792c9Romain Guy                (*this.*render)(cachedGlyph, (int) floorf(penX), penY,
485671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        bitmap, bitmapW, bitmapH, bounds, positions);
486671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
487671d6cf460531825a321edb200523d0faa7792c9Romain Guy
488671d6cf460531825a321edb200523d0faa7792c9Romain Guy            penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
489671d6cf460531825a321edb200523d0faa7792c9Romain Guy
490671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyphsCount++;
491694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
492671d6cf460531825a321edb200523d0faa7792c9Romain Guy    } else {
493671d6cf460531825a321edb200523d0faa7792c9Romain Guy        const SkPaint::Align align = paint->getTextAlign();
494694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
495671d6cf460531825a321edb200523d0faa7792c9Romain Guy        // This is for renderPosText()
496671d6cf460531825a321edb200523d0faa7792c9Romain Guy        while (glyphsCount < numGlyphs) {
497671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyph_t glyph = GET_GLYPH(text);
498694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
499671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // Reached the end of the string
500671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (IS_END_OF_STRING(glyph)) {
501671d6cf460531825a321edb200523d0faa7792c9Romain Guy                break;
502671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
503671d6cf460531825a321edb200523d0faa7792c9Romain Guy
504671d6cf460531825a321edb200523d0faa7792c9Romain Guy            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
505671d6cf460531825a321edb200523d0faa7792c9Romain Guy
506671d6cf460531825a321edb200523d0faa7792c9Romain Guy            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
507671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (cachedGlyph->mIsValid) {
508671d6cf460531825a321edb200523d0faa7792c9Romain Guy                int penX = x + positions[(glyphsCount << 1)];
509671d6cf460531825a321edb200523d0faa7792c9Romain Guy                int penY = y + positions[(glyphsCount << 1) + 1];
510671d6cf460531825a321edb200523d0faa7792c9Romain Guy
511671d6cf460531825a321edb200523d0faa7792c9Romain Guy                switch (align) {
512671d6cf460531825a321edb200523d0faa7792c9Romain Guy                    case SkPaint::kRight_Align:
513671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX);
514671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY);
515671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        break;
516671d6cf460531825a321edb200523d0faa7792c9Romain Guy                    case SkPaint::kCenter_Align:
517671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1);
518671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1);
519671d6cf460531825a321edb200523d0faa7792c9Romain Guy                    default:
520671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        break;
521671d6cf460531825a321edb200523d0faa7792c9Romain Guy                }
522671d6cf460531825a321edb200523d0faa7792c9Romain Guy
523671d6cf460531825a321edb200523d0faa7792c9Romain Guy                (*this.*render)(cachedGlyph, penX, penY,
524671d6cf460531825a321edb200523d0faa7792c9Romain Guy                        bitmap, bitmapW, bitmapH, bounds, positions);
525671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
526671d6cf460531825a321edb200523d0faa7792c9Romain Guy
527671d6cf460531825a321edb200523d0faa7792c9Romain Guy            glyphsCount++;
528694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
529694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
530694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
531694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
53251769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) {
533694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mAdvanceX = skiaGlyph.fAdvanceX;
534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mAdvanceY = skiaGlyph.fAdvanceY;
535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapLeft = skiaGlyph.fLeft;
536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapTop = skiaGlyph.fTop;
5372bffd268f135df8308c9e67af110525a5c463424Romain Guy    glyph->mLsbDelta = skiaGlyph.fLsbDelta;
5382bffd268f135df8308c9e67af110525a5c463424Romain Guy    glyph->mRsbDelta = skiaGlyph.fRsbDelta;
539694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
540694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
541694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
542694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
543694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Get the bitmap for the glyph
544694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    paint->findImage(skiaGlyph);
5457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY);
546694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
547694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!glyph->mIsValid) {
548694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
549694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
550694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
551694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + skiaGlyph.fWidth;
552694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + skiaGlyph.fHeight;
553694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
55489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    glyph->mStartX = startX;
55589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    glyph->mStartY = startY;
556694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapWidth = skiaGlyph.fWidth;
557694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapHeight = skiaGlyph.fHeight;
558694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5597de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth;
5607de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight;
561694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
56233fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy    glyph->mBitmapMinU = startX / (float) cacheWidth;
56333fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy    glyph->mBitmapMinV = startY / (float) cacheHeight;
56433fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy    glyph->mBitmapMaxU = endX / (float) cacheWidth;
56533fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy    glyph->mBitmapMaxV = endY / (float) cacheHeight;
566694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
56751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    mState->mUploadTexture = true;
568694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
569694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5707de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) {
57151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
572694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCachedGlyphs.add(glyph, newGlyph);
573694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
574726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
575694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    newGlyph->mGlyphIndex = skiaGlyph.fID;
576694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    newGlyph->mIsValid = false;
577694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
578694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    updateGlyphCache(paint, skiaGlyph, newGlyph);
579694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
580694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return newGlyph;
581694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
582694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5832577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
584bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        int flags, uint32_t italicStyle, uint32_t scaleX,
585bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy        SkPaint::Style style, uint32_t strokeWidth) {
586694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Vector<Font*> &activeFonts = state->mActiveFonts;
587694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
588694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < activeFonts.size(); i++) {
58951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        Font* font = activeFonts[i];
5902577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy        if (font->mFontId == fontId && font->mFontSize == fontSize &&
5918668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase                font->mFlags == flags && font->mItalicStyle == italicStyle &&
592bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy                font->mScaleX == scaleX && font->mStyle == style &&
593bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy                (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
59451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy            return font;
595694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
596694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
597694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
598bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
599bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy            scaleX, style, strokeWidth);
600694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    activeFonts.push(newFont);
601694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return newFont;
602694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
603694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
604694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
605694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer
606694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
607694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
608514fb18827186591d66973c2362c859b64b63556Romain Guystatic bool sLogFontRendererCreate = true;
609514fb18827186591d66973c2362c859b64b63556Romain Guy
610694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() {
611c9855a53edfac818dc68714557185977556f849dRomain Guy    if (sLogFontRendererCreate) {
612c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("Creating FontRenderer");
613c9855a53edfac818dc68714557185977556f849dRomain Guy    }
61451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
615b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy    mGammaTable = NULL;
616694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = false;
617694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mMaxNumberOfQuads = 1024;
618694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentQuadIndex = 0;
619694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6209cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    mTextMeshPtr = NULL;
6217de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCurrentCacheTexture = NULL;
6227de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mLastCacheTexture = NULL;
6237de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTextureSmall = NULL;
6247de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture128 = NULL;
6257de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture256 = NULL;
6267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture512 = NULL;
6279cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy
6282a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    mLinearFiltering = false;
6292a47c14e2a6f152496b43104bc785c488583fd59Chet Haase
630694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mIndexBufferID = 0;
631694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6327de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
6337de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT;
63451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
63551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    char property[PROPERTY_VALUE_MAX];
63651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) {
637c9855a53edfac818dc68714557185977556f849dRomain Guy        if (sLogFontRendererCreate) {
638c9855a53edfac818dc68714557185977556f849dRomain Guy            INIT_LOGD("  Setting text cache width to %s pixels", property);
639c9855a53edfac818dc68714557185977556f849dRomain Guy        }
6407de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mSmallCacheWidth = atoi(property);
64151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    } else {
642514fb18827186591d66973c2362c859b64b63556Romain Guy        if (sLogFontRendererCreate) {
6437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            INIT_LOGD("  Using default text cache width of %i pixels", mSmallCacheWidth);
644514fb18827186591d66973c2362c859b64b63556Romain Guy        }
64551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    }
64651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
64751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) {
648c9855a53edfac818dc68714557185977556f849dRomain Guy        if (sLogFontRendererCreate) {
649c9855a53edfac818dc68714557185977556f849dRomain Guy            INIT_LOGD("  Setting text cache width to %s pixels", property);
650c9855a53edfac818dc68714557185977556f849dRomain Guy        }
6517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mSmallCacheHeight = atoi(property);
65251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    } else {
653514fb18827186591d66973c2362c859b64b63556Romain Guy        if (sLogFontRendererCreate) {
6547de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            INIT_LOGD("  Using default text cache height of %i pixels", mSmallCacheHeight);
655514fb18827186591d66973c2362c859b64b63556Romain Guy        }
65651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    }
657514fb18827186591d66973c2362c859b64b63556Romain Guy
658514fb18827186591d66973c2362c859b64b63556Romain Guy    sLogFontRendererCreate = false;
659694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
660694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
661694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() {
662694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
663694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete mCacheLines[i];
664694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
665694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.clear();
666694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6679cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    if (mInitialized) {
668a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy        // Unbinding the buffer shouldn't be necessary but it crashes with some drivers
669a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy        Caches::getInstance().unbindIndicesBuffer();
670b0317984d34da99b614597ad0a8b39268eacb783Romain Guy        glDeleteBuffers(1, &mIndexBufferID);
671b0317984d34da99b614597ad0a8b39268eacb783Romain Guy
6729cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy        delete[] mTextMeshPtr;
6737de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTextureSmall;
6747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture128;
6757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture256;
6767de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        delete mCacheTexture512;
6779b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
678694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
679694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Vector<Font*> fontsToDereference = mActiveFonts;
680694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < fontsToDereference.size(); i++) {
681694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete fontsToDereference[i];
682694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
683694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
684694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
685694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() {
686694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex != 0) {
687694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
688694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
689694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
6909d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
691694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
692694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mActiveFonts[i]->invalidateTextureCache();
693694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
6949d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
695e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    uint16_t totalGlyphs = 0;
696694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
697e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        totalGlyphs += mCacheLines[i]->mNumGlyphs;
698e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        mCacheLines[i]->init();
699e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
700e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
701e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER
702e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    ALOGD("FontRenderer: flushAllAndInvalidatel");
703e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    // Erase caches, just as a debugging facility
704e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (mCacheTextureSmall && mCacheTextureSmall->mTexture) {
705e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        memset(mCacheTextureSmall->mTexture, 0,
706e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight);
707e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
708e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (mCacheTexture128 && mCacheTexture128->mTexture) {
709e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        memset(mCacheTexture128->mTexture, 0,
710e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                mCacheTexture128->mWidth * mCacheTexture128->mHeight);
711694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
712e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (mCacheTexture256 && mCacheTexture256->mTexture) {
713e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        memset(mCacheTexture256->mTexture, 0,
714e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                mCacheTexture256->mWidth * mCacheTexture256->mHeight);
715e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
716e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (mCacheTexture512 && mCacheTexture512->mTexture) {
717e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        memset(mCacheTexture512->mTexture, 0,
718e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                mCacheTexture512->mWidth * mCacheTexture512->mHeight);
719e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
720e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs);
721e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif
722694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
723694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
7249a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) {
7259a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    if (cacheTexture && cacheTexture->mTexture) {
7269a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        glDeleteTextures(1, &cacheTexture->mTextureId);
7279d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete[] cacheTexture->mTexture;
7289a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        cacheTexture->mTexture = NULL;
72999a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy        cacheTexture->mTextureId = 0;
7309a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    }
7319a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase}
7329a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
7339a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::flushLargeCaches() {
7349a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    if ((!mCacheTexture128 || !mCacheTexture128->mTexture) &&
7359a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            (!mCacheTexture256 || !mCacheTexture256->mTexture) &&
7369a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            (!mCacheTexture512 || !mCacheTexture512->mTexture)) {
7379a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        // Typical case; no large glyph caches allocated
7389a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        return;
7399a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    }
7409a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
7419a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
7429a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        CacheTextureLine* cacheLine = mCacheLines[i];
7439a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        if ((cacheLine->mCacheTexture == mCacheTexture128 ||
7449a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                cacheLine->mCacheTexture == mCacheTexture256 ||
7459a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                cacheLine->mCacheTexture == mCacheTexture512) &&
7469a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                cacheLine->mCacheTexture->mTexture != NULL) {
747e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER
748e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            if (cacheLine->mCacheTexture == mCacheTexture128) {
749e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                ALOGD("flushing cacheTexture128");
750e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            } else if (cacheLine->mCacheTexture == mCacheTexture256) {
751e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                ALOGD("flushing cacheTexture256");
752e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            } else {
753e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                ALOGD("flushing cacheTexture512");
754e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            }
755e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif
756e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            cacheLine->init();
7579a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
7589a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase                mActiveFonts[i]->invalidateTextureCache(cacheLine);
7599a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            }
7609a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        }
7619a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    }
7629a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
7639a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    deallocateTextureMemory(mCacheTexture128);
7649a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    deallocateTextureMemory(mCacheTexture256);
7659a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    deallocateTextureMemory(mCacheTexture512);
7669a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase}
7679a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
7689d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guyvoid FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
7692a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    int width = cacheTexture->mWidth;
7702a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    int height = cacheTexture->mHeight;
7719d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
7722a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    cacheTexture->mTexture = new uint8_t[width * height];
77399a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy
77499a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy    if (!cacheTexture->mTextureId) {
77599a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy        glGenTextures(1, &cacheTexture->mTextureId);
77699a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy    }
7779d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
77816c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy    Caches::getInstance().activeTexture(0);
7792a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
7802a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
7812a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    // Initialize texture dimensions
7822a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
7832a47c14e2a6f152496b43104bc785c488583fd59Chet Haase            GL_ALPHA, GL_UNSIGNED_BYTE, 0);
7842a47c14e2a6f152496b43104bc785c488583fd59Chet Haase
7852a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    const GLenum filtering = cacheTexture->mLinearFiltering ? GL_LINEAR : GL_NEAREST;
7862a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
7872a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
7887de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
7892a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
7902a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
7917de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase}
7927de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
7937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
7947de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        uint32_t* retOriginX, uint32_t* retOriginY) {
7957de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mIsValid = false;
796694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the glyph is too tall, don't cache it
797e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (mCacheLines.size() == 0 ||
798e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
799e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        if (mCacheLines.size() != 0) {
800e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            ALOGE("Font size too large to fit in cache. width, height = %i, %i",
801e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                    (int) glyph.fWidth, (int) glyph.fHeight);
802e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        }
8037de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        return;
804694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
805694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
806694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Now copy the bitmap into the cache texture
807694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
808694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
809694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
810694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    bool bitmapFit = false;
8117de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    CacheTextureLine *cacheLine;
812694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
813694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
814694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (bitmapFit) {
8157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            cacheLine = mCacheLines[i];
816694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
817694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
818694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
819694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
820694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the new glyph didn't fit, flush the state so far and invalidate everything
821694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!bitmapFit) {
822694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        flushAllAndInvalidate();
823694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
824694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // Try to fit it again
825694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        for (uint32_t i = 0; i < mCacheLines.size(); i++) {
826694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
827694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            if (bitmapFit) {
8287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase                cacheLine = mCacheLines[i];
829694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                break;
830694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            }
831694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
832694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
833694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // if we still don't fit, something is wrong and we shouldn't draw
834694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (!bitmapFit) {
8357de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            return;
836694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
837694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
838694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8397de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mCachedTextureLine = cacheLine;
8407de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
841694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginX = startX;
842694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginY = startY;
843694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
844694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + glyph.fWidth;
845694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + glyph.fHeight;
846694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint32_t cacheWidth = cacheLine->mMaxWidth;
848694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8499d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    CacheTexture* cacheTexture = cacheLine->mCacheTexture;
8509d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    if (!cacheTexture->mTexture) {
8517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        // Large-glyph texture memory is allocated only as needed
8522a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        allocateTextureMemory(cacheTexture);
8537de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
8549d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
8557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint8_t* cacheBuffer = cacheTexture->mTexture;
85689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
857694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    unsigned int stride = glyph.rowBytes();
858694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
859694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
86033fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy
86133fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy    for (cacheX = startX - TEXTURE_BORDER_SIZE; cacheX < endX + TEXTURE_BORDER_SIZE; cacheX++) {
86233fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy        cacheBuffer[(startY - TEXTURE_BORDER_SIZE) * cacheWidth + cacheX] = 0;
86333fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy        cacheBuffer[(endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + cacheX] = 0;
86433fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy    }
86533fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy
86633fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy    for (cacheY = startY - TEXTURE_BORDER_SIZE + 1;
86733fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy            cacheY < endY + TEXTURE_BORDER_SIZE - 1; cacheY++) {
86833fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy        cacheBuffer[cacheY * cacheWidth + startX - TEXTURE_BORDER_SIZE] = 0;
86933fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy        cacheBuffer[cacheY * cacheWidth + endX + TEXTURE_BORDER_SIZE - 1] = 0;
87033fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy    }
87133fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy
872b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy    if (mGammaTable) {
873b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy        for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
874b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy            for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
875b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy                uint8_t tempCol = bitmapBuffer[bY * stride + bX];
876b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy                cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
877b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy            }
878b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy        }
879b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy    } else {
880b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy        for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
881b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy            for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
882b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy                uint8_t tempCol = bitmapBuffer[bY * stride + bX];
883b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy                cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol;
884b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy            }
885694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
886694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
8879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
8887de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mIsValid = true;
889694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
890694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8917de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
8920aa87bbfc41e8b5f52de701ac17b4e66a7a7b609Romain Guy    CacheTexture* cacheTexture = new CacheTexture(width, height);
8939d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
8942a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    if (allocate) {
8952a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        allocateTextureMemory(cacheTexture);
8962a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    }
8979d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
8982a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    return cacheTexture;
8997de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase}
9007de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
9017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::initTextTexture() {
9029d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
9039d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete mCacheLines[i];
9049d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    }
9057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.clear();
9067de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
9079d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    if (mCacheTextureSmall) {
9089d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete mCacheTextureSmall;
9099d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete mCacheTexture128;
9109d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete mCacheTexture256;
9119d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy        delete mCacheTexture512;
9129d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy    }
9139d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
9147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    // Next, use other, separate caches for large glyphs.
9157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    uint16_t maxWidth = 0;
9167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (Caches::hasInstance()) {
9177de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        maxWidth = Caches::getInstance().maxTextureSize;
9187de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
9199d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
9207de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) {
9217de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        maxWidth = MAX_TEXT_CACHE_WIDTH;
9227de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
9239d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
9247de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true);
9257de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture128 = createCacheTexture(maxWidth, 256, false);
9267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture256 = createCacheTexture(maxWidth, 256, false);
9277de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheTexture512 = createCacheTexture(maxWidth, 512, false);
9287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCurrentCacheTexture = mCacheTextureSmall;
9297de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
9307de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mUploadTexture = false;
9317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    // Split up our default cache texture into lines of certain widths
932694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nextLine = 0;
933e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, mCacheTextureSmall));
934694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
935e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, mCacheTextureSmall));
936694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
937e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, mCacheTextureSmall));
93865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    nextLine += mCacheLines.top()->mMaxHeight;
939e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, mCacheTextureSmall));
940694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
941e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, mCacheTextureSmall));
942694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
943e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, mCacheTextureSmall));
944694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
9457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine,
946e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            nextLine, mCacheTextureSmall));
9477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
9487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    //  The first cache is split into 2 lines of height 128, the rest have just one cache line.
949e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, mCacheTexture128));
950e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, mCacheTexture128));
951e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, mCacheTexture256));
952e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, mCacheTexture512));
953694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
954694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
955694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad
956694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() {
957d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    uint32_t numIndices = mMaxNumberOfQuads * 6;
958d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t);
95951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
960694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
961694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Four verts, two triangles , six indices per quad
962694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) {
963694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int i6 = i * 6;
964694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int i4 = i * 4;
965694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
966694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 0] = i4 + 0;
967694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 1] = i4 + 1;
968694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 2] = i4 + 2;
969694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
970694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 3] = i4 + 0;
971694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 4] = i4 + 2;
972694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 5] = i4 + 3;
973694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
974694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
975694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glGenBuffers(1, &mIndexBufferID);
97615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    Caches::getInstance().bindIndicesBuffer(mIndexBufferID);
9775d794412e3e429e47404395badcd11b0b8639e8bRomain Guy    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW);
978694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
979694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    free(indexBufferData);
980694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
981d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    uint32_t coordSize = 2;
982694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t uvSize = 2;
983694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t vertsPerQuad = 4;
9849b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize;
9859b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mTextMeshPtr = new float[vertexBufferSize];
986694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
987694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
988694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text
989694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() {
990694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mInitialized) {
991694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
992694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
993694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
994694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initTextTexture();
995694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initVertexArrayBuffers();
996694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
997694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = true;
998694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
999694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
10009b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() {
10017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) {
10029b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        return;
10039b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
10049b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
10052d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    Caches& caches = Caches::getInstance();
10062d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    GLuint lastTextureId = 0;
10079b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    // Iterate over all the cache lines and see which ones need to be updated
10089b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
10099b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        CacheTextureLine* cl = mCacheLines[i];
10107de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) {
10117de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            CacheTexture* cacheTexture = cl->mCacheTexture;
10129b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t xOffset = 0;
10139b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t yOffset = cl->mCurrentRow;
10147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            uint32_t width   = cl->mMaxWidth;
10159b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            uint32_t height  = cl->mMaxHeight;
10167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            void* textureData = cacheTexture->mTexture + (yOffset * width);
10179b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
10182d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy            if (cacheTexture->mTextureId != lastTextureId) {
10192d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy                caches.activeTexture(0);
10202d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy                glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
10212d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy                lastTextureId = cacheTexture->mTextureId;
10222d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy            }
1023e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER
1024e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            ALOGD("glTextSubimage for cacheLine %d: xOff, yOff, width height = %d, %d, %d, %d", i,
1025e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase                    xOffset, yOffset, width, height);
1026e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif
10279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
10281e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy                    GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
10299b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
10309b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            cl->mDirty = false;
10319b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        }
1032694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
1033694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
103416c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy    caches.activeTexture(0);
10357de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId);
10362a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    if (mLinearFiltering != mCurrentCacheTexture->mLinearFiltering) {
10372a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        const GLenum filtering = mLinearFiltering ? GL_LINEAR : GL_NEAREST;
10382a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
10392a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
10402a47c14e2a6f152496b43104bc785c488583fd59Chet Haase        mCurrentCacheTexture->mLinearFiltering = mLinearFiltering;
10412a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    }
10427de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mLastCacheTexture = mCurrentCacheTexture;
10437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
10449b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mUploadTexture = false;
10459b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk}
10469b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
10479b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() {
10489b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    checkTextureUpdate();
10499b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
105015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    Caches& caches = Caches::getInstance();
10512d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    caches.bindIndicesBuffer(mIndexBufferID);
105215bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    if (!mDrawn) {
105315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        float* buffer = mTextMeshPtr;
105415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        int offset = 2;
105515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
105615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        bool force = caches.unbindMeshBuffer();
105715bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        caches.bindPositionVertexPointer(force, caches.currentProgram->position, buffer);
105815bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy        caches.bindTexCoordsVertexPointer(force, caches.currentProgram->texCoords,
105915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy                buffer + offset);
106015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    }
106115bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
1062694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
10635b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
10645b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mDrawn = true;
1065694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
1066694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
10679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
10689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
10697de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        float x4, float y4, float u4, float v4, CacheTexture* texture) {
10707de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (texture != mCurrentCacheTexture) {
10717de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        if (mCurrentQuadIndex != 0) {
10727de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            // First, draw everything stored already which uses the previous texture
10737de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            issueDrawCommand();
10747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            mCurrentQuadIndex = 0;
10757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        }
10767de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        // Now use the new texture id
10777de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mCurrentCacheTexture = texture;
10787de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
107909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy
1080694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    const uint32_t vertsPerQuad = 4;
1081d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy    const uint32_t floatsPerVert = 4;
108251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
1083694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1084694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x1;
1085694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y1;
1086694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u1;
1087694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v1;
1088694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1089694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x2;
1090694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y2;
1091694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u2;
1092694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v2;
1093694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1094694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x3;
1095694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y3;
1096694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u3;
1097694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v3;
1098694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1099694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x4;
1100694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y4;
1101694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u4;
1102694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v4;
1103694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1104694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentQuadIndex++;
11059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
11069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
11079777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
11089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
11099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x4, float y4, float u4, float v4, CacheTexture* texture) {
11109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
11119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mClip &&
11129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
11139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return;
11149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
11159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
11169777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
1117694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
11185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    if (mBounds) {
11195b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->left = fmin(mBounds->left, x1);
11205b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->top = fmin(mBounds->top, y3);
11215b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->right = fmax(mBounds->right, x3);
11225b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mBounds->bottom = fmax(mBounds->bottom, y1);
11235b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
11245b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
1125694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
1126694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
1127694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
1128694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
1129694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
1130694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
11319777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
11329777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
11339777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x4, float y4, float u4, float v4, CacheTexture* texture) {
11349777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
11359777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
11369777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
11379777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mBounds) {
11389777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
11399777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
11409777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
11419777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
11429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
11439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
11449777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
11459777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        issueDrawCommand();
11469777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        mCurrentQuadIndex = 0;
11479777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
11489777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
11499777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
115065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) {
1151325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    int flags = 0;
1152325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    if (paint->isFakeBoldText()) {
1153325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy        flags |= Font::kFakeBold;
1154325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    }
11552577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy
11562577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy    const float skewX = paint->getTextSkewX();
11572577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy    uint32_t italicStyle = *(uint32_t*) &skewX;
11588668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase    const float scaleXFloat = paint->getTextScaleX();
11598668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase    uint32_t scaleX = *(uint32_t*) &scaleXFloat;
1160bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    SkPaint::Style style = paint->getStyle();
1161bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    const float strokeWidthFloat = paint->getStrokeWidth();
1162bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
1163bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy    mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle,
1164bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy            scaleX, style, strokeWidth);
116565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
1166694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
11677975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy
1168f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
1169416a847633680d94efb926837efdc18726d54918Raph Levien        uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) {
11701e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    checkInit();
11711e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
11721e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    if (!mCurrentFont) {
11731e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        DropShadow image;
11741e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.width = 0;
11751e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.height = 0;
11761e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.image = NULL;
11771e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.penX = 0;
11781e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        image.penY = 0;
11791e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        return image;
11801e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    }
1181f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
11822d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    mDrawn = false;
1183ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy    mClip = NULL;
1184ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy    mBounds = NULL;
1185ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
1186f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    Rect bounds;
1187416a847633680d94efb926837efdc18726d54918Raph Levien    mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
1188ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
11891e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
11901e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
1191f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight];
1192ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
11931e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) {
1194f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        dataBuffer[i] = 0;
1195f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
11961e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
1197f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int penX = radius - bounds.left;
1198f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    int penY = radius - bounds.bottom;
1199f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
1200726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
1201416a847633680d94efb926837efdc18726d54918Raph Levien            Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
1202f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    blurImage(dataBuffer, paddedWidth, paddedHeight, radius);
1203f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
1204f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    DropShadow image;
1205f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.width = paddedWidth;
1206f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.height = paddedHeight;
1207f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.image = dataBuffer;
1208f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.penX = penX;
1209f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.penY = penY;
12102d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy
1211f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    return image;
1212f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
1213694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1214671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::initRender(const Rect* clip, Rect* bounds) {
1215694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    checkInit();
1216694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
12175b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mDrawn = false;
12185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mBounds = bounds;
121909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy    mClip = clip;
1220671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
1221ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
1222671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::finishRender() {
12235b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mBounds = NULL;
1224ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy    mClip = NULL;
1225694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex != 0) {
1227694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
1228694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
1229694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
1230671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
1231671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1232e816baea651476aca4407200d4a5e629b9ab8dfaChet Haasevoid FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs) {
1233e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    int flags = 0;
1234e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    if (paint->isFakeBoldText()) {
1235e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase        flags |= Font::kFakeBold;
1236e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
1237e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    const float skewX = paint->getTextSkewX();
1238e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    uint32_t italicStyle = *(uint32_t*) &skewX;
1239e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    const float scaleXFloat = paint->getTextScaleX();
1240e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    uint32_t scaleX = *(uint32_t*) &scaleXFloat;
1241e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    SkPaint::Style style = paint->getStyle();
1242e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    const float strokeWidthFloat = paint->getStrokeWidth();
1243e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
1244e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    float fontSize = paint->getTextSize();
1245e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    Font* font = Font::create(this, SkTypeface::UniqueID(paint->getTypeface()),
1246e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase            fontSize, flags, italicStyle, scaleX, style, strokeWidth);
1247e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
1248e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    font->precache(paint, text, numGlyphs);
1249e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase}
1250e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
1251671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
1252671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) {
1253671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (!mCurrentFont) {
1254671d6cf460531825a321edb200523d0faa7792c9Romain Guy        ALOGE("No font set");
1255671d6cf460531825a321edb200523d0faa7792c9Romain Guy        return false;
1256671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
1257671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1258671d6cf460531825a321edb200523d0faa7792c9Romain Guy    initRender(clip, bounds);
1259671d6cf460531825a321edb200523d0faa7792c9Romain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y);
1260671d6cf460531825a321edb200523d0faa7792c9Romain Guy    finishRender();
1261671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1262671d6cf460531825a321edb200523d0faa7792c9Romain Guy    return mDrawn;
1263671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
1264671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1265671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
1266671d6cf460531825a321edb200523d0faa7792c9Romain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
1267671d6cf460531825a321edb200523d0faa7792c9Romain Guy        const float* positions, Rect* bounds) {
1268671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (!mCurrentFont) {
1269671d6cf460531825a321edb200523d0faa7792c9Romain Guy        ALOGE("No font set");
1270671d6cf460531825a321edb200523d0faa7792c9Romain Guy        return false;
1271671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
1272671d6cf460531825a321edb200523d0faa7792c9Romain Guy
1273671d6cf460531825a321edb200523d0faa7792c9Romain Guy    initRender(clip, bounds);
1274671d6cf460531825a321edb200523d0faa7792c9Romain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
1275671d6cf460531825a321edb200523d0faa7792c9Romain Guy    finishRender();
12765b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
12775b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    return mDrawn;
12789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
12799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
12809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guybool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text,
12819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path,
12829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float hOffset, float vOffset, Rect* bounds) {
12839777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (!mCurrentFont) {
12849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        ALOGE("No font set");
12859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return false;
12869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
12879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
12889777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    initRender(clip, bounds);
12899777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
12909777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    finishRender();
12919777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
12929777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    return mDrawn;
1293694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
1294694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
129589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
129689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Compute gaussian weights for the blur
129789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // e is the euler's number
129889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float e = 2.718281828459045f;
129989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float pi = 3.1415926535897932f;
130089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
130189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // x is of the form [-radius .. 0 .. radius]
130289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // and sigma varies with radius.
130389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Based on some experimental radius values and sigma's
130489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // we approximately fit sigma = f(radius) as
1305f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    // sigma = radius * 0.3  + 0.6
130689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // The larger the radius gets, the more our gaussian blur
130789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // will resemble a box blur since with large sigma
130889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // the gaussian curve begins to lose its shape
1309325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    float sigma = 0.3f * (float) radius + 0.6f;
131089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
131189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // Now compute the coefficints
131289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // We will store some redundant values to save some math during
131389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // the blur calculations
131489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    // precompute some values
131589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
131689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
131789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
131889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float normalizeFactor = 0.0f;
1319325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t r = -radius; r <= radius; r ++) {
13207975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy        float floatR = (float) r;
132189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
132289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        normalizeFactor += weights[r + radius];
132389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
132489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
132589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    //Now we need to normalize the weights because all our coefficients need to add up to one
132689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    normalizeFactor = 1.0f / normalizeFactor;
1327325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t r = -radius; r <= radius; r ++) {
132889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        weights[r + radius] *= normalizeFactor;
132989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
133089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
133189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
133289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius,
13331e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
133489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float blurredPixel = 0.0f;
133589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float currentPixel = 0.0f;
133689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1337325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t y = 0; y < height; y ++) {
133889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
133989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        const uint8_t* input = source + y * width;
134089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        uint8_t* output = dest + y * width;
134189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1342325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy        for (int32_t x = 0; x < width; x ++) {
134389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            blurredPixel = 0.0f;
134489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const float* gPtr = weights;
134589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            // Optimization for non-border pixels
1346325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy            if (x > radius && x < (width - radius)) {
134789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                const uint8_t *i = input + (x - radius);
1348325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int r = -radius; r <= radius; r ++) {
13497975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy                    currentPixel = (float) (*i);
135089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
135189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
135289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    i++;
135389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
135489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            } else {
1355325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int32_t r = -radius; r <= radius; r ++) {
135689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    // Stepping left and right away from the pixel
135789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    int validW = x + r;
1358325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validW < 0) {
135989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validW = 0;
136089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
1361325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validW > width - 1) {
136289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validW = width - 1;
136389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
136489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1365325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    currentPixel = (float) input[validW];
136689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
136789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
136889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
136989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
137089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            *output = (uint8_t)blurredPixel;
137189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            output ++;
137289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
137389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
137489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
137589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
137689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius,
13771e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
137889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float blurredPixel = 0.0f;
137989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float currentPixel = 0.0f;
138089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1381325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy    for (int32_t y = 0; y < height; y ++) {
138289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
138389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        uint8_t* output = dest + y * width;
138489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1385325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy        for (int32_t x = 0; x < width; x ++) {
138689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            blurredPixel = 0.0f;
138789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const float* gPtr = weights;
138889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            const uint8_t* input = source + x;
138989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            // Optimization for non-border pixels
1390325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy            if (y > radius && y < (height - radius)) {
139189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                const uint8_t *i = input + ((y - radius) * width);
1392325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int32_t r = -radius; r <= radius; r ++) {
139389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    currentPixel = (float)(*i);
139489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
139589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
139689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    i += width;
139789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
139889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            } else {
1399325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                for (int32_t r = -radius; r <= radius; r ++) {
140089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    int validH = y + r;
140189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    // Clamp to zero and width
1402325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validH < 0) {
140389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validH = 0;
140489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
1405325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    if (validH > height - 1) {
140689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                        validH = height - 1;
140789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
140889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
140989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    const uint8_t *i = input + validH * width;
1410325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy                    currentPixel = (float) (*i);
141189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    blurredPixel += currentPixel * gPtr[0];
141289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    gPtr++;
141389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                }
141489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            }
1415325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy            *output = (uint8_t) blurredPixel;
141689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            output ++;
141789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
141889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    }
141989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
142089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
142189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
142289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) {
142389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    float *gaussian = new float[2 * radius + 1];
142489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    computeGaussianWeights(gaussian, radius);
1425d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
142689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    uint8_t* scratch = new uint8_t[width * height];
1427d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
142889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    horizontalBlur(gaussian, radius, image, scratch, width, height);
142989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    verticalBlur(gaussian, radius, scratch, image, width, height);
1430d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
143189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    delete[] gaussian;
143289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    delete[] scratch;
143389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
143489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
1435694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer
1436694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android
1437