blob: 4f21b3b0140da1a603c6ca756ed499575d905c06 [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) {
Steve Blockaf12ac62012-01-06 19:20:56 +000042 ALOGE("Reinitialization of fonts not supported");
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070043 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) {
Steve Blockaf12ac62012-01-06 19:20:56 +000054 ALOGE("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) {
Steve Blockaf12ac62012-01-06 19:20:56 +000064 ALOGE("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) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000127 ALOGE("Skipping invalid index");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700128 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) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000168 ALOGE("No return rectangle provided to measure text");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700169 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) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000240 ALOGE("Couldn't load glyph.");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700241 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) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000381 ALOGE("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) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000412 ALOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700413 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) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000442 ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700443 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 ++) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000474 ALOGE("Cache Line: H: %u Empty Space: %f",
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700475 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
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700493 ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
494 ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
495 Element::Builder builder;
496 builder.add(colorElem.get(), "Color", 1);
497 builder.add(gammaElem.get(), "Gamma", 1);
498 ObjectBaseRef<const Element> constInput = builder.create(mRSC);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700499
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700500 ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 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;
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700504 tmp[1] = (uint32_t)inputType.get();
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
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700508 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
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
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700515 mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
516 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP).get());
517 mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700518
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700519 mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
520 false, false,
521 RS_BLEND_SRC_SRC_ALPHA,
522 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
523 RS_DEPTH_FUNC_ALWAYS).get());
Jason Sams8feea4e2011-03-18 15:03:25 -0700524 mFontProgramStore->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700525}
526
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800527void FontState::initTextTexture() {
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700528 ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700529
530 // We will allocate a texture to initially hold 32 character bitmaps
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700531 ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), 1024, 256, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700532
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700533 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700534 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700535 mTextTexture.set(cacheAlloc);
Jason Samsb7e83bd2010-12-15 01:41:00 -0800536 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700537
538 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700539 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700540 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
541 nextLine += mCacheLines.top()->mMaxHeight;
542 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
543 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700544 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
545 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700546 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
547 nextLine += mCacheLines.top()->mMaxHeight;
548 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
549 nextLine += mCacheLines.top()->mMaxHeight;
550 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
551 nextLine += mCacheLines.top()->mMaxHeight;
552 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
553}
554
555// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800556void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700557 // Now lets write index data
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700558 ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700559 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700560 ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700561
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700562 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700563 RS_ALLOCATION_USAGE_SCRIPT |
564 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700565 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
566
567 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800568 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700569 int32_t i6 = i * 6;
570 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700571
572 indexPtr[i6 + 0] = i4 + 0;
573 indexPtr[i6 + 1] = i4 + 1;
574 indexPtr[i6 + 2] = i4 + 2;
575
576 indexPtr[i6 + 3] = i4 + 0;
577 indexPtr[i6 + 4] = i4 + 2;
578 indexPtr[i6 + 5] = i4 + 3;
579 }
580
Jason Samseb4fe182011-05-26 16:33:01 -0700581 indexAlloc->sendDirty(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700582
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700583 ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
584 ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700585
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700586 Element::Builder builder;
587 builder.add(posElem.get(), "position", 1);
588 builder.add(texElem.get(), "texture0", 1);
589 ObjectBaseRef<const Element> vertexDataElem = builder.create(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700590
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700591 ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
592 mMaxNumberOfQuads * 4,
593 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700594
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700595 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700596 RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700597 mTextMeshPtr = (float*)vertexAlloc->getPtr();
598
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700599 mMesh.set(new Mesh(mRSC, 1, 1));
600 mMesh->setVertexBuffer(vertexAlloc, 0);
601 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
602 mMesh->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700603}
604
605// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800606void FontState::checkInit() {
607 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700608 return;
609 }
610
611 initTextTexture();
612 initRenderState();
613
614 initVertexArrayBuffers();
615
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700616 // We store a string with letters in a rough frequency of occurrence
617 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
618 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
619 mLatinPrecache += String8(",.?!()-+@;:`'");
620 mLatinPrecache += String8("0123456789");
621
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700622 mInitialized = true;
623}
624
625void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800626 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700627
Jason Sams60709252010-11-17 15:29:32 -0800628 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
629 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
630 mRSC->setProgramFragment(mFontShaderF.get());
631 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700632
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800633 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800634 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700635 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700636 }
637
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700638 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700639 return;
640 }
641
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700642 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700643}
644
645void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800646 float u1, float v1,
647 float x2, float y2, float z2,
648 float u2, float v2,
649 float x3, float y3, float z3,
650 float u3, float v3,
651 float x4, float y4, float z4,
652 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700653 const uint32_t vertsPerQuad = 4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800654 const uint32_t floatsPerVert = 6;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700655 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
656
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800657 if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700658 return;
659 }
660
661 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
Steve Blockaf12ac62012-01-06 19:20:56 +0000662 ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
663 ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
664 ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700665
666 (*currentPos++) = x1;
667 (*currentPos++) = y1;
668 (*currentPos++) = z1;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800669 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700670 (*currentPos++) = u1;
671 (*currentPos++) = v1;
672
673 (*currentPos++) = x2;
674 (*currentPos++) = y2;
675 (*currentPos++) = z2;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800676 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700677 (*currentPos++) = u2;
678 (*currentPos++) = v2;
679
680 (*currentPos++) = x3;
681 (*currentPos++) = y3;
682 (*currentPos++) = z3;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800683 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700684 (*currentPos++) = u3;
685 (*currentPos++) = v3;
686
687 (*currentPos++) = x4;
688 (*currentPos++) = y4;
689 (*currentPos++) = z4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800690 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700691 (*currentPos++) = u4;
692 (*currentPos++) = v4;
693
694 mCurrentQuadIndex ++;
695
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800696 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700697 issueDrawCommand();
698 mCurrentQuadIndex = 0;
699 }
700}
701
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700702uint32_t FontState::getRemainingCacheCapacity() {
703 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700704 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800705 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700706 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
707 totalPixels += mCacheLines[i]->mMaxWidth;
708 }
709 remainingCapacity = (remainingCapacity * 100) / totalPixels;
710 return remainingCapacity;
711}
712
713void FontState::precacheLatin(Font *font) {
714 // Remaining capacity is measured in %
715 uint32_t remainingCapacity = getRemainingCacheCapacity();
716 uint32_t precacheIdx = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800717 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700718 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
719 remainingCapacity = getRemainingCacheCapacity();
720 precacheIdx ++;
721 }
722}
723
724
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700725void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
726 uint32_t startIndex, int32_t numGlyphs,
727 Font::RenderMode mode,
728 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800729 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700730 checkInit();
731
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700732 // Render code here
733 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800734 if (!currentFont) {
735 if (!mDefault.get()) {
Christian Robertson1f5f9a32011-08-09 15:24:25 -0700736 String8 fontsDir("/fonts/Roboto-Regular.ttf");
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800737 String8 fullPath(getenv("ANDROID_ROOT"));
738 fullPath += fontsDir;
739
Alex Sakhartchouk7b3e9bd2011-03-16 19:28:25 -0700740 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700741 }
742 currentFont = mDefault.get();
743 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800744 if (!currentFont) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000745 ALOGE("Unable to initialize any fonts");
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700746 return;
747 }
748
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800749 // Cull things that are off the screen
750 mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
751 mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
752
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700753 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
754 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700755
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800756 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700757 issueDrawCommand();
758 mCurrentQuadIndex = 0;
759 }
760}
761
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700762void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
763 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800764 bounds->bottom = - bounds->bottom;
765 bounds->top = - bounds->top;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700766}
767
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700768void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700769 mConstants.mFontColor[0] = r;
770 mConstants.mFontColor[1] = g;
771 mConstants.mFontColor[2] = b;
772 mConstants.mFontColor[3] = a;
773
774 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700775 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700776 if (luminance <= mBlackThreshold) {
777 mConstants.mGamma = mBlackGamma;
778 } else if (luminance >= mWhiteThreshold) {
779 mConstants.mGamma = mWhiteGamma;
780 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700781
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700782 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700783}
784
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700785void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700786 *r = mConstants.mFontColor[0];
787 *g = mConstants.mFontColor[1];
788 *b = mConstants.mFontColor[2];
789 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700790}
791
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800792void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700793 mInitialized = false;
794
Stephen Hines01b7d292010-09-28 15:45:45 -0700795 mFontShaderFConstant.clear();
796
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700797 mMesh.clear();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700798
799 mFontShaderF.clear();
800 mFontSampler.clear();
801 mFontProgramStore.clear();
802
803 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800804 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700805 delete mCacheLines[i];
806 }
807 mCacheLines.clear();
808
809 mDefault.clear();
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700810#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800811 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700812 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700813 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700814 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700815#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700816}
817
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700818#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800819bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
820 if ((uint32_t)bitmap->rows > mMaxHeight) {
821 return false;
822 }
823
824 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
825 *retOriginX = mCurrentCol;
826 *retOriginY = mCurrentRow;
827 mCurrentCol += bitmap->width;
828 mDirty = true;
829 return true;
830 }
831
832 return false;
833}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700834#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800835
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700836namespace android {
837namespace renderscript {
838
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700839RsFont rsi_FontCreateFromFile(Context *rsc,
840 char const *name, size_t name_length,
841 float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700842 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800843 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700844 newFont->incUserRef();
845 }
846 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700847}
848
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700849RsFont rsi_FontCreateFromMemory(Context *rsc,
850 char const *name, size_t name_length,
851 float fontSize, uint32_t dpi,
852 const void *data, size_t data_length) {
853 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800854 if (newFont) {
855 newFont->incUserRef();
856 }
857 return newFont;
858}
859
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700860} // renderscript
861} // android