blob: c4276cfe82617684a02fb3dbb2293269efc95a88 [file] [log] [blame]
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -070018#include "rsContext.h"
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070019
20#include "rsFont.h"
21#include "rsProgramFragment.h"
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -070022#include <cutils/properties.h>
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -080023
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -070024#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -080025#include <ft2build.h>
26#include FT_FREETYPE_H
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070027#include FT_BITMAP_H
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -070028#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070029
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070030using namespace android;
31using namespace android::renderscript;
32
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080033Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070034 mInitialized = false;
35 mHasKerning = false;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -070036 mFace = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070037}
38
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -080039bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -070040#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080041 if (mInitialized) {
Steve Block3762c312012-01-06 19:20:56 +000042 ALOGE("Reinitialization of fonts not supported");
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070043 return false;
44 }
45
Alex Sakhartchoukb0253ea2011-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 Sakhartchouked9f2102010-11-09 17:00:54 -080053 if (error) {
Steve Block3762c312012-01-06 19:20:56 +000054 ALOGE("Unable to initialize font %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070055 return false;
56 }
57
58 mFontName = name;
59 mFontSize = fontSize;
60 mDpi = dpi;
61
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080062 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080063 if (error) {
Steve Block3762c312012-01-06 19:20:56 +000064 ALOGE("Unable to set font size on %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070065 return false;
66 }
67
68 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070069
70 mInitialized = true;
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -070071#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070072 return true;
73}
74
Jason Sams38f8d9d2011-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 Sakhartchouked9f2102010-11-09 17:00:54 -080084void Font::invalidateTextureCache() {
85 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070086 mCachedGlyphs.valueAt(i)->mIsValid = false;
87 }
88}
89
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080090void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070091 FontState *state = &mRSC->mStateFont;
92
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070093 int32_t nPenX = x + glyph->mBitmapLeft;
94 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070095
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700100
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700101 int32_t width = (int32_t) glyph->mBitmapWidth;
102 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700103
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700108}
109
Alex Sakhartchouk10825a02010-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 Block3762c312012-01-06 19:20:56 +0000127 ALOGE("Skipping invalid index");
Alex Sakhartchouk10825a02010-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 Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800143 // 0, 0 is top left, so bottom is a positive number
144 if (bounds->bottom < nPenY) {
Alex Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800153 if (bounds->top > nPenY - height) {
154 bounds->top = nPenY - height;
Alex Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700163 return;
164 }
165
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800166 if (mode == Font::MEASURE) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700167 if (bounds == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000168 ALOGE("No return rectangle provided to measure text");
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700169 return;
170 }
171 // Reset min and max of the bounding box to something large
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800172 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700173 }
174
175 int32_t penX = x, penY = y;
176 int32_t glyphsLeft = 1;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800177 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-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 Root300ba682010-11-09 14:37:23 -0800186 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700187
188 // Reached the end of the string or encountered
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800189 if (utfChar < 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700190 break;
191 }
192
193 // Move to the next character in the array
194 index = nextIndex;
195
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700196 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800199 if (cachedGlyph->mIsValid) {
200 switch (mode) {
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700211 }
212
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800213 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700214
215 // If we were given a specific number of glyphs, decrement
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800216 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700217 glyphsLeft --;
218 }
219 }
220}
221
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700222Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
223
224 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800225 if (cachedGlyph == NULL) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700226 cachedGlyph = cacheGlyph((uint32_t)utfChar);
227 }
228 // Is the glyph still in texture cache?
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800229 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700230 updateGlyphCache(cachedGlyph);
231 }
232
233 return cachedGlyph;
234}
235
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800236void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700237#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700238 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800239 if (error) {
Steve Block3762c312012-01-06 19:20:56 +0000240 ALOGE("Couldn't load glyph.");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700241 return;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700242 }
243
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800244 glyph->mAdvanceX = mFace->glyph->advance.x;
245 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouk071508d2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700257 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700258
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800259 if (!glyph->mIsValid) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700260 return;
261 }
262
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700263 uint32_t endX = startX + bitmap->width;
264 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700265
266 glyph->mBitmapMinX = startX;
267 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700268 glyph->mBitmapWidth = bitmap->width;
269 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk17a8a192011-06-03 10:18:01 -0700278#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700279}
280
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800281Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700282 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
283 mCachedGlyphs.add(glyph, newGlyph);
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700284#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700285 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
286 newGlyph->mIsValid = false;
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700287#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700288 updateGlyphCache(newGlyph);
289
290 return newGlyph;
291}
292
Alex Sakhartchoukb0253ea2011-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 Sakhartchouk27f50522010-08-18 15:46:43 -0700295 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700296 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
297
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800298 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700299 Font *ithFont = activeFonts[i];
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800300 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700301 return ithFont;
302 }
303 }
304
305 Font *newFont = new Font(rsc);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800306 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800307 if (isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700308 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700309 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700310 return newFont;
311 }
312
Jason Samsb38d5342010-10-21 14:06:55 -0700313 ObjectBase::checkDelete(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700314 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700315}
316
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800317Font::~Font() {
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700318#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800319 if (mFace) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700320 FT_Done_Face(mFace);
321 }
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700322#endif
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700323
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800324 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700325 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700326 delete glyph;
327 }
328}
329
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800330FontState::FontState() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700331 mInitialized = false;
332 mMaxNumberOfQuads = 1024;
333 mCurrentQuadIndex = 0;
334 mRSC = NULL;
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700335#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700336 mLibrary = NULL;
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700337#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700345 gamma = atof(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700346 }
347
348 // Get the black gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700349 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700350 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700351 blackThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700352 }
353 mBlackThreshold = (float)(blackThreshold) / 255.0f;
354
355 // Get the white gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700356 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700357 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700358 whiteThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk960ae152010-10-12 14:15:17 -0700365
366 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700367}
368
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800369FontState::~FontState() {
370 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700371 delete mCacheLines[i];
372 }
373
374 rsAssert(!mActiveFonts.size());
375}
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700376#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800377FT_Library FontState::getLib() {
378 if (!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700379 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800380 if (error) {
Steve Block3762c312012-01-06 19:20:56 +0000381 ALOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700382 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700383 }
384 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700385
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700386 return mLibrary;
387}
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700388#endif //ANDROID_RS_SERIALIZE
389
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700390
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800391void FontState::init(Context *rsc) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700392 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700393}
394
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800395void FontState::flushAllAndInvalidate() {
396 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700397 issueDrawCommand();
398 mCurrentQuadIndex = 0;
399 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800400 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700401 mActiveFonts[i]->invalidateTextureCache();
402 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800403 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700404 mCacheLines[i]->mCurrentCol = 0;
405 }
406}
407
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700408#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800409bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700410 // If the glyph is too tall, don't cache it
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800411 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Steve Block3762c312012-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 Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800421 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700422 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800423 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800429 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700430 flushAllAndInvalidate();
431
432 // Try to fit it again
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800433 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700434 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800435 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800441 if (!bitmapFit) {
Steve Block3762c312012-01-06 19:20:56 +0000442 ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700453 uint32_t cacheWidth = getCacheTextureType()->getDimX();
454
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700455 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
456 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700457
458 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchouked9f2102010-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 Sakhartchouk10825a02010-10-05 11:33:27 -0700461 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-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 Sams7e8aae72011-05-26 16:33:01 -0700468
469 mTextTexture->sendDirty(mRSC);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700470 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700471
472 // Some debug code
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800473 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Steve Block3762c312012-01-06 19:20:56 +0000474 ALOGE("Cache Line: H: %u Empty Space: %f",
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk17a8a192011-06-03 10:18:01 -0700482#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700483
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800484void FontState::initRenderState() {
Alex Sakhartchoukd2091632010-10-06 11:15:01 -0700485 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700489 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700490 shaderString.append(" gl_FragColor = col;\n");
491 shaderString.append("}\n");
492
Alex Sakhartchouk2123b462012-02-15 16:21:46 -0800493 const char *textureNames[] = { "Tex0" };
494 const size_t textureNamesLengths[] = { 4 };
495 size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
496
497 ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
498 RS_KIND_USER, false, 4);
499 ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
500 RS_KIND_USER, false, 1);
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700501 Element::Builder builder;
502 builder.add(colorElem.get(), "Color", 1);
503 builder.add(gammaElem.get(), "Gamma", 1);
504 ObjectBaseRef<const Element> constInput = builder.create(mRSC);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700505
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700506 ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700507
508 uint32_t tmp[4];
509 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700510 tmp[1] = (uint32_t)inputType.get();
Alex Sakhartchouk67f2e442010-11-18 15:22:43 -0800511 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
512 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700513
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700514 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
Alex Sakhartchouk2123b462012-02-15 16:21:46 -0800515 RS_ALLOCATION_USAGE_SCRIPT |
516 RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
517 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), shaderString.length(),
518 textureNames, numTextures, textureNamesLengths,
519 tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700520 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700521 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700522
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700523 mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
Alex Sakhartchouk2123b462012-02-15 16:21:46 -0800524 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
525 RS_SAMPLER_CLAMP).get());
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700526 mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700527
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700528 mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
529 false, false,
530 RS_BLEND_SRC_SRC_ALPHA,
531 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
532 RS_DEPTH_FUNC_ALWAYS).get());
Jason Sams48f50562011-03-18 15:03:25 -0700533 mFontProgramStore->init();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700534}
535
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800536void FontState::initTextTexture() {
Alex Sakhartchouk2123b462012-02-15 16:21:46 -0800537 ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
538 RS_KIND_PIXEL_A, true, 1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700539
540 // We will allocate a texture to initially hold 32 character bitmaps
Alex Sakhartchouk2123b462012-02-15 16:21:46 -0800541 ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
542 1024, 256, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700543
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700544 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
Jason Sams7e8aae72011-05-26 16:33:01 -0700545 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700546 mTextTexture.set(cacheAlloc);
Jason Sams6d8eb262010-12-15 01:41:00 -0800547 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700548
549 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700550 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700551 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
552 nextLine += mCacheLines.top()->mMaxHeight;
553 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
554 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700555 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
556 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700557 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
558 nextLine += mCacheLines.top()->mMaxHeight;
559 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
560 nextLine += mCacheLines.top()->mMaxHeight;
561 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
562 nextLine += mCacheLines.top()->mMaxHeight;
563 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
564}
565
566// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800567void FontState::initVertexArrayBuffers() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700568 // Now lets write index data
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700569 ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700570 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700571 ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700572
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700573 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
Jason Sams7e8aae72011-05-26 16:33:01 -0700574 RS_ALLOCATION_USAGE_SCRIPT |
575 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700576 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
577
578 // Four verts, two triangles , six indices per quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800579 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700580 int32_t i6 = i * 6;
581 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700582
583 indexPtr[i6 + 0] = i4 + 0;
584 indexPtr[i6 + 1] = i4 + 1;
585 indexPtr[i6 + 2] = i4 + 2;
586
587 indexPtr[i6 + 3] = i4 + 0;
588 indexPtr[i6 + 4] = i4 + 2;
589 indexPtr[i6 + 5] = i4 + 3;
590 }
591
Jason Sams7e8aae72011-05-26 16:33:01 -0700592 indexAlloc->sendDirty(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700593
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700594 ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
595 ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700596
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700597 Element::Builder builder;
598 builder.add(posElem.get(), "position", 1);
599 builder.add(texElem.get(), "texture0", 1);
600 ObjectBaseRef<const Element> vertexDataElem = builder.create(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700601
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700602 ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
603 mMaxNumberOfQuads * 4,
604 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700605
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700606 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
Jason Sams7e8aae72011-05-26 16:33:01 -0700607 RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700608 mTextMeshPtr = (float*)vertexAlloc->getPtr();
609
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700610 mMesh.set(new Mesh(mRSC, 1, 1));
611 mMesh->setVertexBuffer(vertexAlloc, 0);
612 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
613 mMesh->init();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700614}
615
616// We don't want to allocate anything unless we actually draw text
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800617void FontState::checkInit() {
618 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700619 return;
620 }
621
622 initTextTexture();
623 initRenderState();
624
625 initVertexArrayBuffers();
626
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700627 // We store a string with letters in a rough frequency of occurrence
628 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
629 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
630 mLatinPrecache += String8(",.?!()-+@;:`'");
631 mLatinPrecache += String8("0123456789");
632
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700633 mInitialized = true;
634}
635
636void FontState::issueDrawCommand() {
Jason Samsa17af042010-11-17 15:29:32 -0800637 Context::PushState ps(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700638
Jason Samsa17af042010-11-17 15:29:32 -0800639 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
640 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
641 mRSC->setProgramFragment(mFontShaderF.get());
642 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700643
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800644 if (mConstantsDirty) {
Jason Sams49a05d72010-12-29 14:31:29 -0800645 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700646 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700647 }
648
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700649 if (!mRSC->setupCheck()) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700650 return;
651 }
652
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700653 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700654}
655
656void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800657 float u1, float v1,
658 float x2, float y2, float z2,
659 float u2, float v2,
660 float x3, float y3, float z3,
661 float u3, float v3,
662 float x4, float y4, float z4,
663 float u4, float v4) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700664 const uint32_t vertsPerQuad = 4;
Alex Sakhartchouke60149d2011-11-15 15:15:21 -0800665 const uint32_t floatsPerVert = 6;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700666 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
667
Alex Sakhartchouk2d8ef492011-11-16 12:22:10 -0800668 if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700669 return;
670 }
671
672 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
Steve Block3762c312012-01-06 19:20:56 +0000673 ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
674 ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
675 ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700676
677 (*currentPos++) = x1;
678 (*currentPos++) = y1;
679 (*currentPos++) = z1;
Alex Sakhartchouke60149d2011-11-15 15:15:21 -0800680 (*currentPos++) = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700681 (*currentPos++) = u1;
682 (*currentPos++) = v1;
683
684 (*currentPos++) = x2;
685 (*currentPos++) = y2;
686 (*currentPos++) = z2;
Alex Sakhartchouke60149d2011-11-15 15:15:21 -0800687 (*currentPos++) = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700688 (*currentPos++) = u2;
689 (*currentPos++) = v2;
690
691 (*currentPos++) = x3;
692 (*currentPos++) = y3;
693 (*currentPos++) = z3;
Alex Sakhartchouke60149d2011-11-15 15:15:21 -0800694 (*currentPos++) = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700695 (*currentPos++) = u3;
696 (*currentPos++) = v3;
697
698 (*currentPos++) = x4;
699 (*currentPos++) = y4;
700 (*currentPos++) = z4;
Alex Sakhartchouke60149d2011-11-15 15:15:21 -0800701 (*currentPos++) = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700702 (*currentPos++) = u4;
703 (*currentPos++) = v4;
704
705 mCurrentQuadIndex ++;
706
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800707 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700708 issueDrawCommand();
709 mCurrentQuadIndex = 0;
710 }
711}
712
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700713uint32_t FontState::getRemainingCacheCapacity() {
714 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700715 uint32_t totalPixels = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800716 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700717 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
718 totalPixels += mCacheLines[i]->mMaxWidth;
719 }
720 remainingCapacity = (remainingCapacity * 100) / totalPixels;
721 return remainingCapacity;
722}
723
724void FontState::precacheLatin(Font *font) {
725 // Remaining capacity is measured in %
726 uint32_t remainingCapacity = getRemainingCacheCapacity();
727 uint32_t precacheIdx = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800728 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700729 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
730 remainingCapacity = getRemainingCacheCapacity();
731 precacheIdx ++;
732 }
733}
734
735
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700736void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
737 uint32_t startIndex, int32_t numGlyphs,
738 Font::RenderMode mode,
739 Font::Rect *bounds,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800740 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700741 checkInit();
742
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700743 // Render code here
744 Font *currentFont = mRSC->getFont();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800745 if (!currentFont) {
746 if (!mDefault.get()) {
Christian Robertsonbeb2b5c2011-08-09 15:24:25 -0700747 String8 fontsDir("/fonts/Roboto-Regular.ttf");
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800748 String8 fullPath(getenv("ANDROID_ROOT"));
749 fullPath += fontsDir;
750
Alex Sakhartchouk2c74ad92011-03-16 19:28:25 -0700751 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700752 }
753 currentFont = mDefault.get();
754 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800755 if (!currentFont) {
Steve Block3762c312012-01-06 19:20:56 +0000756 ALOGE("Unable to initialize any fonts");
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700757 return;
758 }
759
Alex Sakhartchouk2d8ef492011-11-16 12:22:10 -0800760 // Cull things that are off the screen
761 mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
762 mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
763
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700764 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
765 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700766
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800767 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700768 issueDrawCommand();
769 mCurrentQuadIndex = 0;
770 }
771}
772
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700773void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
774 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800775 bounds->bottom = - bounds->bottom;
776 bounds->top = - bounds->top;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700777}
778
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700779void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700780 mConstants.mFontColor[0] = r;
781 mConstants.mFontColor[1] = g;
782 mConstants.mFontColor[2] = b;
783 mConstants.mFontColor[3] = a;
784
785 mConstants.mGamma = 1.0f;
Alex Sakhartchouk76322af2010-10-05 13:23:55 -0700786 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700787 if (luminance <= mBlackThreshold) {
788 mConstants.mGamma = mBlackGamma;
789 } else if (luminance >= mWhiteThreshold) {
790 mConstants.mGamma = mWhiteGamma;
791 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700792
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700793 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700794}
795
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700796void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700797 *r = mConstants.mFontColor[0];
798 *g = mConstants.mFontColor[1];
799 *b = mConstants.mFontColor[2];
800 *a = mConstants.mFontColor[3];
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700801}
802
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800803void FontState::deinit(Context *rsc) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700804 mInitialized = false;
805
Stephen Hines01f0ad72010-09-28 15:45:45 -0700806 mFontShaderFConstant.clear();
807
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700808 mMesh.clear();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700809
810 mFontShaderF.clear();
811 mFontSampler.clear();
812 mFontProgramStore.clear();
813
814 mTextTexture.clear();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800815 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700816 delete mCacheLines[i];
817 }
818 mCacheLines.clear();
819
820 mDefault.clear();
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700821#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800822 if (mLibrary) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700823 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700824 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700825 }
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700826#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700827}
828
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700829#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800830bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
831 if ((uint32_t)bitmap->rows > mMaxHeight) {
832 return false;
833 }
834
835 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
836 *retOriginX = mCurrentCol;
837 *retOriginY = mCurrentRow;
838 mCurrentCol += bitmap->width;
839 mDirty = true;
840 return true;
841 }
842
843 return false;
844}
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700845#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800846
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700847namespace android {
848namespace renderscript {
849
Alex Sakhartchouke7c4a752011-04-06 10:57:51 -0700850RsFont rsi_FontCreateFromFile(Context *rsc,
851 char const *name, size_t name_length,
852 float fontSize, uint32_t dpi) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700853 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800854 if (newFont) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700855 newFont->incUserRef();
856 }
857 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700858}
859
Alex Sakhartchouke7c4a752011-04-06 10:57:51 -0700860RsFont rsi_FontCreateFromMemory(Context *rsc,
861 char const *name, size_t name_length,
862 float fontSize, uint32_t dpi,
863 const void *data, size_t data_length) {
864 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800865 if (newFont) {
866 newFont->incUserRef();
867 }
868 return newFont;
869}
870
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700871} // renderscript
872} // android