FontRenderer.cpp revision 694b519ac647fe998fd396fe0784cc8e179aadc4
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 "FontRenderer.h"
20694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
21694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#include <SkUtils.h>
22694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
23694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace android {
24694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace uirenderer {
25694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
26694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
27694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Font
28694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
29694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
30694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize) :
31694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mState(state), mFontId(fontId), mFontSize(fontSize) {
32694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
33694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
34694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
35694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::~Font() {
36694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) {
37694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (mState->mActiveFonts[ct] == this) {
38694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            mState->mActiveFonts.removeAt(ct);
39694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
40694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
41694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
42694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
43694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
44694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
45694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete glyph;
46694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
47694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
48694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
49694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::invalidateTextureCache() {
50694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
51694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCachedGlyphs.valueAt(i)->mIsValid = false;
52694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
53694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
54694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
55694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) {
56694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    FontRenderer *state = mState;
57694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
58694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nPenX = x + glyph->mBitmapLeft;
59694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
60694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
61694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    state->appendMeshQuad(nPenX, nPenY, 0, glyph->mBitmapMinU, glyph->mBitmapMaxV,
62694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            nPenX + (int) glyph->mBitmapWidth, nPenY, 0, glyph->mBitmapMaxU, glyph->mBitmapMaxV,
63694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            nPenX + (int) glyph->mBitmapWidth, nPenY - (int) glyph->mBitmapHeight,
64694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            0, glyph->mBitmapMaxU, glyph->mBitmapMinV, nPenX, nPenY - (int) glyph->mBitmapHeight,
65694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            0, glyph->mBitmapMinU, glyph->mBitmapMinV);
66694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
67694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
68694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::renderUTF(SkPaint* paint, const char *text, uint32_t len, uint32_t start, int numGlyphs,
69694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int x, int y) {
70694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (numGlyphs == 0 || text == NULL || len == 0) {
71694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
72694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
73694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
74694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int penX = x, penY = y;
75694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int glyphsLeft = 1;
76694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (numGlyphs > 0) {
77694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        glyphsLeft = numGlyphs;
78694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
79694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
80694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    //size_t index = start;
81694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    //size_t nextIndex = 0;
82694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
83694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    text += start;
84694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
85694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    while (glyphsLeft > 0) {
86694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        //int32_t utfChar = utf32_at(text, len, index, &nextIndex);
87694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int32_t utfChar = SkUTF16_NextUnichar((const uint16_t**) &text);
88694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
89694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // Reached the end of the string or encountered
90694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (utfChar < 0) {
91694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
92694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
93694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
94694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // Move to the next character in the array
95694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        //index = nextIndex;
96694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
97694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor(utfChar);
98694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
99694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (cachedGlyph == NULL) {
100694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            cachedGlyph = cacheGlyph(paint, utfChar);
101694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
102694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // Is the glyph still in texture cache?
103694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (!cachedGlyph->mIsValid) {
104694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar);
105694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            updateGlyphCache(paint, skiaGlyph, cachedGlyph);
106694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
107694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
108694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
109694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (cachedGlyph->mIsValid) {
110694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            drawCachedGlyph(cachedGlyph, penX, penY);
111694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
112694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
113694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // TODO: Check how to do this conversion
114694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        penX += SkFixedRound(cachedGlyph->mAdvanceX);
115694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
116694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // If we were given a specific number of glyphs, decrement
117694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (numGlyphs > 0) {
118694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            glyphsLeft--;
119694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
120694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
121694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
122694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
123694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo *glyph) {
124694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mAdvanceX = skiaGlyph.fAdvanceX;
125694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mAdvanceY = skiaGlyph.fAdvanceY;
126694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapLeft = skiaGlyph.fLeft;
127694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapTop = skiaGlyph.fTop;
128694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
129694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
130694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
131694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
132694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Let the font state figure out where to put the bitmap
133694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    FontRenderer *state = mState;
134694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Get the bitmap for the glyph
135694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    paint->findImage(skiaGlyph);
136694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mIsValid = state->cacheBitmap(skiaGlyph, &startX, &startY);
137694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
138694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!glyph->mIsValid) {
139694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
140694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
141694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
142694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + skiaGlyph.fWidth;
143694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + skiaGlyph.fHeight;
144694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
145694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapWidth = skiaGlyph.fWidth;
146694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapHeight = skiaGlyph.fHeight;
147694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
148694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t cacheWidth = state->getCacheWidth();
149694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t cacheHeight = state->getCacheHeight();
150694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
151694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMinU = (float) startX / (float) cacheWidth;
152694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMinV = (float) startY / (float) cacheHeight;
153694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMaxU = (float) endX / (float) cacheWidth;
154694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glyph->mBitmapMaxV = (float) endY / (float) cacheHeight;
155694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
156694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    state->mUploadTexture = true;
157694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
158694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
159694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::CachedGlyphInfo *Font::cacheGlyph(SkPaint* paint, int32_t glyph) {
160694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
161694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCachedGlyphs.add(glyph, newGlyph);
162694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
163694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    const SkGlyph& skiaGlyph = paint->getUnicharMetrics(glyph);
164694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    newGlyph->mGlyphIndex = skiaGlyph.fID;
165694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    newGlyph->mIsValid = false;
166694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
167694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    updateGlyphCache(paint, skiaGlyph, newGlyph);
168694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
169694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return newGlyph;
170694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
171694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
172694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize) {
173694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Vector<Font*> &activeFonts = state->mActiveFonts;
174694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
175694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < activeFonts.size(); i++) {
176694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        Font *ithFont = activeFonts[i];
177694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (ithFont->mFontId == fontId && ithFont->mFontSize == fontSize) {
178694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            return ithFont;
179694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
180694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
181694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
182694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Font* newFont = new Font(state, fontId, fontSize);
183694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    activeFonts.push(newFont);
184694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return newFont;
185694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
186694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
187694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
188694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer
189694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
190694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
191694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() {
192694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = false;
193694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mMaxNumberOfQuads = 1024;
194694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentQuadIndex = 0;
195694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
196694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mIndexBufferID = 0;
197694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
198694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheWidth = 1024;
199694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheHeight = 256;
200694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
201694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
202694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() {
203694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
204694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete mCacheLines[i];
205694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
206694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.clear();
207694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
208694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    delete mTextTexture;
209694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
210694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Vector<Font*> fontsToDereference = mActiveFonts;
211694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < fontsToDereference.size(); i++) {
212694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        delete fontsToDereference[i];
213694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
214694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
215694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
216694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() {
217694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex != 0) {
218694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
219694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
220694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
221694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
222694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mActiveFonts[i]->invalidateTextureCache();
223694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
224694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
225694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCacheLines[i]->mCurrentCol = 0;
226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
227694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
228694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
229694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guybool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
230694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the glyph is too tall, don't cache it
231694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (glyph.fWidth > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
232694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        LOGE("Font size to large to fit in cache. width, height = %i, %i",
233694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                (int) glyph.fWidth, (int) glyph.fHeight);
234694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return false;
235694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
236694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
237694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Now copy the bitmap into the cache texture
238694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
239694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
240694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
241694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    bool bitmapFit = false;
242694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
243694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
244694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (bitmapFit) {
245694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            break;
246694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
247694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
248694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the new glyph didn't fit, flush the state so far and invalidate everything
250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!bitmapFit) {
251694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        flushAllAndInvalidate();
252694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
253694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // Try to fit it again
254694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        for (uint32_t i = 0; i < mCacheLines.size(); i++) {
255694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
256694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            if (bitmapFit) {
257694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                break;
258694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            }
259694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
260694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
261694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // if we still don't fit, something is wrong and we shouldn't draw
262694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (!bitmapFit) {
263694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i",
264694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    (int) glyph.fWidth, (int) glyph.fHeight);
265694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            return false;
266694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
267694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
268694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
269694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginX = startX;
270694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginY = startY;
271694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
272694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + glyph.fWidth;
273694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + glyph.fHeight;
274694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
275694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t cacheWidth = mCacheWidth;
276694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
277694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    unsigned char *cacheBuffer = mTextTexture;
278694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    unsigned char *bitmapBuffer = (unsigned char*) glyph.fImage;
279694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    unsigned int stride = glyph.rowBytes();
280694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
281694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
282694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
283694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
284694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            unsigned char tempCol = bitmapBuffer[bY * stride + bX];
285694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol;
286694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
287694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
288694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
289694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    return true;
290694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
291694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
292694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initTextTexture() {
293694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mTextTexture = new unsigned char[mCacheWidth * mCacheHeight];
294694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mUploadTexture = false;
295694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
296694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glGenTextures(1, &mTextureId);
297694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBindTexture(GL_TEXTURE_2D, mTextureId);
298694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
299694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
300694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
301694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
302694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
303694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
304694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
305694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
306694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Split up our cache texture into lines of certain widths
307694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int nextLine = 0;
308694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.push(new CacheTextureLine(16, mCacheWidth, nextLine, 0));
309694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
310694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.push(new CacheTextureLine(24, mCacheWidth, nextLine, 0));
311694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
312694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.push(new CacheTextureLine(32, mCacheWidth, nextLine, 0));
313694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
314694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.push(new CacheTextureLine(32, mCacheWidth, nextLine, 0));
315694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
316694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.push(new CacheTextureLine(40, mCacheWidth, nextLine, 0));
317694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    nextLine += mCacheLines.top()->mMaxHeight;
318694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCacheLines.push(new CacheTextureLine(mCacheHeight - nextLine, mCacheWidth, nextLine, 0));
319694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
320694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
321694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad
322694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() {
323694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t numIndicies = mMaxNumberOfQuads * 6;
324694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t);
325694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint16_t *indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
326694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
327694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Four verts, two triangles , six indices per quad
328694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) {
329694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int i6 = i * 6;
330694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int i4 = i * 4;
331694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
332694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 0] = i4 + 0;
333694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 1] = i4 + 1;
334694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 2] = i4 + 2;
335694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
336694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 3] = i4 + 0;
337694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 4] = i4 + 2;
338694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        indexBufferData[i6 + 5] = i4 + 3;
339694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
340694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
341694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glGenBuffers(1, &mIndexBufferID);
342694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBindBuffer(GL_ARRAY_BUFFER, mIndexBufferID);
343694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBufferData(GL_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_DYNAMIC_DRAW);
344694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBindBuffer(GL_ARRAY_BUFFER, 0);
345694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
346694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    free(indexBufferData);
347694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
348694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t coordSize = 3;
349694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t uvSize = 2;
350694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t vertsPerQuad = 4;
351694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t vertexBufferSizeBytes = mMaxNumberOfQuads * vertsPerQuad * coordSize *
352694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            uvSize * sizeof(float);
353694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mTextMeshPtr = (float*) malloc(vertexBufferSizeBytes);
354694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
355694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
356694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text
357694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() {
358694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mInitialized) {
359694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
360694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
361694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
362694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initTextTexture();
363694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initVertexArrayBuffers();
364694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
365694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = true;
366694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
367694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
368694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::issueDrawCommand() {
369694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mUploadTexture) {
370694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        glBindTexture(GL_TEXTURE_2D, mTextureId);
371694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0, GL_ALPHA,
372694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                GL_UNSIGNED_BYTE, mTextTexture);
373694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mUploadTexture = false;
374694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
375694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
376694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    float *vtx = mTextMeshPtr;
377694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    float *tex = vtx + 3;
378694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
379694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // position is slot 0
380694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t slot = 0;
381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glVertexAttribPointer(slot, 3, GL_FLOAT, false, 20, vtx);
382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // texture0 is slot 1
384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    slot = 1;
385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glVertexAttribPointer(slot, 2, GL_FLOAT, false, 20, tex);
386694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
390694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
391694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2,
392694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3,
393694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        float x4, float y4, float z4, float u4, float v4) {
394694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    const uint32_t vertsPerQuad = 4;
395694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    const uint32_t floatsPerVert = 5;
396694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
397694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
398694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // TODO: Cull things that are off the screen
399694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    //    float width = (float)mRSC->getWidth();
400694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    //    float height = (float)mRSC->getHeight();
401694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    //
402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    //    if(x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
403694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    //        return;
404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    //    }
405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x1;
407694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y1;
408694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = z1;
409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u1;
410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v1;
411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
412694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x2;
413694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y2;
414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = z2;
415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u2;
416694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v2;
417694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
418694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x3;
419694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y3;
420694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = z3;
421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u3;
422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v3;
423694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
424694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = x4;
425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = y4;
426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = z4;
427694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = u4;
428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    (*currentPos++) = v4;
429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
430694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentQuadIndex++;
431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
432694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
434694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
435694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
436694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
437694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
438694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::setFont(uint32_t fontId, float fontSize) {
439694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mCurrentFont = Font::create(this, fontId, fontSize);
440694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
441694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
442694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::renderText(SkPaint* paint, const char *text, uint32_t len, uint32_t startIndex,
443694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int numGlyphs, int x, int y) {
444694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    checkInit();
445694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
446694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Render code here
447694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    Font *currentFont = mCurrentFont;
448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (!currentFont) {
449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        LOGE("Unable to initialize any fonts");
450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
451694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
452694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
453694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    currentFont->renderUTF(paint, text, len, startIndex, numGlyphs, x, y);
454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
455694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mCurrentQuadIndex != 0) {
456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mCurrentQuadIndex = 0;
458694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
459694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
461694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::renderText(SkPaint* paint, const char *text, int x, int y) {
462694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    size_t textLen = strlen(text);
463694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    renderText(paint, text, textLen, 0, -1, x, y);
464694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
465694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
466694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer
467694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android
468