xref: /aosp_15_r20/frameworks/rs/rsFont.cpp (revision e1eccf28f96817838ad6867f7f39d2351ec11f56)
1*e1eccf28SAndroid Build Coastguard Worker 
2*e1eccf28SAndroid Build Coastguard Worker /*
3*e1eccf28SAndroid Build Coastguard Worker  * Copyright (C) 2009 The Android Open Source Project
4*e1eccf28SAndroid Build Coastguard Worker  *
5*e1eccf28SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
6*e1eccf28SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
7*e1eccf28SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
8*e1eccf28SAndroid Build Coastguard Worker  *
9*e1eccf28SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
10*e1eccf28SAndroid Build Coastguard Worker  *
11*e1eccf28SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
12*e1eccf28SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
13*e1eccf28SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*e1eccf28SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
15*e1eccf28SAndroid Build Coastguard Worker  * limitations under the License.
16*e1eccf28SAndroid Build Coastguard Worker  */
17*e1eccf28SAndroid Build Coastguard Worker 
18*e1eccf28SAndroid Build Coastguard Worker #include "rsContext.h"
19*e1eccf28SAndroid Build Coastguard Worker #include "rs.h"
20*e1eccf28SAndroid Build Coastguard Worker #include "rsFont.h"
21*e1eccf28SAndroid Build Coastguard Worker #include "rsProgramFragment.h"
22*e1eccf28SAndroid Build Coastguard Worker #include "rsMesh.h"
23*e1eccf28SAndroid Build Coastguard Worker 
24*e1eccf28SAndroid Build Coastguard Worker #ifndef ANDROID_RS_SERIALIZE
25*e1eccf28SAndroid Build Coastguard Worker #include <ft2build.h>
26*e1eccf28SAndroid Build Coastguard Worker #include FT_FREETYPE_H
27*e1eccf28SAndroid Build Coastguard Worker #include FT_BITMAP_H
28*e1eccf28SAndroid Build Coastguard Worker #endif //ANDROID_RS_SERIALIZE
29*e1eccf28SAndroid Build Coastguard Worker #include <string.h>
30*e1eccf28SAndroid Build Coastguard Worker 
31*e1eccf28SAndroid Build Coastguard Worker namespace android {
32*e1eccf28SAndroid Build Coastguard Worker namespace renderscript {
33*e1eccf28SAndroid Build Coastguard Worker 
Font(Context * rsc)34*e1eccf28SAndroid Build Coastguard Worker Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
35*e1eccf28SAndroid Build Coastguard Worker     mInitialized = false;
36*e1eccf28SAndroid Build Coastguard Worker     mHasKerning = false;
37*e1eccf28SAndroid Build Coastguard Worker     mFace = nullptr;
38*e1eccf28SAndroid Build Coastguard Worker }
39*e1eccf28SAndroid Build Coastguard Worker 
init(const char * name,float fontSize,uint32_t dpi,const void * data,uint32_t dataLen)40*e1eccf28SAndroid Build Coastguard Worker bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
41*e1eccf28SAndroid Build Coastguard Worker #ifndef ANDROID_RS_SERIALIZE
42*e1eccf28SAndroid Build Coastguard Worker     if (mInitialized) {
43*e1eccf28SAndroid Build Coastguard Worker         ALOGE("Reinitialization of fonts not supported");
44*e1eccf28SAndroid Build Coastguard Worker         return false;
45*e1eccf28SAndroid Build Coastguard Worker     }
46*e1eccf28SAndroid Build Coastguard Worker 
47*e1eccf28SAndroid Build Coastguard Worker     FT_Error error = 0;
48*e1eccf28SAndroid Build Coastguard Worker     if (data != nullptr && dataLen > 0) {
49*e1eccf28SAndroid Build Coastguard Worker         error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
50*e1eccf28SAndroid Build Coastguard Worker     } else {
51*e1eccf28SAndroid Build Coastguard Worker         error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
52*e1eccf28SAndroid Build Coastguard Worker     }
53*e1eccf28SAndroid Build Coastguard Worker 
54*e1eccf28SAndroid Build Coastguard Worker     if (error) {
55*e1eccf28SAndroid Build Coastguard Worker         ALOGE("Unable to initialize font %s", name);
56*e1eccf28SAndroid Build Coastguard Worker         return false;
57*e1eccf28SAndroid Build Coastguard Worker     }
58*e1eccf28SAndroid Build Coastguard Worker 
59*e1eccf28SAndroid Build Coastguard Worker     mFontName = rsuCopyString(name);
60*e1eccf28SAndroid Build Coastguard Worker     mFontSize = fontSize;
61*e1eccf28SAndroid Build Coastguard Worker     mDpi = dpi;
62*e1eccf28SAndroid Build Coastguard Worker 
63*e1eccf28SAndroid Build Coastguard Worker     error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
64*e1eccf28SAndroid Build Coastguard Worker     if (error) {
65*e1eccf28SAndroid Build Coastguard Worker         ALOGE("Unable to set font size on %s", name);
66*e1eccf28SAndroid Build Coastguard Worker         return false;
67*e1eccf28SAndroid Build Coastguard Worker     }
68*e1eccf28SAndroid Build Coastguard Worker 
69*e1eccf28SAndroid Build Coastguard Worker     mHasKerning = FT_HAS_KERNING(mFace);
70*e1eccf28SAndroid Build Coastguard Worker 
71*e1eccf28SAndroid Build Coastguard Worker     mInitialized = true;
72*e1eccf28SAndroid Build Coastguard Worker #endif //ANDROID_RS_SERIALIZE
73*e1eccf28SAndroid Build Coastguard Worker     return true;
74*e1eccf28SAndroid Build Coastguard Worker }
75*e1eccf28SAndroid Build Coastguard Worker 
preDestroy() const76*e1eccf28SAndroid Build Coastguard Worker void Font::preDestroy() const {
77*e1eccf28SAndroid Build Coastguard Worker     auto& activeFonts = mRSC->mStateFont.mActiveFonts;
78*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t ct = 0; ct < activeFonts.size(); ct++) {
79*e1eccf28SAndroid Build Coastguard Worker         if (activeFonts[ct] == this) {
80*e1eccf28SAndroid Build Coastguard Worker             activeFonts.erase(activeFonts.begin() + ct);
81*e1eccf28SAndroid Build Coastguard Worker             break;
82*e1eccf28SAndroid Build Coastguard Worker         }
83*e1eccf28SAndroid Build Coastguard Worker     }
84*e1eccf28SAndroid Build Coastguard Worker }
85*e1eccf28SAndroid Build Coastguard Worker 
invalidateTextureCache()86*e1eccf28SAndroid Build Coastguard Worker void Font::invalidateTextureCache() {
87*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
88*e1eccf28SAndroid Build Coastguard Worker         mCachedGlyphs.valueAt(i)->mIsValid = false;
89*e1eccf28SAndroid Build Coastguard Worker     }
90*e1eccf28SAndroid Build Coastguard Worker }
91*e1eccf28SAndroid Build Coastguard Worker 
drawCachedGlyph(CachedGlyphInfo * glyph,int32_t x,int32_t y)92*e1eccf28SAndroid Build Coastguard Worker void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
93*e1eccf28SAndroid Build Coastguard Worker     FontState *state = &mRSC->mStateFont;
94*e1eccf28SAndroid Build Coastguard Worker 
95*e1eccf28SAndroid Build Coastguard Worker     int32_t nPenX = x + glyph->mBitmapLeft;
96*e1eccf28SAndroid Build Coastguard Worker     int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
97*e1eccf28SAndroid Build Coastguard Worker 
98*e1eccf28SAndroid Build Coastguard Worker     float u1 = glyph->mBitmapMinU;
99*e1eccf28SAndroid Build Coastguard Worker     float u2 = glyph->mBitmapMaxU;
100*e1eccf28SAndroid Build Coastguard Worker     float v1 = glyph->mBitmapMinV;
101*e1eccf28SAndroid Build Coastguard Worker     float v2 = glyph->mBitmapMaxV;
102*e1eccf28SAndroid Build Coastguard Worker 
103*e1eccf28SAndroid Build Coastguard Worker     int32_t width = (int32_t) glyph->mBitmapWidth;
104*e1eccf28SAndroid Build Coastguard Worker     int32_t height = (int32_t) glyph->mBitmapHeight;
105*e1eccf28SAndroid Build Coastguard Worker 
106*e1eccf28SAndroid Build Coastguard Worker     state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
107*e1eccf28SAndroid Build Coastguard Worker                           nPenX + width, nPenY, 0, u2, v2,
108*e1eccf28SAndroid Build Coastguard Worker                           nPenX + width, nPenY - height, 0, u2, v1,
109*e1eccf28SAndroid Build Coastguard Worker                           nPenX, nPenY - height, 0, u1, v1);
110*e1eccf28SAndroid Build Coastguard Worker }
111*e1eccf28SAndroid Build Coastguard Worker 
drawCachedGlyph(CachedGlyphInfo * glyph,int32_t x,int32_t y,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH)112*e1eccf28SAndroid Build Coastguard Worker void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
113*e1eccf28SAndroid Build Coastguard Worker                            uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
114*e1eccf28SAndroid Build Coastguard Worker     int32_t nPenX = x + glyph->mBitmapLeft;
115*e1eccf28SAndroid Build Coastguard Worker     int32_t nPenY = y + glyph->mBitmapTop;
116*e1eccf28SAndroid Build Coastguard Worker 
117*e1eccf28SAndroid Build Coastguard Worker     uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
118*e1eccf28SAndroid Build Coastguard Worker     uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
119*e1eccf28SAndroid Build Coastguard Worker 
120*e1eccf28SAndroid Build Coastguard Worker     FontState *state = &mRSC->mStateFont;
121*e1eccf28SAndroid Build Coastguard Worker     uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
122*e1eccf28SAndroid Build Coastguard Worker     const uint8_t* cacheBuffer = state->mCacheBuffer;
123*e1eccf28SAndroid Build Coastguard Worker 
124*e1eccf28SAndroid Build Coastguard Worker     uint32_t cacheX = 0, cacheY = 0;
125*e1eccf28SAndroid Build Coastguard Worker     int32_t bX = 0, bY = 0;
126*e1eccf28SAndroid Build Coastguard Worker     for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
127*e1eccf28SAndroid Build Coastguard Worker         for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
128*e1eccf28SAndroid Build Coastguard Worker             if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
129*e1eccf28SAndroid Build Coastguard Worker                 ALOGE("Skipping invalid index");
130*e1eccf28SAndroid Build Coastguard Worker                 continue;
131*e1eccf28SAndroid Build Coastguard Worker             }
132*e1eccf28SAndroid Build Coastguard Worker             uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
133*e1eccf28SAndroid Build Coastguard Worker             bitmap[bY * bitmapW + bX] = tempCol;
134*e1eccf28SAndroid Build Coastguard Worker         }
135*e1eccf28SAndroid Build Coastguard Worker     }
136*e1eccf28SAndroid Build Coastguard Worker }
137*e1eccf28SAndroid Build Coastguard Worker 
measureCachedGlyph(CachedGlyphInfo * glyph,int32_t x,int32_t y,Rect * bounds)138*e1eccf28SAndroid Build Coastguard Worker void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
139*e1eccf28SAndroid Build Coastguard Worker     int32_t nPenX = x + glyph->mBitmapLeft;
140*e1eccf28SAndroid Build Coastguard Worker     int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
141*e1eccf28SAndroid Build Coastguard Worker 
142*e1eccf28SAndroid Build Coastguard Worker     int32_t width = (int32_t) glyph->mBitmapWidth;
143*e1eccf28SAndroid Build Coastguard Worker     int32_t height = (int32_t) glyph->mBitmapHeight;
144*e1eccf28SAndroid Build Coastguard Worker 
145*e1eccf28SAndroid Build Coastguard Worker     // 0, 0 is top left, so bottom is a positive number
146*e1eccf28SAndroid Build Coastguard Worker     if (bounds->bottom < nPenY) {
147*e1eccf28SAndroid Build Coastguard Worker         bounds->bottom = nPenY;
148*e1eccf28SAndroid Build Coastguard Worker     }
149*e1eccf28SAndroid Build Coastguard Worker     if (bounds->left > nPenX) {
150*e1eccf28SAndroid Build Coastguard Worker         bounds->left = nPenX;
151*e1eccf28SAndroid Build Coastguard Worker     }
152*e1eccf28SAndroid Build Coastguard Worker     if (bounds->right < nPenX + width) {
153*e1eccf28SAndroid Build Coastguard Worker         bounds->right = nPenX + width;
154*e1eccf28SAndroid Build Coastguard Worker     }
155*e1eccf28SAndroid Build Coastguard Worker     if (bounds->top > nPenY - height) {
156*e1eccf28SAndroid Build Coastguard Worker         bounds->top = nPenY - height;
157*e1eccf28SAndroid Build Coastguard Worker     }
158*e1eccf28SAndroid Build Coastguard Worker }
159*e1eccf28SAndroid Build Coastguard Worker 
renderUTF(const char * text,uint32_t len,int32_t x,int32_t y,uint32_t start,int32_t numGlyphs,RenderMode mode,Rect * bounds,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH)160*e1eccf28SAndroid Build Coastguard Worker void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
161*e1eccf28SAndroid Build Coastguard Worker                      uint32_t start, int32_t numGlyphs,
162*e1eccf28SAndroid Build Coastguard Worker                      RenderMode mode, Rect *bounds,
163*e1eccf28SAndroid Build Coastguard Worker                      uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
164*e1eccf28SAndroid Build Coastguard Worker     if (!mInitialized || numGlyphs == 0 || text == nullptr || len == 0) {
165*e1eccf28SAndroid Build Coastguard Worker         return;
166*e1eccf28SAndroid Build Coastguard Worker     }
167*e1eccf28SAndroid Build Coastguard Worker 
168*e1eccf28SAndroid Build Coastguard Worker     if (mode == Font::MEASURE) {
169*e1eccf28SAndroid Build Coastguard Worker         if (bounds == nullptr) {
170*e1eccf28SAndroid Build Coastguard Worker             ALOGE("No return rectangle provided to measure text");
171*e1eccf28SAndroid Build Coastguard Worker             return;
172*e1eccf28SAndroid Build Coastguard Worker         }
173*e1eccf28SAndroid Build Coastguard Worker         // Reset min and max of the bounding box to something large
174*e1eccf28SAndroid Build Coastguard Worker         bounds->set(1e6, -1e6, 1e6, -1e6);
175*e1eccf28SAndroid Build Coastguard Worker     }
176*e1eccf28SAndroid Build Coastguard Worker 
177*e1eccf28SAndroid Build Coastguard Worker     int32_t penX = x, penY = y;
178*e1eccf28SAndroid Build Coastguard Worker     int32_t glyphsLeft = 1;
179*e1eccf28SAndroid Build Coastguard Worker     if (numGlyphs > 0) {
180*e1eccf28SAndroid Build Coastguard Worker         glyphsLeft = numGlyphs;
181*e1eccf28SAndroid Build Coastguard Worker     }
182*e1eccf28SAndroid Build Coastguard Worker 
183*e1eccf28SAndroid Build Coastguard Worker     size_t index = start;
184*e1eccf28SAndroid Build Coastguard Worker     size_t nextIndex = 0;
185*e1eccf28SAndroid Build Coastguard Worker 
186*e1eccf28SAndroid Build Coastguard Worker     while (glyphsLeft > 0) {
187*e1eccf28SAndroid Build Coastguard Worker 
188*e1eccf28SAndroid Build Coastguard Worker         int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
189*e1eccf28SAndroid Build Coastguard Worker 
190*e1eccf28SAndroid Build Coastguard Worker         // Reached the end of the string or encountered
191*e1eccf28SAndroid Build Coastguard Worker         if (utfChar < 0) {
192*e1eccf28SAndroid Build Coastguard Worker             break;
193*e1eccf28SAndroid Build Coastguard Worker         }
194*e1eccf28SAndroid Build Coastguard Worker 
195*e1eccf28SAndroid Build Coastguard Worker         // Move to the next character in the array
196*e1eccf28SAndroid Build Coastguard Worker         index = nextIndex;
197*e1eccf28SAndroid Build Coastguard Worker 
198*e1eccf28SAndroid Build Coastguard Worker         CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
199*e1eccf28SAndroid Build Coastguard Worker 
200*e1eccf28SAndroid Build Coastguard Worker         // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
201*e1eccf28SAndroid Build Coastguard Worker         if (cachedGlyph->mIsValid) {
202*e1eccf28SAndroid Build Coastguard Worker             switch (mode) {
203*e1eccf28SAndroid Build Coastguard Worker             case FRAMEBUFFER:
204*e1eccf28SAndroid Build Coastguard Worker                 drawCachedGlyph(cachedGlyph, penX, penY);
205*e1eccf28SAndroid Build Coastguard Worker                 break;
206*e1eccf28SAndroid Build Coastguard Worker             case BITMAP:
207*e1eccf28SAndroid Build Coastguard Worker                 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
208*e1eccf28SAndroid Build Coastguard Worker                 break;
209*e1eccf28SAndroid Build Coastguard Worker             case MEASURE:
210*e1eccf28SAndroid Build Coastguard Worker                 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
211*e1eccf28SAndroid Build Coastguard Worker                 break;
212*e1eccf28SAndroid Build Coastguard Worker             }
213*e1eccf28SAndroid Build Coastguard Worker         }
214*e1eccf28SAndroid Build Coastguard Worker 
215*e1eccf28SAndroid Build Coastguard Worker         penX += (cachedGlyph->mAdvanceX >> 6);
216*e1eccf28SAndroid Build Coastguard Worker 
217*e1eccf28SAndroid Build Coastguard Worker         // If we were given a specific number of glyphs, decrement
218*e1eccf28SAndroid Build Coastguard Worker         if (numGlyphs > 0) {
219*e1eccf28SAndroid Build Coastguard Worker             glyphsLeft --;
220*e1eccf28SAndroid Build Coastguard Worker         }
221*e1eccf28SAndroid Build Coastguard Worker     }
222*e1eccf28SAndroid Build Coastguard Worker }
223*e1eccf28SAndroid Build Coastguard Worker 
getCachedUTFChar(int32_t utfChar)224*e1eccf28SAndroid Build Coastguard Worker Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
225*e1eccf28SAndroid Build Coastguard Worker 
226*e1eccf28SAndroid Build Coastguard Worker     CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
227*e1eccf28SAndroid Build Coastguard Worker     if (cachedGlyph == nullptr) {
228*e1eccf28SAndroid Build Coastguard Worker         cachedGlyph = cacheGlyph((uint32_t)utfChar);
229*e1eccf28SAndroid Build Coastguard Worker     }
230*e1eccf28SAndroid Build Coastguard Worker     // Is the glyph still in texture cache?
231*e1eccf28SAndroid Build Coastguard Worker     if (!cachedGlyph->mIsValid) {
232*e1eccf28SAndroid Build Coastguard Worker         updateGlyphCache(cachedGlyph);
233*e1eccf28SAndroid Build Coastguard Worker     }
234*e1eccf28SAndroid Build Coastguard Worker 
235*e1eccf28SAndroid Build Coastguard Worker     return cachedGlyph;
236*e1eccf28SAndroid Build Coastguard Worker }
237*e1eccf28SAndroid Build Coastguard Worker 
updateGlyphCache(CachedGlyphInfo * glyph)238*e1eccf28SAndroid Build Coastguard Worker void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
239*e1eccf28SAndroid Build Coastguard Worker #ifndef ANDROID_RS_SERIALIZE
240*e1eccf28SAndroid Build Coastguard Worker     FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
241*e1eccf28SAndroid Build Coastguard Worker     if (error) {
242*e1eccf28SAndroid Build Coastguard Worker         ALOGE("Couldn't load glyph.");
243*e1eccf28SAndroid Build Coastguard Worker         return;
244*e1eccf28SAndroid Build Coastguard Worker     }
245*e1eccf28SAndroid Build Coastguard Worker 
246*e1eccf28SAndroid Build Coastguard Worker     glyph->mAdvanceX = mFace->glyph->advance.x;
247*e1eccf28SAndroid Build Coastguard Worker     glyph->mAdvanceY = mFace->glyph->advance.y;
248*e1eccf28SAndroid Build Coastguard Worker     glyph->mBitmapLeft = mFace->glyph->bitmap_left;
249*e1eccf28SAndroid Build Coastguard Worker     glyph->mBitmapTop = mFace->glyph->bitmap_top;
250*e1eccf28SAndroid Build Coastguard Worker 
251*e1eccf28SAndroid Build Coastguard Worker     FT_Bitmap *bitmap = &mFace->glyph->bitmap;
252*e1eccf28SAndroid Build Coastguard Worker 
253*e1eccf28SAndroid Build Coastguard Worker     // Now copy the bitmap into the cache texture
254*e1eccf28SAndroid Build Coastguard Worker     uint32_t startX = 0;
255*e1eccf28SAndroid Build Coastguard Worker     uint32_t startY = 0;
256*e1eccf28SAndroid Build Coastguard Worker 
257*e1eccf28SAndroid Build Coastguard Worker     // Let the font state figure out where to put the bitmap
258*e1eccf28SAndroid Build Coastguard Worker     FontState *state = &mRSC->mStateFont;
259*e1eccf28SAndroid Build Coastguard Worker     glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
260*e1eccf28SAndroid Build Coastguard Worker 
261*e1eccf28SAndroid Build Coastguard Worker     if (!glyph->mIsValid) {
262*e1eccf28SAndroid Build Coastguard Worker         return;
263*e1eccf28SAndroid Build Coastguard Worker     }
264*e1eccf28SAndroid Build Coastguard Worker 
265*e1eccf28SAndroid Build Coastguard Worker     uint32_t endX = startX + bitmap->width;
266*e1eccf28SAndroid Build Coastguard Worker     uint32_t endY = startY + bitmap->rows;
267*e1eccf28SAndroid Build Coastguard Worker 
268*e1eccf28SAndroid Build Coastguard Worker     glyph->mBitmapMinX = startX;
269*e1eccf28SAndroid Build Coastguard Worker     glyph->mBitmapMinY = startY;
270*e1eccf28SAndroid Build Coastguard Worker     glyph->mBitmapWidth = bitmap->width;
271*e1eccf28SAndroid Build Coastguard Worker     glyph->mBitmapHeight = bitmap->rows;
272*e1eccf28SAndroid Build Coastguard Worker 
273*e1eccf28SAndroid Build Coastguard Worker     uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
274*e1eccf28SAndroid Build Coastguard Worker     uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
275*e1eccf28SAndroid Build Coastguard Worker 
276*e1eccf28SAndroid Build Coastguard Worker     glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
277*e1eccf28SAndroid Build Coastguard Worker     glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
278*e1eccf28SAndroid Build Coastguard Worker     glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
279*e1eccf28SAndroid Build Coastguard Worker     glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
280*e1eccf28SAndroid Build Coastguard Worker #endif //ANDROID_RS_SERIALIZE
281*e1eccf28SAndroid Build Coastguard Worker }
282*e1eccf28SAndroid Build Coastguard Worker 
cacheGlyph(uint32_t glyph)283*e1eccf28SAndroid Build Coastguard Worker Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
284*e1eccf28SAndroid Build Coastguard Worker     CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
285*e1eccf28SAndroid Build Coastguard Worker     mCachedGlyphs.add(glyph, newGlyph);
286*e1eccf28SAndroid Build Coastguard Worker #ifndef ANDROID_RS_SERIALIZE
287*e1eccf28SAndroid Build Coastguard Worker     newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
288*e1eccf28SAndroid Build Coastguard Worker     newGlyph->mIsValid = false;
289*e1eccf28SAndroid Build Coastguard Worker #endif //ANDROID_RS_SERIALIZE
290*e1eccf28SAndroid Build Coastguard Worker     updateGlyphCache(newGlyph);
291*e1eccf28SAndroid Build Coastguard Worker 
292*e1eccf28SAndroid Build Coastguard Worker     return newGlyph;
293*e1eccf28SAndroid Build Coastguard Worker }
294*e1eccf28SAndroid Build Coastguard Worker 
create(Context * rsc,const char * name,float fontSize,uint32_t dpi,const void * data,uint32_t dataLen)295*e1eccf28SAndroid Build Coastguard Worker Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
296*e1eccf28SAndroid Build Coastguard Worker                     const void *data, uint32_t dataLen) {
297*e1eccf28SAndroid Build Coastguard Worker     rsc->mStateFont.checkInit();
298*e1eccf28SAndroid Build Coastguard Worker     auto& activeFonts = rsc->mStateFont.mActiveFonts;
299*e1eccf28SAndroid Build Coastguard Worker 
300*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < activeFonts.size(); i ++) {
301*e1eccf28SAndroid Build Coastguard Worker         Font *ithFont = activeFonts[i];
302*e1eccf28SAndroid Build Coastguard Worker         if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
303*e1eccf28SAndroid Build Coastguard Worker             return ithFont;
304*e1eccf28SAndroid Build Coastguard Worker         }
305*e1eccf28SAndroid Build Coastguard Worker     }
306*e1eccf28SAndroid Build Coastguard Worker 
307*e1eccf28SAndroid Build Coastguard Worker     Font *newFont = new Font(rsc);
308*e1eccf28SAndroid Build Coastguard Worker     bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
309*e1eccf28SAndroid Build Coastguard Worker     if (isInitialized) {
310*e1eccf28SAndroid Build Coastguard Worker         activeFonts.push_back(newFont);
311*e1eccf28SAndroid Build Coastguard Worker         rsc->mStateFont.precacheLatin(newFont);
312*e1eccf28SAndroid Build Coastguard Worker         return newFont;
313*e1eccf28SAndroid Build Coastguard Worker     }
314*e1eccf28SAndroid Build Coastguard Worker 
315*e1eccf28SAndroid Build Coastguard Worker     ObjectBase::checkDelete(newFont);
316*e1eccf28SAndroid Build Coastguard Worker     return nullptr;
317*e1eccf28SAndroid Build Coastguard Worker }
318*e1eccf28SAndroid Build Coastguard Worker 
~Font()319*e1eccf28SAndroid Build Coastguard Worker Font::~Font() {
320*e1eccf28SAndroid Build Coastguard Worker #ifndef ANDROID_RS_SERIALIZE
321*e1eccf28SAndroid Build Coastguard Worker     if (mFace) {
322*e1eccf28SAndroid Build Coastguard Worker         FT_Done_Face(mFace);
323*e1eccf28SAndroid Build Coastguard Worker     }
324*e1eccf28SAndroid Build Coastguard Worker #endif
325*e1eccf28SAndroid Build Coastguard Worker 
326*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
327*e1eccf28SAndroid Build Coastguard Worker         CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
328*e1eccf28SAndroid Build Coastguard Worker         delete glyph;
329*e1eccf28SAndroid Build Coastguard Worker     }
330*e1eccf28SAndroid Build Coastguard Worker }
331*e1eccf28SAndroid Build Coastguard Worker 
FontState()332*e1eccf28SAndroid Build Coastguard Worker FontState::FontState() {
333*e1eccf28SAndroid Build Coastguard Worker     mInitialized = false;
334*e1eccf28SAndroid Build Coastguard Worker     mMaxNumberOfQuads = 1024;
335*e1eccf28SAndroid Build Coastguard Worker     mCurrentQuadIndex = 0;
336*e1eccf28SAndroid Build Coastguard Worker     mRSC = nullptr;
337*e1eccf28SAndroid Build Coastguard Worker #ifndef ANDROID_RS_SERIALIZE
338*e1eccf28SAndroid Build Coastguard Worker     mLibrary = nullptr;
339*e1eccf28SAndroid Build Coastguard Worker #endif //ANDROID_RS_SERIALIZE
340*e1eccf28SAndroid Build Coastguard Worker 
341*e1eccf28SAndroid Build Coastguard Worker     float gamma = DEFAULT_TEXT_GAMMA;
342*e1eccf28SAndroid Build Coastguard Worker     int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
343*e1eccf28SAndroid Build Coastguard Worker     int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
344*e1eccf28SAndroid Build Coastguard Worker 
345*e1eccf28SAndroid Build Coastguard Worker #ifdef __ANDROID__
346*e1eccf28SAndroid Build Coastguard Worker     // Get the renderer properties
347*e1eccf28SAndroid Build Coastguard Worker     char property[PROP_VALUE_MAX];
348*e1eccf28SAndroid Build Coastguard Worker 
349*e1eccf28SAndroid Build Coastguard Worker     // Get the gamma
350*e1eccf28SAndroid Build Coastguard Worker     if (property_get(PROPERTY_TEXT_GAMMA, property, nullptr) > 0) {
351*e1eccf28SAndroid Build Coastguard Worker         gamma = atof(property);
352*e1eccf28SAndroid Build Coastguard Worker     }
353*e1eccf28SAndroid Build Coastguard Worker 
354*e1eccf28SAndroid Build Coastguard Worker     // Get the black gamma threshold
355*e1eccf28SAndroid Build Coastguard Worker     if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) {
356*e1eccf28SAndroid Build Coastguard Worker         blackThreshold = atoi(property);
357*e1eccf28SAndroid Build Coastguard Worker     }
358*e1eccf28SAndroid Build Coastguard Worker 
359*e1eccf28SAndroid Build Coastguard Worker     // Get the white gamma threshold
360*e1eccf28SAndroid Build Coastguard Worker     if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 0) {
361*e1eccf28SAndroid Build Coastguard Worker         whiteThreshold = atoi(property);
362*e1eccf28SAndroid Build Coastguard Worker     }
363*e1eccf28SAndroid Build Coastguard Worker #endif
364*e1eccf28SAndroid Build Coastguard Worker 
365*e1eccf28SAndroid Build Coastguard Worker     mBlackThreshold = (float)(blackThreshold) / 255.0f;
366*e1eccf28SAndroid Build Coastguard Worker     mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
367*e1eccf28SAndroid Build Coastguard Worker 
368*e1eccf28SAndroid Build Coastguard Worker     // Compute the gamma tables
369*e1eccf28SAndroid Build Coastguard Worker     mBlackGamma = gamma;
370*e1eccf28SAndroid Build Coastguard Worker     mWhiteGamma = 1.0f / gamma;
371*e1eccf28SAndroid Build Coastguard Worker 
372*e1eccf28SAndroid Build Coastguard Worker     setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
373*e1eccf28SAndroid Build Coastguard Worker }
374*e1eccf28SAndroid Build Coastguard Worker 
~FontState()375*e1eccf28SAndroid Build Coastguard Worker FontState::~FontState() {
376*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
377*e1eccf28SAndroid Build Coastguard Worker         delete mCacheLines[i];
378*e1eccf28SAndroid Build Coastguard Worker     }
379*e1eccf28SAndroid Build Coastguard Worker 
380*e1eccf28SAndroid Build Coastguard Worker     rsAssert(!mActiveFonts.size());
381*e1eccf28SAndroid Build Coastguard Worker }
382*e1eccf28SAndroid Build Coastguard Worker #ifndef ANDROID_RS_SERIALIZE
getLib()383*e1eccf28SAndroid Build Coastguard Worker FT_Library FontState::getLib() {
384*e1eccf28SAndroid Build Coastguard Worker     if (!mLibrary) {
385*e1eccf28SAndroid Build Coastguard Worker         FT_Error error = FT_Init_FreeType(&mLibrary);
386*e1eccf28SAndroid Build Coastguard Worker         if (error) {
387*e1eccf28SAndroid Build Coastguard Worker             ALOGE("Unable to initialize freetype");
388*e1eccf28SAndroid Build Coastguard Worker             return nullptr;
389*e1eccf28SAndroid Build Coastguard Worker         }
390*e1eccf28SAndroid Build Coastguard Worker     }
391*e1eccf28SAndroid Build Coastguard Worker 
392*e1eccf28SAndroid Build Coastguard Worker     return mLibrary;
393*e1eccf28SAndroid Build Coastguard Worker }
394*e1eccf28SAndroid Build Coastguard Worker #endif //ANDROID_RS_SERIALIZE
395*e1eccf28SAndroid Build Coastguard Worker 
396*e1eccf28SAndroid Build Coastguard Worker 
init(Context * rsc)397*e1eccf28SAndroid Build Coastguard Worker void FontState::init(Context *rsc) {
398*e1eccf28SAndroid Build Coastguard Worker     mRSC = rsc;
399*e1eccf28SAndroid Build Coastguard Worker }
400*e1eccf28SAndroid Build Coastguard Worker 
flushAllAndInvalidate()401*e1eccf28SAndroid Build Coastguard Worker void FontState::flushAllAndInvalidate() {
402*e1eccf28SAndroid Build Coastguard Worker     if (mCurrentQuadIndex != 0) {
403*e1eccf28SAndroid Build Coastguard Worker         issueDrawCommand();
404*e1eccf28SAndroid Build Coastguard Worker         mCurrentQuadIndex = 0;
405*e1eccf28SAndroid Build Coastguard Worker     }
406*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
407*e1eccf28SAndroid Build Coastguard Worker         mActiveFonts[i]->invalidateTextureCache();
408*e1eccf28SAndroid Build Coastguard Worker     }
409*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
410*e1eccf28SAndroid Build Coastguard Worker         mCacheLines[i]->mCurrentCol = 0;
411*e1eccf28SAndroid Build Coastguard Worker     }
412*e1eccf28SAndroid Build Coastguard Worker }
413*e1eccf28SAndroid Build Coastguard Worker 
414*e1eccf28SAndroid Build Coastguard Worker #ifndef ANDROID_RS_SERIALIZE
cacheBitmap(FT_Bitmap * bitmap,uint32_t * retOriginX,uint32_t * retOriginY)415*e1eccf28SAndroid Build Coastguard Worker bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
416*e1eccf28SAndroid Build Coastguard Worker     // If the glyph is too tall, don't cache it
417*e1eccf28SAndroid Build Coastguard Worker     if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
418*e1eccf28SAndroid Build Coastguard Worker         ALOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
419*e1eccf28SAndroid Build Coastguard Worker         return false;
420*e1eccf28SAndroid Build Coastguard Worker     }
421*e1eccf28SAndroid Build Coastguard Worker 
422*e1eccf28SAndroid Build Coastguard Worker     // Now copy the bitmap into the cache texture
423*e1eccf28SAndroid Build Coastguard Worker     uint32_t startX = 0;
424*e1eccf28SAndroid Build Coastguard Worker     uint32_t startY = 0;
425*e1eccf28SAndroid Build Coastguard Worker 
426*e1eccf28SAndroid Build Coastguard Worker     bool bitmapFit = false;
427*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
428*e1eccf28SAndroid Build Coastguard Worker         bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
429*e1eccf28SAndroid Build Coastguard Worker         if (bitmapFit) {
430*e1eccf28SAndroid Build Coastguard Worker             break;
431*e1eccf28SAndroid Build Coastguard Worker         }
432*e1eccf28SAndroid Build Coastguard Worker     }
433*e1eccf28SAndroid Build Coastguard Worker 
434*e1eccf28SAndroid Build Coastguard Worker     // If the new glyph didn't fit, flush the state so far and invalidate everything
435*e1eccf28SAndroid Build Coastguard Worker     if (!bitmapFit) {
436*e1eccf28SAndroid Build Coastguard Worker         flushAllAndInvalidate();
437*e1eccf28SAndroid Build Coastguard Worker 
438*e1eccf28SAndroid Build Coastguard Worker         // Try to fit it again
439*e1eccf28SAndroid Build Coastguard Worker         for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
440*e1eccf28SAndroid Build Coastguard Worker             bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
441*e1eccf28SAndroid Build Coastguard Worker             if (bitmapFit) {
442*e1eccf28SAndroid Build Coastguard Worker                 break;
443*e1eccf28SAndroid Build Coastguard Worker             }
444*e1eccf28SAndroid Build Coastguard Worker         }
445*e1eccf28SAndroid Build Coastguard Worker 
446*e1eccf28SAndroid Build Coastguard Worker         // if we still don't fit, something is wrong and we shouldn't draw
447*e1eccf28SAndroid Build Coastguard Worker         if (!bitmapFit) {
448*e1eccf28SAndroid Build Coastguard Worker             ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
449*e1eccf28SAndroid Build Coastguard Worker             return false;
450*e1eccf28SAndroid Build Coastguard Worker         }
451*e1eccf28SAndroid Build Coastguard Worker     }
452*e1eccf28SAndroid Build Coastguard Worker 
453*e1eccf28SAndroid Build Coastguard Worker     *retOriginX = startX;
454*e1eccf28SAndroid Build Coastguard Worker     *retOriginY = startY;
455*e1eccf28SAndroid Build Coastguard Worker 
456*e1eccf28SAndroid Build Coastguard Worker     uint32_t endX = startX + bitmap->width;
457*e1eccf28SAndroid Build Coastguard Worker     uint32_t endY = startY + bitmap->rows;
458*e1eccf28SAndroid Build Coastguard Worker 
459*e1eccf28SAndroid Build Coastguard Worker     uint32_t cacheWidth = getCacheTextureType()->getDimX();
460*e1eccf28SAndroid Build Coastguard Worker 
461*e1eccf28SAndroid Build Coastguard Worker     uint8_t *cacheBuffer = mCacheBuffer;
462*e1eccf28SAndroid Build Coastguard Worker     uint8_t *bitmapBuffer = bitmap->buffer;
463*e1eccf28SAndroid Build Coastguard Worker 
464*e1eccf28SAndroid Build Coastguard Worker     uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
465*e1eccf28SAndroid Build Coastguard Worker     for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
466*e1eccf28SAndroid Build Coastguard Worker         for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
467*e1eccf28SAndroid Build Coastguard Worker             uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
468*e1eccf28SAndroid Build Coastguard Worker             cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
469*e1eccf28SAndroid Build Coastguard Worker         }
470*e1eccf28SAndroid Build Coastguard Worker     }
471*e1eccf28SAndroid Build Coastguard Worker 
472*e1eccf28SAndroid Build Coastguard Worker     // This will dirty the texture and the shader so next time
473*e1eccf28SAndroid Build Coastguard Worker     // we draw it will upload the data
474*e1eccf28SAndroid Build Coastguard Worker 
475*e1eccf28SAndroid Build Coastguard Worker     mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
476*e1eccf28SAndroid Build Coastguard Worker         RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
477*e1eccf28SAndroid Build Coastguard Worker         mCacheBuffer, mCacheWidth*mCacheHeight, mCacheWidth);
478*e1eccf28SAndroid Build Coastguard Worker 
479*e1eccf28SAndroid Build Coastguard Worker     mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
480*e1eccf28SAndroid Build Coastguard Worker 
481*e1eccf28SAndroid Build Coastguard Worker     // Some debug code
482*e1eccf28SAndroid Build Coastguard Worker     /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
483*e1eccf28SAndroid Build Coastguard Worker         ALOGE("Cache Line: H: %u Empty Space: %f",
484*e1eccf28SAndroid Build Coastguard Worker              mCacheLines[i]->mMaxHeight,
485*e1eccf28SAndroid Build Coastguard Worker               (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
486*e1eccf28SAndroid Build Coastguard Worker 
487*e1eccf28SAndroid Build Coastguard Worker     }*/
488*e1eccf28SAndroid Build Coastguard Worker 
489*e1eccf28SAndroid Build Coastguard Worker     return true;
490*e1eccf28SAndroid Build Coastguard Worker }
491*e1eccf28SAndroid Build Coastguard Worker #endif //ANDROID_RS_SERIALIZE
492*e1eccf28SAndroid Build Coastguard Worker 
initRenderState()493*e1eccf28SAndroid Build Coastguard Worker void FontState::initRenderState() {
494*e1eccf28SAndroid Build Coastguard Worker     const char *shaderString = "varying vec2 varTex0;\n"
495*e1eccf28SAndroid Build Coastguard Worker                                "void main() {\n"
496*e1eccf28SAndroid Build Coastguard Worker                                "  lowp vec4 col = UNI_Color;\n"
497*e1eccf28SAndroid Build Coastguard Worker                                "  col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"
498*e1eccf28SAndroid Build Coastguard Worker                                "  col.a = pow(col.a, UNI_Gamma);\n"
499*e1eccf28SAndroid Build Coastguard Worker                                "  gl_FragColor = col;\n"
500*e1eccf28SAndroid Build Coastguard Worker                                "}\n";
501*e1eccf28SAndroid Build Coastguard Worker 
502*e1eccf28SAndroid Build Coastguard Worker     const char *textureNames[] = { "Tex0" };
503*e1eccf28SAndroid Build Coastguard Worker     const size_t textureNamesLengths[] = { 4 };
504*e1eccf28SAndroid Build Coastguard Worker     size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
505*e1eccf28SAndroid Build Coastguard Worker 
506*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
507*e1eccf28SAndroid Build Coastguard Worker                                                                 RS_KIND_USER, false, 4);
508*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
509*e1eccf28SAndroid Build Coastguard Worker                                                                 RS_KIND_USER, false, 1);
510*e1eccf28SAndroid Build Coastguard Worker 
511*e1eccf28SAndroid Build Coastguard Worker     const char *ebn1[] = { "Color", "Gamma" };
512*e1eccf28SAndroid Build Coastguard Worker     const Element *ebe1[] = {colorElem.get(), gammaElem.get()};
513*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<const Element> constInput = Element::create(mRSC, 2, ebe1, ebn1);
514*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1);
515*e1eccf28SAndroid Build Coastguard Worker 
516*e1eccf28SAndroid Build Coastguard Worker     uintptr_t tmp[4];
517*e1eccf28SAndroid Build Coastguard Worker     tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
518*e1eccf28SAndroid Build Coastguard Worker     tmp[1] = (uintptr_t)inputType.get();
519*e1eccf28SAndroid Build Coastguard Worker     tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
520*e1eccf28SAndroid Build Coastguard Worker     tmp[3] = RS_TEXTURE_2D;
521*e1eccf28SAndroid Build Coastguard Worker 
522*e1eccf28SAndroid Build Coastguard Worker     mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
523*e1eccf28SAndroid Build Coastguard Worker                                                           RS_ALLOCATION_USAGE_SCRIPT |
524*e1eccf28SAndroid Build Coastguard Worker                                                           RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
525*e1eccf28SAndroid Build Coastguard Worker     ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
526*e1eccf28SAndroid Build Coastguard Worker                                               textureNames, numTextures, textureNamesLengths,
527*e1eccf28SAndroid Build Coastguard Worker                                               tmp, 4);
528*e1eccf28SAndroid Build Coastguard Worker     mFontShaderF.set(pf);
529*e1eccf28SAndroid Build Coastguard Worker     mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
530*e1eccf28SAndroid Build Coastguard Worker 
531*e1eccf28SAndroid Build Coastguard Worker     mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
532*e1eccf28SAndroid Build Coastguard Worker                                          RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
533*e1eccf28SAndroid Build Coastguard Worker                                          RS_SAMPLER_CLAMP).get());
534*e1eccf28SAndroid Build Coastguard Worker     mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
535*e1eccf28SAndroid Build Coastguard Worker 
536*e1eccf28SAndroid Build Coastguard Worker     mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
537*e1eccf28SAndroid Build Coastguard Worker                                                         false, false,
538*e1eccf28SAndroid Build Coastguard Worker                                                         RS_BLEND_SRC_SRC_ALPHA,
539*e1eccf28SAndroid Build Coastguard Worker                                                         RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
540*e1eccf28SAndroid Build Coastguard Worker                                                         RS_DEPTH_FUNC_ALWAYS).get());
541*e1eccf28SAndroid Build Coastguard Worker     mFontProgramStore->init();
542*e1eccf28SAndroid Build Coastguard Worker }
543*e1eccf28SAndroid Build Coastguard Worker 
initTextTexture()544*e1eccf28SAndroid Build Coastguard Worker void FontState::initTextTexture() {
545*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
546*e1eccf28SAndroid Build Coastguard Worker                                                                 RS_KIND_PIXEL_A, true, 1);
547*e1eccf28SAndroid Build Coastguard Worker 
548*e1eccf28SAndroid Build Coastguard Worker     // We will allocate a texture to initially hold 32 character bitmaps
549*e1eccf28SAndroid Build Coastguard Worker     mCacheHeight = 256;
550*e1eccf28SAndroid Build Coastguard Worker     mCacheWidth = 1024;
551*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), mCacheWidth, mCacheHeight);
552*e1eccf28SAndroid Build Coastguard Worker 
553*e1eccf28SAndroid Build Coastguard Worker     mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
554*e1eccf28SAndroid Build Coastguard Worker 
555*e1eccf28SAndroid Build Coastguard Worker 
556*e1eccf28SAndroid Build Coastguard Worker     Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
557*e1eccf28SAndroid Build Coastguard Worker                                 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
558*e1eccf28SAndroid Build Coastguard Worker     mTextTexture.set(cacheAlloc);
559*e1eccf28SAndroid Build Coastguard Worker 
560*e1eccf28SAndroid Build Coastguard Worker     // Split up our cache texture into lines of certain widths
561*e1eccf28SAndroid Build Coastguard Worker     int32_t nextLine = 0;
562*e1eccf28SAndroid Build Coastguard Worker     mCacheLines.push_back(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
563*e1eccf28SAndroid Build Coastguard Worker     nextLine += mCacheLines.back()->mMaxHeight;
564*e1eccf28SAndroid Build Coastguard Worker     mCacheLines.push_back(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
565*e1eccf28SAndroid Build Coastguard Worker     nextLine += mCacheLines.back()->mMaxHeight;
566*e1eccf28SAndroid Build Coastguard Worker     mCacheLines.push_back(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
567*e1eccf28SAndroid Build Coastguard Worker     nextLine += mCacheLines.back()->mMaxHeight;
568*e1eccf28SAndroid Build Coastguard Worker     mCacheLines.push_back(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
569*e1eccf28SAndroid Build Coastguard Worker     nextLine += mCacheLines.back()->mMaxHeight;
570*e1eccf28SAndroid Build Coastguard Worker     mCacheLines.push_back(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
571*e1eccf28SAndroid Build Coastguard Worker     nextLine += mCacheLines.back()->mMaxHeight;
572*e1eccf28SAndroid Build Coastguard Worker     mCacheLines.push_back(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
573*e1eccf28SAndroid Build Coastguard Worker     nextLine += mCacheLines.back()->mMaxHeight;
574*e1eccf28SAndroid Build Coastguard Worker     mCacheLines.push_back(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
575*e1eccf28SAndroid Build Coastguard Worker }
576*e1eccf28SAndroid Build Coastguard Worker 
577*e1eccf28SAndroid Build Coastguard Worker // Avoid having to reallocate memory and render quad by quad
initVertexArrayBuffers()578*e1eccf28SAndroid Build Coastguard Worker void FontState::initVertexArrayBuffers() {
579*e1eccf28SAndroid Build Coastguard Worker     // Now lets write index data
580*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
581*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), mMaxNumberOfQuads * 6);
582*e1eccf28SAndroid Build Coastguard Worker 
583*e1eccf28SAndroid Build Coastguard Worker     Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
584*e1eccf28SAndroid Build Coastguard Worker                                                           RS_ALLOCATION_USAGE_SCRIPT |
585*e1eccf28SAndroid Build Coastguard Worker                                                           RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
586*e1eccf28SAndroid Build Coastguard Worker     uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
587*e1eccf28SAndroid Build Coastguard Worker 
588*e1eccf28SAndroid Build Coastguard Worker     // Four verts, two triangles , six indices per quad
589*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
590*e1eccf28SAndroid Build Coastguard Worker         int32_t i6 = i * 6;
591*e1eccf28SAndroid Build Coastguard Worker         int32_t i4 = i * 4;
592*e1eccf28SAndroid Build Coastguard Worker 
593*e1eccf28SAndroid Build Coastguard Worker         indexPtr[i6 + 0] = i4 + 0;
594*e1eccf28SAndroid Build Coastguard Worker         indexPtr[i6 + 1] = i4 + 1;
595*e1eccf28SAndroid Build Coastguard Worker         indexPtr[i6 + 2] = i4 + 2;
596*e1eccf28SAndroid Build Coastguard Worker 
597*e1eccf28SAndroid Build Coastguard Worker         indexPtr[i6 + 3] = i4 + 0;
598*e1eccf28SAndroid Build Coastguard Worker         indexPtr[i6 + 4] = i4 + 2;
599*e1eccf28SAndroid Build Coastguard Worker         indexPtr[i6 + 5] = i4 + 3;
600*e1eccf28SAndroid Build Coastguard Worker     }
601*e1eccf28SAndroid Build Coastguard Worker 
602*e1eccf28SAndroid Build Coastguard Worker     indexAlloc->sendDirty(mRSC);
603*e1eccf28SAndroid Build Coastguard Worker 
604*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
605*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
606*e1eccf28SAndroid Build Coastguard Worker 
607*e1eccf28SAndroid Build Coastguard Worker     const char *ebn1[] = { "position", "texture0" };
608*e1eccf28SAndroid Build Coastguard Worker     const Element *ebe1[] = {posElem.get(), texElem.get()};
609*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
610*e1eccf28SAndroid Build Coastguard Worker 
611*e1eccf28SAndroid Build Coastguard Worker     ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(), mMaxNumberOfQuads * 4);
612*e1eccf28SAndroid Build Coastguard Worker 
613*e1eccf28SAndroid Build Coastguard Worker     Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
614*e1eccf28SAndroid Build Coastguard Worker                                                            RS_ALLOCATION_USAGE_SCRIPT);
615*e1eccf28SAndroid Build Coastguard Worker     mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
616*e1eccf28SAndroid Build Coastguard Worker 
617*e1eccf28SAndroid Build Coastguard Worker     mMesh.set(new Mesh(mRSC, 1, 1));
618*e1eccf28SAndroid Build Coastguard Worker     mMesh->setVertexBuffer(vertexAlloc, 0);
619*e1eccf28SAndroid Build Coastguard Worker     mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
620*e1eccf28SAndroid Build Coastguard Worker     mMesh->init();
621*e1eccf28SAndroid Build Coastguard Worker     mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
622*e1eccf28SAndroid Build Coastguard Worker     mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
623*e1eccf28SAndroid Build Coastguard Worker }
624*e1eccf28SAndroid Build Coastguard Worker 
625*e1eccf28SAndroid Build Coastguard Worker // We don't want to allocate anything unless we actually draw text
checkInit()626*e1eccf28SAndroid Build Coastguard Worker void FontState::checkInit() {
627*e1eccf28SAndroid Build Coastguard Worker     if (mInitialized) {
628*e1eccf28SAndroid Build Coastguard Worker         return;
629*e1eccf28SAndroid Build Coastguard Worker     }
630*e1eccf28SAndroid Build Coastguard Worker 
631*e1eccf28SAndroid Build Coastguard Worker     initTextTexture();
632*e1eccf28SAndroid Build Coastguard Worker     initRenderState();
633*e1eccf28SAndroid Build Coastguard Worker 
634*e1eccf28SAndroid Build Coastguard Worker     initVertexArrayBuffers();
635*e1eccf28SAndroid Build Coastguard Worker 
636*e1eccf28SAndroid Build Coastguard Worker     // We store a string with letters in a rough frequency of occurrence
637*e1eccf28SAndroid Build Coastguard Worker     mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
638*e1eccf28SAndroid Build Coastguard Worker                      "EISARNTOLCDUGPMHBYFVKWZXJQ"
639*e1eccf28SAndroid Build Coastguard Worker                      ",.?!()-+@;:`'0123456789";
640*e1eccf28SAndroid Build Coastguard Worker     mInitialized = true;
641*e1eccf28SAndroid Build Coastguard Worker }
642*e1eccf28SAndroid Build Coastguard Worker 
issueDrawCommand()643*e1eccf28SAndroid Build Coastguard Worker void FontState::issueDrawCommand() {
644*e1eccf28SAndroid Build Coastguard Worker     Context::PushState ps(mRSC);
645*e1eccf28SAndroid Build Coastguard Worker 
646*e1eccf28SAndroid Build Coastguard Worker     mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
647*e1eccf28SAndroid Build Coastguard Worker     mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
648*e1eccf28SAndroid Build Coastguard Worker     mRSC->setProgramFragment(mFontShaderF.get());
649*e1eccf28SAndroid Build Coastguard Worker     mRSC->setProgramStore(mFontProgramStore.get());
650*e1eccf28SAndroid Build Coastguard Worker 
651*e1eccf28SAndroid Build Coastguard Worker     if (mConstantsDirty) {
652*e1eccf28SAndroid Build Coastguard Worker         mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
653*e1eccf28SAndroid Build Coastguard Worker         mConstantsDirty = false;
654*e1eccf28SAndroid Build Coastguard Worker     }
655*e1eccf28SAndroid Build Coastguard Worker 
656*e1eccf28SAndroid Build Coastguard Worker     if (!mRSC->setupCheck()) {
657*e1eccf28SAndroid Build Coastguard Worker         return;
658*e1eccf28SAndroid Build Coastguard Worker     }
659*e1eccf28SAndroid Build Coastguard Worker 
660*e1eccf28SAndroid Build Coastguard Worker     mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
661*e1eccf28SAndroid Build Coastguard Worker }
662*e1eccf28SAndroid Build Coastguard Worker 
appendMeshQuad(float x1,float y1,float z1,float u1,float v1,float x2,float y2,float z2,float u2,float v2,float x3,float y3,float z3,float u3,float v3,float x4,float y4,float z4,float u4,float v4)663*e1eccf28SAndroid Build Coastguard Worker void FontState::appendMeshQuad(float x1, float y1, float z1,
664*e1eccf28SAndroid Build Coastguard Worker                                float u1, float v1,
665*e1eccf28SAndroid Build Coastguard Worker                                float x2, float y2, float z2,
666*e1eccf28SAndroid Build Coastguard Worker                                float u2, float v2,
667*e1eccf28SAndroid Build Coastguard Worker                                float x3, float y3, float z3,
668*e1eccf28SAndroid Build Coastguard Worker                                float u3, float v3,
669*e1eccf28SAndroid Build Coastguard Worker                                float x4, float y4, float z4,
670*e1eccf28SAndroid Build Coastguard Worker                                float u4, float v4) {
671*e1eccf28SAndroid Build Coastguard Worker     const uint32_t vertsPerQuad = 4;
672*e1eccf28SAndroid Build Coastguard Worker     const uint32_t floatsPerVert = 6;
673*e1eccf28SAndroid Build Coastguard Worker     float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
674*e1eccf28SAndroid Build Coastguard Worker 
675*e1eccf28SAndroid Build Coastguard Worker     if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
676*e1eccf28SAndroid Build Coastguard Worker         return;
677*e1eccf28SAndroid Build Coastguard Worker     }
678*e1eccf28SAndroid Build Coastguard Worker 
679*e1eccf28SAndroid Build Coastguard Worker     /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
680*e1eccf28SAndroid Build Coastguard Worker     ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
681*e1eccf28SAndroid Build Coastguard Worker     ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
682*e1eccf28SAndroid Build Coastguard Worker     ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
683*e1eccf28SAndroid Build Coastguard Worker 
684*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = x1;
685*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = y1;
686*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = z1;
687*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = 0;
688*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = u1;
689*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = v1;
690*e1eccf28SAndroid Build Coastguard Worker 
691*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = x2;
692*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = y2;
693*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = z2;
694*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = 0;
695*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = u2;
696*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = v2;
697*e1eccf28SAndroid Build Coastguard Worker 
698*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = x3;
699*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = y3;
700*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = z3;
701*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = 0;
702*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = u3;
703*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = v3;
704*e1eccf28SAndroid Build Coastguard Worker 
705*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = x4;
706*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = y4;
707*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = z4;
708*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = 0;
709*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = u4;
710*e1eccf28SAndroid Build Coastguard Worker     (*currentPos++) = v4;
711*e1eccf28SAndroid Build Coastguard Worker 
712*e1eccf28SAndroid Build Coastguard Worker     mCurrentQuadIndex ++;
713*e1eccf28SAndroid Build Coastguard Worker 
714*e1eccf28SAndroid Build Coastguard Worker     if (mCurrentQuadIndex == mMaxNumberOfQuads) {
715*e1eccf28SAndroid Build Coastguard Worker         issueDrawCommand();
716*e1eccf28SAndroid Build Coastguard Worker         mCurrentQuadIndex = 0;
717*e1eccf28SAndroid Build Coastguard Worker     }
718*e1eccf28SAndroid Build Coastguard Worker }
719*e1eccf28SAndroid Build Coastguard Worker 
getRemainingCacheCapacity()720*e1eccf28SAndroid Build Coastguard Worker uint32_t FontState::getRemainingCacheCapacity() {
721*e1eccf28SAndroid Build Coastguard Worker     uint32_t remainingCapacity = 0;
722*e1eccf28SAndroid Build Coastguard Worker     uint32_t totalPixels = 0;
723*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
724*e1eccf28SAndroid Build Coastguard Worker          remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
725*e1eccf28SAndroid Build Coastguard Worker          totalPixels += mCacheLines[i]->mMaxWidth;
726*e1eccf28SAndroid Build Coastguard Worker     }
727*e1eccf28SAndroid Build Coastguard Worker     remainingCapacity = (remainingCapacity * 100) / totalPixels;
728*e1eccf28SAndroid Build Coastguard Worker     return remainingCapacity;
729*e1eccf28SAndroid Build Coastguard Worker }
730*e1eccf28SAndroid Build Coastguard Worker 
precacheLatin(Font * font)731*e1eccf28SAndroid Build Coastguard Worker void FontState::precacheLatin(Font *font) {
732*e1eccf28SAndroid Build Coastguard Worker     // Remaining capacity is measured in %
733*e1eccf28SAndroid Build Coastguard Worker     uint32_t remainingCapacity = getRemainingCacheCapacity();
734*e1eccf28SAndroid Build Coastguard Worker     uint32_t precacheIdx = 0;
735*e1eccf28SAndroid Build Coastguard Worker     const size_t l = strlen(mLatinPrecache);
736*e1eccf28SAndroid Build Coastguard Worker     while ((remainingCapacity > 25) && (precacheIdx < l)) {
737*e1eccf28SAndroid Build Coastguard Worker         font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
738*e1eccf28SAndroid Build Coastguard Worker         remainingCapacity = getRemainingCacheCapacity();
739*e1eccf28SAndroid Build Coastguard Worker         precacheIdx ++;
740*e1eccf28SAndroid Build Coastguard Worker     }
741*e1eccf28SAndroid Build Coastguard Worker }
742*e1eccf28SAndroid Build Coastguard Worker 
743*e1eccf28SAndroid Build Coastguard Worker 
renderText(const char * text,uint32_t len,int32_t x,int32_t y,uint32_t startIndex,int32_t numGlyphs,Font::RenderMode mode,Font::Rect * bounds,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH)744*e1eccf28SAndroid Build Coastguard Worker void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
745*e1eccf28SAndroid Build Coastguard Worker                            uint32_t startIndex, int32_t numGlyphs,
746*e1eccf28SAndroid Build Coastguard Worker                            Font::RenderMode mode,
747*e1eccf28SAndroid Build Coastguard Worker                            Font::Rect *bounds,
748*e1eccf28SAndroid Build Coastguard Worker                            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
749*e1eccf28SAndroid Build Coastguard Worker     checkInit();
750*e1eccf28SAndroid Build Coastguard Worker 
751*e1eccf28SAndroid Build Coastguard Worker     // Render code here
752*e1eccf28SAndroid Build Coastguard Worker     Font *currentFont = mRSC->getFont();
753*e1eccf28SAndroid Build Coastguard Worker     if (!currentFont) {
754*e1eccf28SAndroid Build Coastguard Worker         if (!mDefault.get()) {
755*e1eccf28SAndroid Build Coastguard Worker             char fullPath[1024];
756*e1eccf28SAndroid Build Coastguard Worker             const char * root = getenv("ANDROID_ROOT");
757*e1eccf28SAndroid Build Coastguard Worker             rsAssert(strlen(root) < 256);
758*e1eccf28SAndroid Build Coastguard Worker             strlcpy(fullPath, root, sizeof(fullPath));
759*e1eccf28SAndroid Build Coastguard Worker             strlcat(fullPath, "/fonts/Roboto-Regular.ttf", sizeof(fullPath));
760*e1eccf28SAndroid Build Coastguard Worker             fullPath[sizeof(fullPath)-1] = '\0';
761*e1eccf28SAndroid Build Coastguard Worker             mDefault.set(Font::create(mRSC, fullPath, 8, mRSC->getDPI()));
762*e1eccf28SAndroid Build Coastguard Worker         }
763*e1eccf28SAndroid Build Coastguard Worker         currentFont = mDefault.get();
764*e1eccf28SAndroid Build Coastguard Worker     }
765*e1eccf28SAndroid Build Coastguard Worker     if (!currentFont) {
766*e1eccf28SAndroid Build Coastguard Worker         ALOGE("Unable to initialize any fonts");
767*e1eccf28SAndroid Build Coastguard Worker         return;
768*e1eccf28SAndroid Build Coastguard Worker     }
769*e1eccf28SAndroid Build Coastguard Worker 
770*e1eccf28SAndroid Build Coastguard Worker     // Cull things that are off the screen
771*e1eccf28SAndroid Build Coastguard Worker     mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
772*e1eccf28SAndroid Build Coastguard Worker     mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
773*e1eccf28SAndroid Build Coastguard Worker 
774*e1eccf28SAndroid Build Coastguard Worker     currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
775*e1eccf28SAndroid Build Coastguard Worker                            mode, bounds, bitmap, bitmapW, bitmapH);
776*e1eccf28SAndroid Build Coastguard Worker 
777*e1eccf28SAndroid Build Coastguard Worker     if (mCurrentQuadIndex != 0) {
778*e1eccf28SAndroid Build Coastguard Worker         issueDrawCommand();
779*e1eccf28SAndroid Build Coastguard Worker         mCurrentQuadIndex = 0;
780*e1eccf28SAndroid Build Coastguard Worker     }
781*e1eccf28SAndroid Build Coastguard Worker }
782*e1eccf28SAndroid Build Coastguard Worker 
measureText(const char * text,uint32_t len,Font::Rect * bounds)783*e1eccf28SAndroid Build Coastguard Worker void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
784*e1eccf28SAndroid Build Coastguard Worker     renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
785*e1eccf28SAndroid Build Coastguard Worker     bounds->bottom = - bounds->bottom;
786*e1eccf28SAndroid Build Coastguard Worker     bounds->top = - bounds->top;
787*e1eccf28SAndroid Build Coastguard Worker }
788*e1eccf28SAndroid Build Coastguard Worker 
setFontColor(float r,float g,float b,float a)789*e1eccf28SAndroid Build Coastguard Worker void FontState::setFontColor(float r, float g, float b, float a) {
790*e1eccf28SAndroid Build Coastguard Worker     mConstants.mFontColor[0] = r;
791*e1eccf28SAndroid Build Coastguard Worker     mConstants.mFontColor[1] = g;
792*e1eccf28SAndroid Build Coastguard Worker     mConstants.mFontColor[2] = b;
793*e1eccf28SAndroid Build Coastguard Worker     mConstants.mFontColor[3] = a;
794*e1eccf28SAndroid Build Coastguard Worker 
795*e1eccf28SAndroid Build Coastguard Worker     mConstants.mGamma = 1.0f;
796*e1eccf28SAndroid Build Coastguard Worker     const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
797*e1eccf28SAndroid Build Coastguard Worker     if (luminance <= mBlackThreshold) {
798*e1eccf28SAndroid Build Coastguard Worker         mConstants.mGamma = mBlackGamma;
799*e1eccf28SAndroid Build Coastguard Worker     } else if (luminance >= mWhiteThreshold) {
800*e1eccf28SAndroid Build Coastguard Worker         mConstants.mGamma = mWhiteGamma;
801*e1eccf28SAndroid Build Coastguard Worker     }
802*e1eccf28SAndroid Build Coastguard Worker 
803*e1eccf28SAndroid Build Coastguard Worker     mConstantsDirty = true;
804*e1eccf28SAndroid Build Coastguard Worker }
805*e1eccf28SAndroid Build Coastguard Worker 
getFontColor(float * r,float * g,float * b,float * a) const806*e1eccf28SAndroid Build Coastguard Worker void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
807*e1eccf28SAndroid Build Coastguard Worker     *r = mConstants.mFontColor[0];
808*e1eccf28SAndroid Build Coastguard Worker     *g = mConstants.mFontColor[1];
809*e1eccf28SAndroid Build Coastguard Worker     *b = mConstants.mFontColor[2];
810*e1eccf28SAndroid Build Coastguard Worker     *a = mConstants.mFontColor[3];
811*e1eccf28SAndroid Build Coastguard Worker }
812*e1eccf28SAndroid Build Coastguard Worker 
deinit(Context * rsc)813*e1eccf28SAndroid Build Coastguard Worker void FontState::deinit(Context *rsc) {
814*e1eccf28SAndroid Build Coastguard Worker     mInitialized = false;
815*e1eccf28SAndroid Build Coastguard Worker 
816*e1eccf28SAndroid Build Coastguard Worker     mFontShaderFConstant.clear();
817*e1eccf28SAndroid Build Coastguard Worker 
818*e1eccf28SAndroid Build Coastguard Worker     mMesh.clear();
819*e1eccf28SAndroid Build Coastguard Worker 
820*e1eccf28SAndroid Build Coastguard Worker     mFontShaderF.clear();
821*e1eccf28SAndroid Build Coastguard Worker     mFontSampler.clear();
822*e1eccf28SAndroid Build Coastguard Worker     mFontProgramStore.clear();
823*e1eccf28SAndroid Build Coastguard Worker 
824*e1eccf28SAndroid Build Coastguard Worker     mTextTexture.clear();
825*e1eccf28SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
826*e1eccf28SAndroid Build Coastguard Worker         delete mCacheLines[i];
827*e1eccf28SAndroid Build Coastguard Worker     }
828*e1eccf28SAndroid Build Coastguard Worker     mCacheLines.clear();
829*e1eccf28SAndroid Build Coastguard Worker 
830*e1eccf28SAndroid Build Coastguard Worker     mDefault.clear();
831*e1eccf28SAndroid Build Coastguard Worker #ifndef ANDROID_RS_SERIALIZE
832*e1eccf28SAndroid Build Coastguard Worker     if (mLibrary) {
833*e1eccf28SAndroid Build Coastguard Worker         FT_Done_FreeType( mLibrary );
834*e1eccf28SAndroid Build Coastguard Worker         mLibrary = nullptr;
835*e1eccf28SAndroid Build Coastguard Worker     }
836*e1eccf28SAndroid Build Coastguard Worker #endif //ANDROID_RS_SERIALIZE
837*e1eccf28SAndroid Build Coastguard Worker }
838*e1eccf28SAndroid Build Coastguard Worker 
839*e1eccf28SAndroid Build Coastguard Worker #ifndef ANDROID_RS_SERIALIZE
fitBitmap(FT_Bitmap_ * bitmap,uint32_t * retOriginX,uint32_t * retOriginY)840*e1eccf28SAndroid Build Coastguard Worker bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
841*e1eccf28SAndroid Build Coastguard Worker     if ((uint32_t)bitmap->rows > mMaxHeight) {
842*e1eccf28SAndroid Build Coastguard Worker         return false;
843*e1eccf28SAndroid Build Coastguard Worker     }
844*e1eccf28SAndroid Build Coastguard Worker 
845*e1eccf28SAndroid Build Coastguard Worker     if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
846*e1eccf28SAndroid Build Coastguard Worker         *retOriginX = mCurrentCol;
847*e1eccf28SAndroid Build Coastguard Worker         *retOriginY = mCurrentRow;
848*e1eccf28SAndroid Build Coastguard Worker         mCurrentCol += bitmap->width;
849*e1eccf28SAndroid Build Coastguard Worker         mDirty = true;
850*e1eccf28SAndroid Build Coastguard Worker        return true;
851*e1eccf28SAndroid Build Coastguard Worker     }
852*e1eccf28SAndroid Build Coastguard Worker 
853*e1eccf28SAndroid Build Coastguard Worker     return false;
854*e1eccf28SAndroid Build Coastguard Worker }
855*e1eccf28SAndroid Build Coastguard Worker #endif //ANDROID_RS_SERIALIZE
856*e1eccf28SAndroid Build Coastguard Worker 
rsi_FontCreateFromFile(Context * rsc,char const * name,size_t name_length,float fontSize,uint32_t dpi)857*e1eccf28SAndroid Build Coastguard Worker RsFont rsi_FontCreateFromFile(Context *rsc,
858*e1eccf28SAndroid Build Coastguard Worker                               char const *name, size_t name_length,
859*e1eccf28SAndroid Build Coastguard Worker                               float fontSize, uint32_t dpi) {
860*e1eccf28SAndroid Build Coastguard Worker     Font *newFont = Font::create(rsc, name, fontSize, dpi);
861*e1eccf28SAndroid Build Coastguard Worker     if (newFont) {
862*e1eccf28SAndroid Build Coastguard Worker         newFont->incUserRef();
863*e1eccf28SAndroid Build Coastguard Worker     }
864*e1eccf28SAndroid Build Coastguard Worker     return newFont;
865*e1eccf28SAndroid Build Coastguard Worker }
866*e1eccf28SAndroid Build Coastguard Worker 
rsi_FontCreateFromMemory(Context * rsc,char const * name,size_t name_length,float fontSize,uint32_t dpi,const void * data,size_t data_length)867*e1eccf28SAndroid Build Coastguard Worker RsFont rsi_FontCreateFromMemory(Context *rsc,
868*e1eccf28SAndroid Build Coastguard Worker                                 char const *name, size_t name_length,
869*e1eccf28SAndroid Build Coastguard Worker                                 float fontSize, uint32_t dpi,
870*e1eccf28SAndroid Build Coastguard Worker                                 const void *data, size_t data_length) {
871*e1eccf28SAndroid Build Coastguard Worker     Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
872*e1eccf28SAndroid Build Coastguard Worker     if (newFont) {
873*e1eccf28SAndroid Build Coastguard Worker         newFont->incUserRef();
874*e1eccf28SAndroid Build Coastguard Worker     }
875*e1eccf28SAndroid Build Coastguard Worker     return newFont;
876*e1eccf28SAndroid Build Coastguard Worker }
877*e1eccf28SAndroid Build Coastguard Worker 
878*e1eccf28SAndroid Build Coastguard Worker } // namespace renderscript
879*e1eccf28SAndroid Build Coastguard Worker } // namespace android
880