blob: ce674f420b114d138cfb96fac1a24ff16f79eee5 [file] [log] [blame]
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -07001
2/*
3 * Copyright (C) 2009 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070018#include "rsContext.h"
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070019
20#include "rsFont.h"
21#include "rsProgramFragment.h"
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -070022#include <cutils/properties.h>
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080023
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070024#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080025#include <ft2build.h>
26#include FT_FREETYPE_H
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070027#include FT_BITMAP_H
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070028#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070029
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070030using namespace android;
31using namespace android::renderscript;
32
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080033Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070034 mInitialized = false;
35 mHasKerning = false;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -070036 mFace = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070037}
38
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080039bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070040#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080041 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070042 LOGE("Reinitialization of fonts not supported");
43 return false;
44 }
45
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080046 FT_Error error = 0;
47 if (data != NULL && dataLen > 0) {
48 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
49 } else {
50 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
51 }
52
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080053 if (error) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080054 LOGE("Unable to initialize font %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070055 return false;
56 }
57
58 mFontName = name;
59 mFontSize = fontSize;
60 mDpi = dpi;
61
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080062 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080063 if (error) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080064 LOGE("Unable to set font size on %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070065 return false;
66 }
67
68 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070069
70 mInitialized = true;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070071#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070072 return true;
73}
74
Jason Sams2e8665d2011-01-27 00:14:13 -080075void Font::preDestroy() const {
76 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
77 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
78 mRSC->mStateFont.mActiveFonts.removeAt(ct);
79 break;
80 }
81 }
82}
83
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080084void Font::invalidateTextureCache() {
85 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070086 mCachedGlyphs.valueAt(i)->mIsValid = false;
87 }
88}
89
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080090void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070091 FontState *state = &mRSC->mStateFont;
92
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070093 int32_t nPenX = x + glyph->mBitmapLeft;
94 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070095
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070096 float u1 = glyph->mBitmapMinU;
97 float u2 = glyph->mBitmapMaxU;
98 float v1 = glyph->mBitmapMinV;
99 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700100
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700101 int32_t width = (int32_t) glyph->mBitmapWidth;
102 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700103
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700104 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
105 nPenX + width, nPenY, 0, u2, v2,
106 nPenX + width, nPenY - height, 0, u2, v1,
107 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700108}
109
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700110void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
111 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
112 int32_t nPenX = x + glyph->mBitmapLeft;
113 int32_t nPenY = y + glyph->mBitmapTop;
114
115 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
116 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
117
118 FontState *state = &mRSC->mStateFont;
119 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
120 const uint8_t* cacheBuffer = state->getTextTextureData();
121
122 uint32_t cacheX = 0, cacheY = 0;
123 int32_t bX = 0, bY = 0;
124 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
125 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
126 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
127 LOGE("Skipping invalid index");
128 continue;
129 }
130 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
131 bitmap[bY * bitmapW + bX] = tempCol;
132 }
133 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700134}
135
136void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
137 int32_t nPenX = x + glyph->mBitmapLeft;
138 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
139
140 int32_t width = (int32_t) glyph->mBitmapWidth;
141 int32_t height = (int32_t) glyph->mBitmapHeight;
142
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800143 // 0, 0 is top left, so bottom is a positive number
144 if (bounds->bottom < nPenY) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700145 bounds->bottom = nPenY;
146 }
147 if (bounds->left > nPenX) {
148 bounds->left = nPenX;
149 }
150 if (bounds->right < nPenX + width) {
151 bounds->right = nPenX + width;
152 }
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800153 if (bounds->top > nPenY - height) {
154 bounds->top = nPenY - height;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700155 }
156}
157
158void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
159 uint32_t start, int32_t numGlyphs,
160 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800161 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
162 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700163 return;
164 }
165
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800166 if (mode == Font::MEASURE) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700167 if (bounds == NULL) {
168 LOGE("No return rectangle provided to measure text");
169 return;
170 }
171 // Reset min and max of the bounding box to something large
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800172 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700173 }
174
175 int32_t penX = x, penY = y;
176 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800177 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700178 glyphsLeft = numGlyphs;
179 }
180
181 size_t index = start;
182 size_t nextIndex = 0;
183
184 while (glyphsLeft > 0) {
185
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800186 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700187
188 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800189 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700190 break;
191 }
192
193 // Move to the next character in the array
194 index = nextIndex;
195
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700196 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700197
198 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800199 if (cachedGlyph->mIsValid) {
200 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700201 case FRAMEBUFFER:
202 drawCachedGlyph(cachedGlyph, penX, penY);
203 break;
204 case BITMAP:
205 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
206 break;
207 case MEASURE:
208 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
209 break;
210 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700211 }
212
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800213 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700214
215 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800216 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700217 glyphsLeft --;
218 }
219 }
220}
221
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700222Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
223
224 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800225 if (cachedGlyph == NULL) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700226 cachedGlyph = cacheGlyph((uint32_t)utfChar);
227 }
228 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800229 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700230 updateGlyphCache(cachedGlyph);
231 }
232
233 return cachedGlyph;
234}
235
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800236void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700237#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700238 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800239 if (error) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700240 LOGE("Couldn't load glyph.");
241 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700242 }
243
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800244 glyph->mAdvanceX = mFace->glyph->advance.x;
245 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700246 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
247 glyph->mBitmapTop = mFace->glyph->bitmap_top;
248
249 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
250
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700251 // Now copy the bitmap into the cache texture
252 uint32_t startX = 0;
253 uint32_t startY = 0;
254
255 // Let the font state figure out where to put the bitmap
256 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700257 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700258
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800259 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700260 return;
261 }
262
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700263 uint32_t endX = startX + bitmap->width;
264 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700265
266 glyph->mBitmapMinX = startX;
267 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700268 glyph->mBitmapWidth = bitmap->width;
269 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700270
271 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
272 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
273
274 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
275 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
276 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
277 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700278#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700279}
280
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800281Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700282 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
283 mCachedGlyphs.add(glyph, newGlyph);
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700284#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700285 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
286 newGlyph->mIsValid = false;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700287#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700288 updateGlyphCache(newGlyph);
289
290 return newGlyph;
291}
292
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800293Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
294 const void *data, uint32_t dataLen) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700295 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700296 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
297
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800298 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700299 Font *ithFont = activeFonts[i];
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800300 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700301 return ithFont;
302 }
303 }
304
305 Font *newFont = new Font(rsc);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800306 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800307 if (isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700308 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700309 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700310 return newFont;
311 }
312
Jason Sams225afd32010-10-21 14:06:55 -0700313 ObjectBase::checkDelete(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700314 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700315}
316
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800317Font::~Font() {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700318#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800319 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700320 FT_Done_Face(mFace);
321 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700322#endif
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700323
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800324 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700325 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700326 delete glyph;
327 }
328}
329
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800330FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700331 mInitialized = false;
332 mMaxNumberOfQuads = 1024;
333 mCurrentQuadIndex = 0;
334 mRSC = NULL;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700335#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700336 mLibrary = NULL;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700337#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700338
339 // Get the renderer properties
340 char property[PROPERTY_VALUE_MAX];
341
342 // Get the gamma
343 float gamma = DEFAULT_TEXT_GAMMA;
344 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700345 gamma = atof(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700346 }
347
348 // Get the black gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700349 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700350 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700351 blackThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700352 }
353 mBlackThreshold = (float)(blackThreshold) / 255.0f;
354
355 // Get the white gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700356 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700357 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700358 whiteThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700359 }
360 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
361
362 // Compute the gamma tables
363 mBlackGamma = gamma;
364 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700365
366 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700367}
368
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800369FontState::~FontState() {
370 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700371 delete mCacheLines[i];
372 }
373
374 rsAssert(!mActiveFonts.size());
375}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700376#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800377FT_Library FontState::getLib() {
378 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700379 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800380 if (error) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700381 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700382 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700383 }
384 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700385
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700386 return mLibrary;
387}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700388#endif //ANDROID_RS_SERIALIZE
389
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700390
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800391void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700392 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700393}
394
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800395void FontState::flushAllAndInvalidate() {
396 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700397 issueDrawCommand();
398 mCurrentQuadIndex = 0;
399 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800400 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700401 mActiveFonts[i]->invalidateTextureCache();
402 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800403 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700404 mCacheLines[i]->mCurrentCol = 0;
405 }
406}
407
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700408#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800409bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700410 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800411 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700412 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
413 return false;
414 }
415
416 // Now copy the bitmap into the cache texture
417 uint32_t startX = 0;
418 uint32_t startY = 0;
419
420 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800421 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700422 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800423 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700424 break;
425 }
426 }
427
428 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800429 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700430 flushAllAndInvalidate();
431
432 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800433 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700434 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800435 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700436 break;
437 }
438 }
439
440 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800441 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700442 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
443 return false;
444 }
445 }
446
447 *retOriginX = startX;
448 *retOriginY = startY;
449
450 uint32_t endX = startX + bitmap->width;
451 uint32_t endY = startY + bitmap->rows;
452
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700453 uint32_t cacheWidth = getCacheTextureType()->getDimX();
454
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700455 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
456 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700457
458 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800459 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
460 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700461 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700462 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
463 }
464 }
465
466 // This will dirty the texture and the shader so next time
467 // we draw it will upload the data
Jason Samseb4fe182011-05-26 16:33:01 -0700468
469 mTextTexture->sendDirty(mRSC);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700470 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700471
472 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800473 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700474 LOGE("Cache Line: H: %u Empty Space: %f",
475 mCacheLines[i]->mMaxHeight,
476 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
477
478 }*/
479
480 return true;
481}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700482#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700483
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800484void FontState::initRenderState() {
Alex Sakhartchouk7ffcaf22010-10-06 11:15:01 -0700485 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700486 shaderString.append("void main() {\n");
487 shaderString.append(" lowp vec4 col = UNI_Color;\n");
488 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700489 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700490 shaderString.append(" gl_FragColor = col;\n");
491 shaderString.append("}\n");
492
493 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700494 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700495 mRSC->mStateElement.elementBuilderBegin();
496 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700497 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700498 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
499
Jason Samsf0c1df42010-10-26 13:09:17 -0700500 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700501
502 uint32_t tmp[4];
503 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
504 tmp[1] = (uint32_t)inputType;
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800505 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
506 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700507
Jason Samseb4fe182011-05-26 16:33:01 -0700508 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType,
Jason Sams366c9c82010-12-08 16:14:36 -0800509 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700510 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
511 shaderString.length(), tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700512 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700513 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700514
515 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
516 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
517 mFontSampler.set(sampler);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700518 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700519
Jason Sams721acc42011-04-06 11:23:54 -0700520 ProgramStore *fontStore = new ProgramStore(mRSC, true, true, true, true,
521 false, false,
Jason Sams00237f12011-04-06 11:44:47 -0700522 RS_BLEND_SRC_SRC_ALPHA,
523 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
Jason Sams721acc42011-04-06 11:23:54 -0700524 RS_DEPTH_FUNC_ALWAYS);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700525 mFontProgramStore.set(fontStore);
Jason Sams8feea4e2011-03-18 15:03:25 -0700526 mFontProgramStore->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700527}
528
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800529void FontState::initTextTexture() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700530 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
531
532 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsf0c1df42010-10-26 13:09:17 -0700533 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700534
Jason Samseb4fe182011-05-26 16:33:01 -0700535 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType,
536 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700537 mTextTexture.set(cacheAlloc);
Jason Samsb7e83bd2010-12-15 01:41:00 -0800538 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700539
540 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700541 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700542 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
543 nextLine += mCacheLines.top()->mMaxHeight;
544 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
545 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700546 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
547 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700548 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
549 nextLine += mCacheLines.top()->mMaxHeight;
550 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
551 nextLine += mCacheLines.top()->mMaxHeight;
552 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
553 nextLine += mCacheLines.top()->mMaxHeight;
554 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
555}
556
557// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800558void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700559 // Now lets write index data
560 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700561 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsf0c1df42010-10-26 13:09:17 -0700562 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700563
Jason Samseb4fe182011-05-26 16:33:01 -0700564 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType,
565 RS_ALLOCATION_USAGE_SCRIPT |
566 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700567 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
568
569 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800570 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700571 int32_t i6 = i * 6;
572 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700573
574 indexPtr[i6 + 0] = i4 + 0;
575 indexPtr[i6 + 1] = i4 + 1;
576 indexPtr[i6 + 2] = i4 + 2;
577
578 indexPtr[i6 + 3] = i4 + 0;
579 indexPtr[i6 + 4] = i4 + 2;
580 indexPtr[i6 + 5] = i4 + 3;
581 }
582
Jason Samseb4fe182011-05-26 16:33:01 -0700583 indexAlloc->sendDirty(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700584
585 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
586 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
587
Alex Sakhartchouk64cd98e2010-10-18 17:18:50 -0700588 mRSC->mStateElement.elementBuilderBegin();
589 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
590 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
591 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700592
Jason Samsf0c1df42010-10-26 13:09:17 -0700593 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
594 mMaxNumberOfQuads * 4,
595 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700596
Jason Samseb4fe182011-05-26 16:33:01 -0700597 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType,
598 RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700599 mTextMeshPtr = (float*)vertexAlloc->getPtr();
600
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700601 mMesh.set(new Mesh(mRSC, 1, 1));
602 mMesh->setVertexBuffer(vertexAlloc, 0);
603 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
604 mMesh->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700605}
606
607// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800608void FontState::checkInit() {
609 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700610 return;
611 }
612
613 initTextTexture();
614 initRenderState();
615
616 initVertexArrayBuffers();
617
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700618 // We store a string with letters in a rough frequency of occurrence
619 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
620 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
621 mLatinPrecache += String8(",.?!()-+@;:`'");
622 mLatinPrecache += String8("0123456789");
623
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700624 mInitialized = true;
625}
626
627void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800628 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700629
Jason Sams60709252010-11-17 15:29:32 -0800630 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
631 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
632 mRSC->setProgramFragment(mFontShaderF.get());
633 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700634
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800635 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800636 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700637 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700638 }
639
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700640 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700641 return;
642 }
643
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700644 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700645}
646
647void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800648 float u1, float v1,
649 float x2, float y2, float z2,
650 float u2, float v2,
651 float x3, float y3, float z3,
652 float u3, float v3,
653 float x4, float y4, float z4,
654 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700655 const uint32_t vertsPerQuad = 4;
656 const uint32_t floatsPerVert = 5;
657 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
658
659 // Cull things that are off the screen
660 float width = (float)mRSC->getWidth();
661 float height = (float)mRSC->getHeight();
662
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800663 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700664 return;
665 }
666
667 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
668 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
669 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
670 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
671
672 (*currentPos++) = x1;
673 (*currentPos++) = y1;
674 (*currentPos++) = z1;
675 (*currentPos++) = u1;
676 (*currentPos++) = v1;
677
678 (*currentPos++) = x2;
679 (*currentPos++) = y2;
680 (*currentPos++) = z2;
681 (*currentPos++) = u2;
682 (*currentPos++) = v2;
683
684 (*currentPos++) = x3;
685 (*currentPos++) = y3;
686 (*currentPos++) = z3;
687 (*currentPos++) = u3;
688 (*currentPos++) = v3;
689
690 (*currentPos++) = x4;
691 (*currentPos++) = y4;
692 (*currentPos++) = z4;
693 (*currentPos++) = u4;
694 (*currentPos++) = v4;
695
696 mCurrentQuadIndex ++;
697
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800698 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700699 issueDrawCommand();
700 mCurrentQuadIndex = 0;
701 }
702}
703
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700704uint32_t FontState::getRemainingCacheCapacity() {
705 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700706 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800707 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700708 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
709 totalPixels += mCacheLines[i]->mMaxWidth;
710 }
711 remainingCapacity = (remainingCapacity * 100) / totalPixels;
712 return remainingCapacity;
713}
714
715void FontState::precacheLatin(Font *font) {
716 // Remaining capacity is measured in %
717 uint32_t remainingCapacity = getRemainingCacheCapacity();
718 uint32_t precacheIdx = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800719 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700720 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
721 remainingCapacity = getRemainingCacheCapacity();
722 precacheIdx ++;
723 }
724}
725
726
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700727void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
728 uint32_t startIndex, int32_t numGlyphs,
729 Font::RenderMode mode,
730 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800731 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700732 checkInit();
733
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700734 // Render code here
735 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800736 if (!currentFont) {
737 if (!mDefault.get()) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800738 String8 fontsDir("/fonts/DroidSans.ttf");
739 String8 fullPath(getenv("ANDROID_ROOT"));
740 fullPath += fontsDir;
741
Alex Sakhartchouk7b3e9bd2011-03-16 19:28:25 -0700742 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700743 }
744 currentFont = mDefault.get();
745 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800746 if (!currentFont) {
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700747 LOGE("Unable to initialize any fonts");
748 return;
749 }
750
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700751 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
752 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700753
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800754 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700755 issueDrawCommand();
756 mCurrentQuadIndex = 0;
757 }
758}
759
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700760void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
761 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800762 bounds->bottom = - bounds->bottom;
763 bounds->top = - bounds->top;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700764}
765
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700766void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700767 mConstants.mFontColor[0] = r;
768 mConstants.mFontColor[1] = g;
769 mConstants.mFontColor[2] = b;
770 mConstants.mFontColor[3] = a;
771
772 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700773 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700774 if (luminance <= mBlackThreshold) {
775 mConstants.mGamma = mBlackGamma;
776 } else if (luminance >= mWhiteThreshold) {
777 mConstants.mGamma = mWhiteGamma;
778 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700779
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700780 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700781}
782
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700783void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700784 *r = mConstants.mFontColor[0];
785 *g = mConstants.mFontColor[1];
786 *b = mConstants.mFontColor[2];
787 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700788}
789
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800790void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700791 mInitialized = false;
792
Stephen Hines01b7d292010-09-28 15:45:45 -0700793 mFontShaderFConstant.clear();
794
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700795 mMesh.clear();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700796
797 mFontShaderF.clear();
798 mFontSampler.clear();
799 mFontProgramStore.clear();
800
801 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800802 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700803 delete mCacheLines[i];
804 }
805 mCacheLines.clear();
806
807 mDefault.clear();
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700808#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800809 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700810 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700811 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700812 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700813#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700814}
815
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700816#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800817bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
818 if ((uint32_t)bitmap->rows > mMaxHeight) {
819 return false;
820 }
821
822 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
823 *retOriginX = mCurrentCol;
824 *retOriginY = mCurrentRow;
825 mCurrentCol += bitmap->width;
826 mDirty = true;
827 return true;
828 }
829
830 return false;
831}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700832#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800833
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700834namespace android {
835namespace renderscript {
836
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700837RsFont rsi_FontCreateFromFile(Context *rsc,
838 char const *name, size_t name_length,
839 float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700840 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800841 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700842 newFont->incUserRef();
843 }
844 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700845}
846
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700847RsFont rsi_FontCreateFromMemory(Context *rsc,
848 char const *name, size_t name_length,
849 float fontSize, uint32_t dpi,
850 const void *data, size_t data_length) {
851 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800852 if (newFont) {
853 newFont->incUserRef();
854 }
855 return newFont;
856}
857
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700858} // renderscript
859} // android