blob: 3665a3d366b7b8d160cc0174f7bbf727c18eec8f [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 Sakhartchouke23d2392012-03-09 09:24:39 -080019#include "rs.h"
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070020#include "rsFont.h"
21#include "rsProgramFragment.h"
Alex Sakhartchouk4edf0302012-03-09 10:47:27 -080022#include "rsMesh.h"
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -070023#include <cutils/properties.h>
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080024
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070025#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080026#include <ft2build.h>
27#include FT_FREETYPE_H
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070028#include FT_BITMAP_H
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070029#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070030
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070031using namespace android;
32using namespace android::renderscript;
33
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080034Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070035 mInitialized = false;
36 mHasKerning = false;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -070037 mFace = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070038}
39
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080040bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070041#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080042 if (mInitialized) {
Steve Blockaf12ac62012-01-06 19:20:56 +000043 ALOGE("Reinitialization of fonts not supported");
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070044 return false;
45 }
46
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080047 FT_Error error = 0;
48 if (data != NULL && dataLen > 0) {
49 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
50 } else {
51 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
52 }
53
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080054 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +000055 ALOGE("Unable to initialize font %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070056 return false;
57 }
58
59 mFontName = name;
60 mFontSize = fontSize;
61 mDpi = dpi;
62
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080063 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080064 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +000065 ALOGE("Unable to set font size on %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070066 return false;
67 }
68
69 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070070
71 mInitialized = true;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070072#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070073 return true;
74}
75
Jason Sams2e8665d2011-01-27 00:14:13 -080076void Font::preDestroy() const {
77 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
78 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
79 mRSC->mStateFont.mActiveFonts.removeAt(ct);
80 break;
81 }
82 }
83}
84
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080085void Font::invalidateTextureCache() {
86 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070087 mCachedGlyphs.valueAt(i)->mIsValid = false;
88 }
89}
90
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080091void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070092 FontState *state = &mRSC->mStateFont;
93
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070094 int32_t nPenX = x + glyph->mBitmapLeft;
95 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070096
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070097 float u1 = glyph->mBitmapMinU;
98 float u2 = glyph->mBitmapMaxU;
99 float v1 = glyph->mBitmapMinV;
100 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700101
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700102 int32_t width = (int32_t) glyph->mBitmapWidth;
103 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700104
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700105 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
106 nPenX + width, nPenY, 0, u2, v2,
107 nPenX + width, nPenY - height, 0, u2, v1,
108 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700109}
110
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700111void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
112 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
113 int32_t nPenX = x + glyph->mBitmapLeft;
114 int32_t nPenY = y + glyph->mBitmapTop;
115
116 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
117 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
118
119 FontState *state = &mRSC->mStateFont;
120 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
Jason Samsa6dd8232012-07-25 19:33:43 -0700121 const uint8_t* cacheBuffer = state->mCacheBuffer;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700122
123 uint32_t cacheX = 0, cacheY = 0;
124 int32_t bX = 0, bY = 0;
125 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
126 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
127 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000128 ALOGE("Skipping invalid index");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700129 continue;
130 }
131 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
132 bitmap[bY * bitmapW + bX] = tempCol;
133 }
134 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700135}
136
137void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
138 int32_t nPenX = x + glyph->mBitmapLeft;
139 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
140
141 int32_t width = (int32_t) glyph->mBitmapWidth;
142 int32_t height = (int32_t) glyph->mBitmapHeight;
143
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800144 // 0, 0 is top left, so bottom is a positive number
145 if (bounds->bottom < nPenY) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700146 bounds->bottom = nPenY;
147 }
148 if (bounds->left > nPenX) {
149 bounds->left = nPenX;
150 }
151 if (bounds->right < nPenX + width) {
152 bounds->right = nPenX + width;
153 }
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800154 if (bounds->top > nPenY - height) {
155 bounds->top = nPenY - height;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700156 }
157}
158
159void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
160 uint32_t start, int32_t numGlyphs,
161 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800162 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
163 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700164 return;
165 }
166
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800167 if (mode == Font::MEASURE) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700168 if (bounds == NULL) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000169 ALOGE("No return rectangle provided to measure text");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700170 return;
171 }
172 // Reset min and max of the bounding box to something large
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800173 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700174 }
175
176 int32_t penX = x, penY = y;
177 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800178 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700179 glyphsLeft = numGlyphs;
180 }
181
182 size_t index = start;
183 size_t nextIndex = 0;
184
185 while (glyphsLeft > 0) {
186
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800187 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700188
189 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800190 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700191 break;
192 }
193
194 // Move to the next character in the array
195 index = nextIndex;
196
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700197 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700198
199 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800200 if (cachedGlyph->mIsValid) {
201 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700202 case FRAMEBUFFER:
203 drawCachedGlyph(cachedGlyph, penX, penY);
204 break;
205 case BITMAP:
206 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
207 break;
208 case MEASURE:
209 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
210 break;
211 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700212 }
213
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800214 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700215
216 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800217 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700218 glyphsLeft --;
219 }
220 }
221}
222
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700223Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
224
225 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800226 if (cachedGlyph == NULL) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700227 cachedGlyph = cacheGlyph((uint32_t)utfChar);
228 }
229 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800230 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700231 updateGlyphCache(cachedGlyph);
232 }
233
234 return cachedGlyph;
235}
236
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800237void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700238#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700239 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800240 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000241 ALOGE("Couldn't load glyph.");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700242 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700243 }
244
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800245 glyph->mAdvanceX = mFace->glyph->advance.x;
246 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700247 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
248 glyph->mBitmapTop = mFace->glyph->bitmap_top;
249
250 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
251
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700252 // Now copy the bitmap into the cache texture
253 uint32_t startX = 0;
254 uint32_t startY = 0;
255
256 // Let the font state figure out where to put the bitmap
257 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700258 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700259
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800260 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700261 return;
262 }
263
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700264 uint32_t endX = startX + bitmap->width;
265 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700266
267 glyph->mBitmapMinX = startX;
268 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700269 glyph->mBitmapWidth = bitmap->width;
270 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700271
272 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
273 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
274
275 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
276 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
277 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
278 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700279#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700280}
281
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800282Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700283 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
284 mCachedGlyphs.add(glyph, newGlyph);
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700285#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700286 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
287 newGlyph->mIsValid = false;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700288#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700289 updateGlyphCache(newGlyph);
290
291 return newGlyph;
292}
293
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800294Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
295 const void *data, uint32_t dataLen) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700296 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700297 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
298
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800299 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700300 Font *ithFont = activeFonts[i];
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800301 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700302 return ithFont;
303 }
304 }
305
306 Font *newFont = new Font(rsc);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800307 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800308 if (isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700309 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700310 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700311 return newFont;
312 }
313
Jason Sams225afd32010-10-21 14:06:55 -0700314 ObjectBase::checkDelete(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700315 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700316}
317
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800318Font::~Font() {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700319#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800320 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700321 FT_Done_Face(mFace);
322 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700323#endif
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700324
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800325 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700326 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700327 delete glyph;
328 }
329}
330
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800331FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700332 mInitialized = false;
333 mMaxNumberOfQuads = 1024;
334 mCurrentQuadIndex = 0;
335 mRSC = NULL;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700336#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700337 mLibrary = NULL;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700338#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700339
340 // Get the renderer properties
341 char property[PROPERTY_VALUE_MAX];
342
343 // Get the gamma
344 float gamma = DEFAULT_TEXT_GAMMA;
345 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700346 gamma = atof(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700347 }
348
349 // Get the black gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700350 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700351 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700352 blackThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700353 }
354 mBlackThreshold = (float)(blackThreshold) / 255.0f;
355
356 // Get the white gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700357 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700358 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700359 whiteThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700360 }
361 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
362
363 // Compute the gamma tables
364 mBlackGamma = gamma;
365 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700366
367 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700368}
369
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800370FontState::~FontState() {
371 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700372 delete mCacheLines[i];
373 }
374
375 rsAssert(!mActiveFonts.size());
376}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700377#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800378FT_Library FontState::getLib() {
379 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700380 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800381 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000382 ALOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700383 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700384 }
385 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700386
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700387 return mLibrary;
388}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700389#endif //ANDROID_RS_SERIALIZE
390
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700391
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800392void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700393 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700394}
395
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800396void FontState::flushAllAndInvalidate() {
397 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700398 issueDrawCommand();
399 mCurrentQuadIndex = 0;
400 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800401 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700402 mActiveFonts[i]->invalidateTextureCache();
403 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800404 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700405 mCacheLines[i]->mCurrentCol = 0;
406 }
407}
408
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700409#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800410bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700411 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800412 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000413 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 -0700414 return false;
415 }
416
417 // Now copy the bitmap into the cache texture
418 uint32_t startX = 0;
419 uint32_t startY = 0;
420
421 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800422 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700423 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800424 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700425 break;
426 }
427 }
428
429 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800430 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700431 flushAllAndInvalidate();
432
433 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800434 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700435 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800436 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700437 break;
438 }
439 }
440
441 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800442 if (!bitmapFit) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000443 ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700444 return false;
445 }
446 }
447
448 *retOriginX = startX;
449 *retOriginY = startY;
450
451 uint32_t endX = startX + bitmap->width;
452 uint32_t endY = startY + bitmap->rows;
453
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700454 uint32_t cacheWidth = getCacheTextureType()->getDimX();
455
Jason Samsa6dd8232012-07-25 19:33:43 -0700456 uint8_t *cacheBuffer = mCacheBuffer;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700457 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700458
459 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800460 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
461 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700462 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700463 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
464 }
465 }
466
467 // This will dirty the texture and the shader so next time
468 // we draw it will upload the data
Jason Samseb4fe182011-05-26 16:33:01 -0700469
Jason Samsa6dd8232012-07-25 19:33:43 -0700470 mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
471 RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
Tim Murray358747a2012-11-26 13:52:04 -0800472 mCacheBuffer, mCacheWidth*mCacheHeight, mCacheWidth);
Jason Samsa6dd8232012-07-25 19:33:43 -0700473
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700474 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700475
476 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800477 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000478 ALOGE("Cache Line: H: %u Empty Space: %f",
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700479 mCacheLines[i]->mMaxHeight,
480 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
481
482 }*/
483
484 return true;
485}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700486#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700487
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800488void FontState::initRenderState() {
Alex Sakhartchouk7ffcaf22010-10-06 11:15:01 -0700489 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700490 shaderString.append("void main() {\n");
491 shaderString.append(" lowp vec4 col = UNI_Color;\n");
492 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700493 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700494 shaderString.append(" gl_FragColor = col;\n");
495 shaderString.append("}\n");
496
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800497 const char *textureNames[] = { "Tex0" };
498 const size_t textureNamesLengths[] = { 4 };
499 size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
500
501 ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
502 RS_KIND_USER, false, 4);
503 ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
504 RS_KIND_USER, false, 1);
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700505 Element::Builder builder;
506 builder.add(colorElem.get(), "Color", 1);
507 builder.add(gammaElem.get(), "Gamma", 1);
508 ObjectBaseRef<const Element> constInput = builder.create(mRSC);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700509
Jason Samsa572aca2013-01-09 11:52:26 -0800510 ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false, 0);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700511
512 uint32_t tmp[4];
513 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700514 tmp[1] = (uint32_t)inputType.get();
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800515 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
516 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700517
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700518 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800519 RS_ALLOCATION_USAGE_SCRIPT |
520 RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
521 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), shaderString.length(),
522 textureNames, numTextures, textureNamesLengths,
523 tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700524 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700525 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700526
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700527 mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800528 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
529 RS_SAMPLER_CLAMP).get());
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700530 mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700531
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700532 mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
533 false, false,
534 RS_BLEND_SRC_SRC_ALPHA,
535 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
536 RS_DEPTH_FUNC_ALWAYS).get());
Jason Sams8feea4e2011-03-18 15:03:25 -0700537 mFontProgramStore->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700538}
539
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800540void FontState::initTextTexture() {
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800541 ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
542 RS_KIND_PIXEL_A, true, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700543
544 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsa6dd8232012-07-25 19:33:43 -0700545 mCacheHeight = 256;
546 mCacheWidth = 1024;
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800547 ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
Jason Samsa572aca2013-01-09 11:52:26 -0800548 mCacheWidth, mCacheHeight, 0, false, false, 0);
Jason Samsa6dd8232012-07-25 19:33:43 -0700549 mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
550
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700551
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700552 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
Jason Samsa6dd8232012-07-25 19:33:43 -0700553 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700554 mTextTexture.set(cacheAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700555
556 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700557 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700558 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
559 nextLine += mCacheLines.top()->mMaxHeight;
560 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
561 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700562 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
563 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700564 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
565 nextLine += mCacheLines.top()->mMaxHeight;
566 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
567 nextLine += mCacheLines.top()->mMaxHeight;
568 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
569 nextLine += mCacheLines.top()->mMaxHeight;
570 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
571}
572
573// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800574void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700575 // Now lets write index data
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700576 ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700577 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsa572aca2013-01-09 11:52:26 -0800578 ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false, 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700579
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700580 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700581 RS_ALLOCATION_USAGE_SCRIPT |
582 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Jason Samsa6dd8232012-07-25 19:33:43 -0700583 uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700584
585 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800586 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700587 int32_t i6 = i * 6;
588 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700589
590 indexPtr[i6 + 0] = i4 + 0;
591 indexPtr[i6 + 1] = i4 + 1;
592 indexPtr[i6 + 2] = i4 + 2;
593
594 indexPtr[i6 + 3] = i4 + 0;
595 indexPtr[i6 + 4] = i4 + 2;
596 indexPtr[i6 + 5] = i4 + 3;
597 }
598
Jason Samseb4fe182011-05-26 16:33:01 -0700599 indexAlloc->sendDirty(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700600
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700601 ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
602 ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700603
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700604 Element::Builder builder;
605 builder.add(posElem.get(), "position", 1);
606 builder.add(texElem.get(), "texture0", 1);
607 ObjectBaseRef<const Element> vertexDataElem = builder.create(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700608
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700609 ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
610 mMaxNumberOfQuads * 4,
Jason Samsa572aca2013-01-09 11:52:26 -0800611 0, 0, false, false, 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700612
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700613 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700614 RS_ALLOCATION_USAGE_SCRIPT);
Jason Samsa6dd8232012-07-25 19:33:43 -0700615 mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700616
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700617 mMesh.set(new Mesh(mRSC, 1, 1));
618 mMesh->setVertexBuffer(vertexAlloc, 0);
619 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
620 mMesh->init();
Jason Samsa6dd8232012-07-25 19:33:43 -0700621 mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
622 mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700623}
624
625// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800626void FontState::checkInit() {
627 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700628 return;
629 }
630
631 initTextTexture();
632 initRenderState();
633
634 initVertexArrayBuffers();
635
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700636 // We store a string with letters in a rough frequency of occurrence
637 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
638 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
639 mLatinPrecache += String8(",.?!()-+@;:`'");
640 mLatinPrecache += String8("0123456789");
641
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700642 mInitialized = true;
643}
644
645void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800646 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700647
Jason Sams60709252010-11-17 15:29:32 -0800648 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
649 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
650 mRSC->setProgramFragment(mFontShaderF.get());
651 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700652
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800653 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800654 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700655 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700656 }
657
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700658 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700659 return;
660 }
661
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700662 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700663}
664
665void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800666 float u1, float v1,
667 float x2, float y2, float z2,
668 float u2, float v2,
669 float x3, float y3, float z3,
670 float u3, float v3,
671 float x4, float y4, float z4,
672 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700673 const uint32_t vertsPerQuad = 4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800674 const uint32_t floatsPerVert = 6;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700675 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
676
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800677 if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700678 return;
679 }
680
681 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
Steve Blockaf12ac62012-01-06 19:20:56 +0000682 ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
683 ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
684 ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700685
686 (*currentPos++) = x1;
687 (*currentPos++) = y1;
688 (*currentPos++) = z1;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800689 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700690 (*currentPos++) = u1;
691 (*currentPos++) = v1;
692
693 (*currentPos++) = x2;
694 (*currentPos++) = y2;
695 (*currentPos++) = z2;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800696 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700697 (*currentPos++) = u2;
698 (*currentPos++) = v2;
699
700 (*currentPos++) = x3;
701 (*currentPos++) = y3;
702 (*currentPos++) = z3;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800703 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700704 (*currentPos++) = u3;
705 (*currentPos++) = v3;
706
707 (*currentPos++) = x4;
708 (*currentPos++) = y4;
709 (*currentPos++) = z4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800710 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700711 (*currentPos++) = u4;
712 (*currentPos++) = v4;
713
714 mCurrentQuadIndex ++;
715
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800716 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700717 issueDrawCommand();
718 mCurrentQuadIndex = 0;
719 }
720}
721
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700722uint32_t FontState::getRemainingCacheCapacity() {
723 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700724 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800725 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700726 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
727 totalPixels += mCacheLines[i]->mMaxWidth;
728 }
729 remainingCapacity = (remainingCapacity * 100) / totalPixels;
730 return remainingCapacity;
731}
732
733void FontState::precacheLatin(Font *font) {
734 // Remaining capacity is measured in %
735 uint32_t remainingCapacity = getRemainingCacheCapacity();
736 uint32_t precacheIdx = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800737 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700738 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
739 remainingCapacity = getRemainingCacheCapacity();
740 precacheIdx ++;
741 }
742}
743
744
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700745void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
746 uint32_t startIndex, int32_t numGlyphs,
747 Font::RenderMode mode,
748 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800749 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700750 checkInit();
751
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700752 // Render code here
753 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800754 if (!currentFont) {
755 if (!mDefault.get()) {
Christian Robertson1f5f9a32011-08-09 15:24:25 -0700756 String8 fontsDir("/fonts/Roboto-Regular.ttf");
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800757 String8 fullPath(getenv("ANDROID_ROOT"));
758 fullPath += fontsDir;
759
Alex Sakhartchouk7b3e9bd2011-03-16 19:28:25 -0700760 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700761 }
762 currentFont = mDefault.get();
763 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800764 if (!currentFont) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000765 ALOGE("Unable to initialize any fonts");
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700766 return;
767 }
768
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800769 // Cull things that are off the screen
770 mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
771 mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
772
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700773 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
774 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700775
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800776 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700777 issueDrawCommand();
778 mCurrentQuadIndex = 0;
779 }
780}
781
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700782void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
783 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800784 bounds->bottom = - bounds->bottom;
785 bounds->top = - bounds->top;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700786}
787
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700788void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700789 mConstants.mFontColor[0] = r;
790 mConstants.mFontColor[1] = g;
791 mConstants.mFontColor[2] = b;
792 mConstants.mFontColor[3] = a;
793
794 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700795 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700796 if (luminance <= mBlackThreshold) {
797 mConstants.mGamma = mBlackGamma;
798 } else if (luminance >= mWhiteThreshold) {
799 mConstants.mGamma = mWhiteGamma;
800 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700801
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700802 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700803}
804
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700805void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700806 *r = mConstants.mFontColor[0];
807 *g = mConstants.mFontColor[1];
808 *b = mConstants.mFontColor[2];
809 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700810}
811
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800812void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700813 mInitialized = false;
814
Stephen Hines01b7d292010-09-28 15:45:45 -0700815 mFontShaderFConstant.clear();
816
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700817 mMesh.clear();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700818
819 mFontShaderF.clear();
820 mFontSampler.clear();
821 mFontProgramStore.clear();
822
823 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800824 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700825 delete mCacheLines[i];
826 }
827 mCacheLines.clear();
828
829 mDefault.clear();
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700830#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800831 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700832 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700833 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700834 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700835#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700836}
837
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700838#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800839bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
840 if ((uint32_t)bitmap->rows > mMaxHeight) {
841 return false;
842 }
843
844 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
845 *retOriginX = mCurrentCol;
846 *retOriginY = mCurrentRow;
847 mCurrentCol += bitmap->width;
848 mDirty = true;
849 return true;
850 }
851
852 return false;
853}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700854#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800855
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700856namespace android {
857namespace renderscript {
858
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700859RsFont rsi_FontCreateFromFile(Context *rsc,
860 char const *name, size_t name_length,
861 float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700862 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800863 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700864 newFont->incUserRef();
865 }
866 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700867}
868
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700869RsFont rsi_FontCreateFromMemory(Context *rsc,
870 char const *name, size_t name_length,
871 float fontSize, uint32_t dpi,
872 const void *data, size_t data_length) {
873 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800874 if (newFont) {
875 newFont->incUserRef();
876 }
877 return newFont;
878}
879
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700880} // renderscript
881} // android