blob: 3917ca19f80d07cf77a6c383ceae6ed9f51e3158 [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) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070042 LOGE("Reinitialization of fonts not supported");
43 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) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080054 LOGE("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) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080064 LOGE("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) {
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 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) {
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 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) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700240 LOGE("Couldn't load glyph.");
241 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) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700381 LOGE("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) {
Alex Sakhartchouk9b949fc2010-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 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) {
Alex Sakhartchouk9b949fc2010-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 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 ++) {
Alex Sakhartchouk9b949fc2010-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 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
493 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700494 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700495 mRSC->mStateElement.elementBuilderBegin();
496 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700497 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700498 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
499
Jason Sams31a7e422010-10-26 13:09:17 -0700500 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-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 Sakhartchouk67f2e442010-11-18 15:22:43 -0800505 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
506 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700507
Jason Sams7e8aae72011-05-26 16:33:01 -0700508 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType,
Jason Sams5476b452010-12-08 16:14:36 -0800509 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700510 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
511 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700512 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700513 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-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 Sakhartchoukb89aaac2010-09-23 16:16:33 -0700518 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700519
Jason Sams331bf9b2011-04-06 11:23:54 -0700520 ProgramStore *fontStore = new ProgramStore(mRSC, true, true, true, true,
521 false, false,
Jason Samsbd184c52011-04-06 11:44:47 -0700522 RS_BLEND_SRC_SRC_ALPHA,
523 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
Jason Sams331bf9b2011-04-06 11:23:54 -0700524 RS_DEPTH_FUNC_ALWAYS);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700525 mFontProgramStore.set(fontStore);
Jason Sams48f50562011-03-18 15:03:25 -0700526 mFontProgramStore->init();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700527}
528
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800529void FontState::initTextTexture() {
Alex Sakhartchouk9b949fc2010-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 Sams31a7e422010-10-26 13:09:17 -0700533 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700534
Jason Sams7e8aae72011-05-26 16:33:01 -0700535 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType,
536 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700537 mTextTexture.set(cacheAlloc);
Jason Sams6d8eb262010-12-15 01:41:00 -0800538 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700539
540 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700541 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk94bbccc2010-08-17 11:09:49 -0700546 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
547 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800558void FontState::initVertexArrayBuffers() {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700561 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Sams31a7e422010-10-26 13:09:17 -0700562 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700563
Jason Sams7e8aae72011-05-26 16:33:01 -0700564 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType,
565 RS_ALLOCATION_USAGE_SCRIPT |
566 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700567 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
568
569 // Four verts, two triangles , six indices per quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800570 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700571 int32_t i6 = i * 6;
572 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-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 Sams7e8aae72011-05-26 16:33:01 -0700583 indexAlloc->sendDirty(mRSC);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk98bfe5d2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700592
Jason Sams31a7e422010-10-26 13:09:17 -0700593 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
594 mMaxNumberOfQuads * 4,
595 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700596
Jason Sams7e8aae72011-05-26 16:33:01 -0700597 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType,
598 RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700599 mTextMeshPtr = (float*)vertexAlloc->getPtr();
600
Alex Sakhartchouk4a36b452011-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700605}
606
607// We don't want to allocate anything unless we actually draw text
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800608void FontState::checkInit() {
609 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700610 return;
611 }
612
613 initTextTexture();
614 initRenderState();
615
616 initVertexArrayBuffers();
617
Alex Sakhartchouk27f50522010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700624 mInitialized = true;
625}
626
627void FontState::issueDrawCommand() {
Jason Samsa17af042010-11-17 15:29:32 -0800628 Context::PushState ps(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700629
Jason Samsa17af042010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700634
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800635 if (mConstantsDirty) {
Jason Sams49a05d72010-12-29 14:31:29 -0800636 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700637 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700638 }
639
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700640 if (!mRSC->setupCheck()) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700641 return;
642 }
643
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700644 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700645}
646
647void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchouked9f2102010-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 Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800663 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800698 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700699 issueDrawCommand();
700 mCurrentQuadIndex = 0;
701 }
702}
703
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700704uint32_t FontState::getRemainingCacheCapacity() {
705 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700706 uint32_t totalPixels = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800707 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk94bbccc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800719 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700720 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
721 remainingCapacity = getRemainingCacheCapacity();
722 precacheIdx ++;
723 }
724}
725
726
Alex Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800731 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700732 checkInit();
733
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700734 // Render code here
735 Font *currentFont = mRSC->getFont();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800736 if (!currentFont) {
737 if (!mDefault.get()) {
Christian Robertsonbeb2b5c2011-08-09 15:24:25 -0700738 String8 fontsDir("/fonts/Roboto-Regular.ttf");
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800739 String8 fullPath(getenv("ANDROID_ROOT"));
740 fullPath += fontsDir;
741
Alex Sakhartchouk2c74ad92011-03-16 19:28:25 -0700742 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700743 }
744 currentFont = mDefault.get();
745 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800746 if (!currentFont) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700747 LOGE("Unable to initialize any fonts");
748 return;
749 }
750
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700751 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
752 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700753
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800754 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700755 issueDrawCommand();
756 mCurrentQuadIndex = 0;
757 }
758}
759
Alex Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800762 bounds->bottom = - bounds->bottom;
763 bounds->top = - bounds->top;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700764}
765
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700766void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk76322af2010-10-05 13:23:55 -0700773 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700774 if (luminance <= mBlackThreshold) {
775 mConstants.mGamma = mBlackGamma;
776 } else if (luminance >= mWhiteThreshold) {
777 mConstants.mGamma = mWhiteGamma;
778 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700779
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700780 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700781}
782
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700783void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk55e81982010-08-05 11:24:14 -0700788}
789
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800790void FontState::deinit(Context *rsc) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700791 mInitialized = false;
792
Stephen Hines01f0ad72010-09-28 15:45:45 -0700793 mFontShaderFConstant.clear();
794
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700795 mMesh.clear();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700796
797 mFontShaderF.clear();
798 mFontSampler.clear();
799 mFontProgramStore.clear();
800
801 mTextTexture.clear();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800802 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700803 delete mCacheLines[i];
804 }
805 mCacheLines.clear();
806
807 mDefault.clear();
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700808#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800809 if (mLibrary) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700810 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700811 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700812 }
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700813#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700814}
815
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700816#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukebd65bb2011-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 Sakhartchouk17a8a192011-06-03 10:18:01 -0700832#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800833
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700834namespace android {
835namespace renderscript {
836
Alex Sakhartchouke7c4a752011-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700840 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800841 if (newFont) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700842 newFont->incUserRef();
843 }
844 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700845}
846
Alex Sakhartchouke7c4a752011-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800852 if (newFont) {
853 newFont->incUserRef();
854 }
855 return newFont;
856}
857
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700858} // renderscript
859} // android