blob: d302182a3e9d9b05df6fcd4f3823a6bfb09fdefe [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"
Nick Kralevich7e85ca22013-05-22 15:04:39 -070023#ifdef HAVE_ANDROID_OS
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -070024#include <cutils/properties.h>
Nick Kralevich7e85ca22013-05-22 15:04:39 -070025#endif
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080026
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070027#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080028#include <ft2build.h>
29#include FT_FREETYPE_H
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070030#include FT_BITMAP_H
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070031#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070032
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070033using namespace android;
34using namespace android::renderscript;
35
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080036Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070037 mInitialized = false;
38 mHasKerning = false;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -070039 mFace = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070040}
41
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080042bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070043#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080044 if (mInitialized) {
Steve Blockaf12ac62012-01-06 19:20:56 +000045 ALOGE("Reinitialization of fonts not supported");
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070046 return false;
47 }
48
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080049 FT_Error error = 0;
50 if (data != NULL && dataLen > 0) {
51 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
52 } else {
53 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
54 }
55
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080056 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +000057 ALOGE("Unable to initialize font %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070058 return false;
59 }
60
Jason Sams48ecf6a2013-07-09 15:35:29 -070061 mFontName = rsuCopyString(name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070062 mFontSize = fontSize;
63 mDpi = dpi;
64
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080065 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080066 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +000067 ALOGE("Unable to set font size on %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070068 return false;
69 }
70
71 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070072
73 mInitialized = true;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070074#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070075 return true;
76}
77
Jason Sams2e8665d2011-01-27 00:14:13 -080078void Font::preDestroy() const {
79 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
80 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
81 mRSC->mStateFont.mActiveFonts.removeAt(ct);
82 break;
83 }
84 }
85}
86
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080087void Font::invalidateTextureCache() {
88 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070089 mCachedGlyphs.valueAt(i)->mIsValid = false;
90 }
91}
92
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080093void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070094 FontState *state = &mRSC->mStateFont;
95
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070096 int32_t nPenX = x + glyph->mBitmapLeft;
97 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070098
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070099 float u1 = glyph->mBitmapMinU;
100 float u2 = glyph->mBitmapMaxU;
101 float v1 = glyph->mBitmapMinV;
102 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700103
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700104 int32_t width = (int32_t) glyph->mBitmapWidth;
105 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700106
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700107 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
108 nPenX + width, nPenY, 0, u2, v2,
109 nPenX + width, nPenY - height, 0, u2, v1,
110 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700111}
112
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700113void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
114 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
115 int32_t nPenX = x + glyph->mBitmapLeft;
116 int32_t nPenY = y + glyph->mBitmapTop;
117
118 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
119 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
120
121 FontState *state = &mRSC->mStateFont;
122 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
Jason Samsa6dd8232012-07-25 19:33:43 -0700123 const uint8_t* cacheBuffer = state->mCacheBuffer;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700124
125 uint32_t cacheX = 0, cacheY = 0;
126 int32_t bX = 0, bY = 0;
127 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
128 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
129 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000130 ALOGE("Skipping invalid index");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700131 continue;
132 }
133 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
134 bitmap[bY * bitmapW + bX] = tempCol;
135 }
136 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700137}
138
139void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
140 int32_t nPenX = x + glyph->mBitmapLeft;
141 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
142
143 int32_t width = (int32_t) glyph->mBitmapWidth;
144 int32_t height = (int32_t) glyph->mBitmapHeight;
145
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800146 // 0, 0 is top left, so bottom is a positive number
147 if (bounds->bottom < nPenY) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700148 bounds->bottom = nPenY;
149 }
150 if (bounds->left > nPenX) {
151 bounds->left = nPenX;
152 }
153 if (bounds->right < nPenX + width) {
154 bounds->right = nPenX + width;
155 }
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800156 if (bounds->top > nPenY - height) {
157 bounds->top = nPenY - height;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700158 }
159}
160
161void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
162 uint32_t start, int32_t numGlyphs,
163 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800164 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
165 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700166 return;
167 }
168
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800169 if (mode == Font::MEASURE) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700170 if (bounds == NULL) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000171 ALOGE("No return rectangle provided to measure text");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700172 return;
173 }
174 // Reset min and max of the bounding box to something large
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800175 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700176 }
177
178 int32_t penX = x, penY = y;
179 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800180 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700181 glyphsLeft = numGlyphs;
182 }
183
184 size_t index = start;
185 size_t nextIndex = 0;
186
187 while (glyphsLeft > 0) {
188
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800189 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700190
191 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800192 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700193 break;
194 }
195
196 // Move to the next character in the array
197 index = nextIndex;
198
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700199 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700200
201 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800202 if (cachedGlyph->mIsValid) {
203 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700204 case FRAMEBUFFER:
205 drawCachedGlyph(cachedGlyph, penX, penY);
206 break;
207 case BITMAP:
208 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
209 break;
210 case MEASURE:
211 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
212 break;
213 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700214 }
215
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800216 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700217
218 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800219 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700220 glyphsLeft --;
221 }
222 }
223}
224
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700225Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
226
227 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800228 if (cachedGlyph == NULL) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700229 cachedGlyph = cacheGlyph((uint32_t)utfChar);
230 }
231 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800232 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700233 updateGlyphCache(cachedGlyph);
234 }
235
236 return cachedGlyph;
237}
238
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800239void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700240#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700241 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800242 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000243 ALOGE("Couldn't load glyph.");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700244 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700245 }
246
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800247 glyph->mAdvanceX = mFace->glyph->advance.x;
248 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700249 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
250 glyph->mBitmapTop = mFace->glyph->bitmap_top;
251
252 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
253
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700254 // Now copy the bitmap into the cache texture
255 uint32_t startX = 0;
256 uint32_t startY = 0;
257
258 // Let the font state figure out where to put the bitmap
259 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700260 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700261
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800262 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700263 return;
264 }
265
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700266 uint32_t endX = startX + bitmap->width;
267 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700268
269 glyph->mBitmapMinX = startX;
270 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700271 glyph->mBitmapWidth = bitmap->width;
272 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700273
274 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
275 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
276
277 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
278 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
279 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
280 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700281#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700282}
283
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800284Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700285 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
286 mCachedGlyphs.add(glyph, newGlyph);
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700287#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700288 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
289 newGlyph->mIsValid = false;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700290#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700291 updateGlyphCache(newGlyph);
292
293 return newGlyph;
294}
295
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800296Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
297 const void *data, uint32_t dataLen) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700298 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700299 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
300
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800301 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700302 Font *ithFont = activeFonts[i];
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800303 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700304 return ithFont;
305 }
306 }
307
308 Font *newFont = new Font(rsc);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800309 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800310 if (isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700311 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700312 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700313 return newFont;
314 }
315
Jason Sams225afd32010-10-21 14:06:55 -0700316 ObjectBase::checkDelete(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700317 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700318}
319
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800320Font::~Font() {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700321#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800322 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700323 FT_Done_Face(mFace);
324 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700325#endif
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700326
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800327 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700328 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700329 delete glyph;
330 }
331}
332
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800333FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700334 mInitialized = false;
335 mMaxNumberOfQuads = 1024;
336 mCurrentQuadIndex = 0;
337 mRSC = NULL;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700338#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700339 mLibrary = NULL;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700340#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700341
Nick Kralevich7e85ca22013-05-22 15:04:39 -0700342 float gamma = DEFAULT_TEXT_GAMMA;
343 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
344 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
345
346#ifdef HAVE_ANDROID_OS
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700347 // Get the renderer properties
348 char property[PROPERTY_VALUE_MAX];
349
350 // Get the gamma
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700351 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700352 gamma = atof(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700353 }
354
355 // Get the black gamma threshold
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700356 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700357 blackThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700358 }
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700359
360 // Get the white gamma threshold
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700361 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700362 whiteThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700363 }
Nick Kralevich7e85ca22013-05-22 15:04:39 -0700364#endif
365
366 mBlackThreshold = (float)(blackThreshold) / 255.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700367 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
368
369 // Compute the gamma tables
370 mBlackGamma = gamma;
371 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700372
373 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700374}
375
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800376FontState::~FontState() {
377 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700378 delete mCacheLines[i];
379 }
380
381 rsAssert(!mActiveFonts.size());
382}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700383#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800384FT_Library FontState::getLib() {
385 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700386 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800387 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000388 ALOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700389 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700390 }
391 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700392
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700393 return mLibrary;
394}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700395#endif //ANDROID_RS_SERIALIZE
396
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700397
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800398void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700399 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700400}
401
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800402void FontState::flushAllAndInvalidate() {
403 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700404 issueDrawCommand();
405 mCurrentQuadIndex = 0;
406 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800407 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700408 mActiveFonts[i]->invalidateTextureCache();
409 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800410 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700411 mCacheLines[i]->mCurrentCol = 0;
412 }
413}
414
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700415#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800416bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700417 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800418 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000419 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 -0700420 return false;
421 }
422
423 // Now copy the bitmap into the cache texture
424 uint32_t startX = 0;
425 uint32_t startY = 0;
426
427 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800428 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700429 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800430 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700431 break;
432 }
433 }
434
435 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800436 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700437 flushAllAndInvalidate();
438
439 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800440 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700441 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800442 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700443 break;
444 }
445 }
446
447 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800448 if (!bitmapFit) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000449 ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700450 return false;
451 }
452 }
453
454 *retOriginX = startX;
455 *retOriginY = startY;
456
457 uint32_t endX = startX + bitmap->width;
458 uint32_t endY = startY + bitmap->rows;
459
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700460 uint32_t cacheWidth = getCacheTextureType()->getDimX();
461
Jason Samsa6dd8232012-07-25 19:33:43 -0700462 uint8_t *cacheBuffer = mCacheBuffer;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700463 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700464
465 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800466 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
467 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700468 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700469 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
470 }
471 }
472
473 // This will dirty the texture and the shader so next time
474 // we draw it will upload the data
Jason Samseb4fe182011-05-26 16:33:01 -0700475
Jason Samsa6dd8232012-07-25 19:33:43 -0700476 mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
477 RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
Tim Murray358747a2012-11-26 13:52:04 -0800478 mCacheBuffer, mCacheWidth*mCacheHeight, mCacheWidth);
Jason Samsa6dd8232012-07-25 19:33:43 -0700479
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700480 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700481
482 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800483 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000484 ALOGE("Cache Line: H: %u Empty Space: %f",
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700485 mCacheLines[i]->mMaxHeight,
486 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
487
488 }*/
489
490 return true;
491}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700492#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700493
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800494void FontState::initRenderState() {
Jason Sams48ecf6a2013-07-09 15:35:29 -0700495 const char *shaderString = "varying vec2 varTex0;\n"
496 "void main() {\n"
497 " lowp vec4 col = UNI_Color;\n"
498 " col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"
499 " col.a = pow(col.a, UNI_Gamma);\n"
500 " gl_FragColor = col;\n"
501 "}\n";
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700502
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800503 const char *textureNames[] = { "Tex0" };
504 const size_t textureNamesLengths[] = { 4 };
505 size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
506
507 ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
508 RS_KIND_USER, false, 4);
509 ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
510 RS_KIND_USER, false, 1);
Jason Samsf313dc32013-07-09 14:29:39 -0700511
512 const char *ebn1[] = { "Color", "Gamma" };
513 const Element *ebe1[] = {colorElem.get(), gammaElem.get()};
514 ObjectBaseRef<const Element> constInput = Element::create(mRSC, 2, ebe1, ebn1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700515
Jason Samsa572aca2013-01-09 11:52:26 -0800516 ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false, 0);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700517
518 uint32_t tmp[4];
519 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700520 tmp[1] = (uint32_t)inputType.get();
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800521 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
522 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700523
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700524 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800525 RS_ALLOCATION_USAGE_SCRIPT |
526 RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Jason Sams48ecf6a2013-07-09 15:35:29 -0700527 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800528 textureNames, numTextures, textureNamesLengths,
529 tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700530 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700531 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700532
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700533 mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800534 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
535 RS_SAMPLER_CLAMP).get());
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700536 mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700537
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700538 mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
539 false, false,
540 RS_BLEND_SRC_SRC_ALPHA,
541 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
542 RS_DEPTH_FUNC_ALWAYS).get());
Jason Sams8feea4e2011-03-18 15:03:25 -0700543 mFontProgramStore->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700544}
545
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800546void FontState::initTextTexture() {
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800547 ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
548 RS_KIND_PIXEL_A, true, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700549
550 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsa6dd8232012-07-25 19:33:43 -0700551 mCacheHeight = 256;
552 mCacheWidth = 1024;
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800553 ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
Jason Samsa572aca2013-01-09 11:52:26 -0800554 mCacheWidth, mCacheHeight, 0, false, false, 0);
Jason Samsa6dd8232012-07-25 19:33:43 -0700555 mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
556
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700557
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700558 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
Jason Samsa6dd8232012-07-25 19:33:43 -0700559 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700560 mTextTexture.set(cacheAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700561
562 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700563 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700564 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
565 nextLine += mCacheLines.top()->mMaxHeight;
566 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
567 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700568 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
569 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700570 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
571 nextLine += mCacheLines.top()->mMaxHeight;
572 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
573 nextLine += mCacheLines.top()->mMaxHeight;
574 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
575 nextLine += mCacheLines.top()->mMaxHeight;
576 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
577}
578
579// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800580void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700581 // Now lets write index data
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700582 ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700583 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsa572aca2013-01-09 11:52:26 -0800584 ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false, 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700585
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700586 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700587 RS_ALLOCATION_USAGE_SCRIPT |
588 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Jason Samsa6dd8232012-07-25 19:33:43 -0700589 uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700590
591 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800592 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700593 int32_t i6 = i * 6;
594 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700595
596 indexPtr[i6 + 0] = i4 + 0;
597 indexPtr[i6 + 1] = i4 + 1;
598 indexPtr[i6 + 2] = i4 + 2;
599
600 indexPtr[i6 + 3] = i4 + 0;
601 indexPtr[i6 + 4] = i4 + 2;
602 indexPtr[i6 + 5] = i4 + 3;
603 }
604
Jason Samseb4fe182011-05-26 16:33:01 -0700605 indexAlloc->sendDirty(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700606
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700607 ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
608 ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700609
Jason Samsf313dc32013-07-09 14:29:39 -0700610 const char *ebn1[] = { "position", "texture0" };
611 const Element *ebe1[] = {posElem.get(), texElem.get()};
612 ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700613
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700614 ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
615 mMaxNumberOfQuads * 4,
Jason Samsa572aca2013-01-09 11:52:26 -0800616 0, 0, false, false, 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700617
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700618 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700619 RS_ALLOCATION_USAGE_SCRIPT);
Jason Samsa6dd8232012-07-25 19:33:43 -0700620 mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700621
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700622 mMesh.set(new Mesh(mRSC, 1, 1));
623 mMesh->setVertexBuffer(vertexAlloc, 0);
624 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
625 mMesh->init();
Jason Samsa6dd8232012-07-25 19:33:43 -0700626 mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
627 mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700628}
629
630// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800631void FontState::checkInit() {
632 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700633 return;
634 }
635
636 initTextTexture();
637 initRenderState();
638
639 initVertexArrayBuffers();
640
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700641 // We store a string with letters in a rough frequency of occurrence
Jason Samsa7f5e042013-07-08 16:46:18 -0700642 mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
643 "EISARNTOLCDUGPMHBYFVKWZXJQ"
644 ",.?!()-+@;:`'0123456789";
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700645 mInitialized = true;
646}
647
648void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800649 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700650
Jason Sams60709252010-11-17 15:29:32 -0800651 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
652 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
653 mRSC->setProgramFragment(mFontShaderF.get());
654 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700655
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800656 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800657 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700658 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700659 }
660
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700661 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700662 return;
663 }
664
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700665 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700666}
667
668void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800669 float u1, float v1,
670 float x2, float y2, float z2,
671 float u2, float v2,
672 float x3, float y3, float z3,
673 float u3, float v3,
674 float x4, float y4, float z4,
675 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700676 const uint32_t vertsPerQuad = 4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800677 const uint32_t floatsPerVert = 6;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700678 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
679
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800680 if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700681 return;
682 }
683
684 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
Steve Blockaf12ac62012-01-06 19:20:56 +0000685 ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
686 ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
687 ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700688
689 (*currentPos++) = x1;
690 (*currentPos++) = y1;
691 (*currentPos++) = z1;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800692 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700693 (*currentPos++) = u1;
694 (*currentPos++) = v1;
695
696 (*currentPos++) = x2;
697 (*currentPos++) = y2;
698 (*currentPos++) = z2;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800699 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700700 (*currentPos++) = u2;
701 (*currentPos++) = v2;
702
703 (*currentPos++) = x3;
704 (*currentPos++) = y3;
705 (*currentPos++) = z3;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800706 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700707 (*currentPos++) = u3;
708 (*currentPos++) = v3;
709
710 (*currentPos++) = x4;
711 (*currentPos++) = y4;
712 (*currentPos++) = z4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800713 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700714 (*currentPos++) = u4;
715 (*currentPos++) = v4;
716
717 mCurrentQuadIndex ++;
718
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800719 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700720 issueDrawCommand();
721 mCurrentQuadIndex = 0;
722 }
723}
724
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700725uint32_t FontState::getRemainingCacheCapacity() {
726 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700727 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800728 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700729 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
730 totalPixels += mCacheLines[i]->mMaxWidth;
731 }
732 remainingCapacity = (remainingCapacity * 100) / totalPixels;
733 return remainingCapacity;
734}
735
736void FontState::precacheLatin(Font *font) {
737 // Remaining capacity is measured in %
738 uint32_t remainingCapacity = getRemainingCacheCapacity();
739 uint32_t precacheIdx = 0;
Jason Samsa7f5e042013-07-08 16:46:18 -0700740 const size_t l = strlen(mLatinPrecache);
741 while ((remainingCapacity > 25) && (precacheIdx < l)) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700742 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
743 remainingCapacity = getRemainingCacheCapacity();
744 precacheIdx ++;
745 }
746}
747
748
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700749void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
750 uint32_t startIndex, int32_t numGlyphs,
751 Font::RenderMode mode,
752 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800753 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700754 checkInit();
755
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700756 // Render code here
757 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800758 if (!currentFont) {
759 if (!mDefault.get()) {
Jason Sams48ecf6a2013-07-09 15:35:29 -0700760 char fullPath[1024];
761 const char * root = getenv("ANDROID_ROOT");
762 rsAssert(strlen(root) < 256);
763 strcpy(fullPath, root);
764 strcat(fullPath, "/fonts/Roboto-Regular.ttf");
765 mDefault.set(Font::create(mRSC, fullPath, 8, mRSC->getDPI()));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700766 }
767 currentFont = mDefault.get();
768 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800769 if (!currentFont) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000770 ALOGE("Unable to initialize any fonts");
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700771 return;
772 }
773
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800774 // Cull things that are off the screen
775 mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
776 mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
777
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700778 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
779 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700780
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800781 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700782 issueDrawCommand();
783 mCurrentQuadIndex = 0;
784 }
785}
786
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700787void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
788 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800789 bounds->bottom = - bounds->bottom;
790 bounds->top = - bounds->top;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700791}
792
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700793void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700794 mConstants.mFontColor[0] = r;
795 mConstants.mFontColor[1] = g;
796 mConstants.mFontColor[2] = b;
797 mConstants.mFontColor[3] = a;
798
799 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700800 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700801 if (luminance <= mBlackThreshold) {
802 mConstants.mGamma = mBlackGamma;
803 } else if (luminance >= mWhiteThreshold) {
804 mConstants.mGamma = mWhiteGamma;
805 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700806
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700807 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700808}
809
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700810void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700811 *r = mConstants.mFontColor[0];
812 *g = mConstants.mFontColor[1];
813 *b = mConstants.mFontColor[2];
814 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700815}
816
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800817void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700818 mInitialized = false;
819
Stephen Hines01b7d292010-09-28 15:45:45 -0700820 mFontShaderFConstant.clear();
821
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700822 mMesh.clear();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700823
824 mFontShaderF.clear();
825 mFontSampler.clear();
826 mFontProgramStore.clear();
827
828 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800829 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700830 delete mCacheLines[i];
831 }
832 mCacheLines.clear();
833
834 mDefault.clear();
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700835#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800836 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700837 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700838 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700839 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700840#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700841}
842
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700843#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800844bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
845 if ((uint32_t)bitmap->rows > mMaxHeight) {
846 return false;
847 }
848
849 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
850 *retOriginX = mCurrentCol;
851 *retOriginY = mCurrentRow;
852 mCurrentCol += bitmap->width;
853 mDirty = true;
854 return true;
855 }
856
857 return false;
858}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700859#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800860
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700861namespace android {
862namespace renderscript {
863
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700864RsFont rsi_FontCreateFromFile(Context *rsc,
865 char const *name, size_t name_length,
866 float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700867 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800868 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700869 newFont->incUserRef();
870 }
871 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700872}
873
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700874RsFont rsi_FontCreateFromMemory(Context *rsc,
875 char const *name, size_t name_length,
876 float fontSize, uint32_t dpi,
877 const void *data, size_t data_length) {
878 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800879 if (newFont) {
880 newFont->incUserRef();
881 }
882 return newFont;
883}
884
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700885} // renderscript
886} // android