blob: b625504dc2a04e30bdcafeb53ab816a60f3eabc9 [file] [log] [blame]
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -07001
2/*
3 * Copyright (C) 2009 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070018#include "rsContext.h"
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070019
20#include "rsFont.h"
21#include "rsProgramFragment.h"
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -070022#include <cutils/properties.h>
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080023
24#include <ft2build.h>
25#include FT_FREETYPE_H
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070026#include FT_BITMAP_H
27
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070028using namespace android;
29using namespace android::renderscript;
30
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080031Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070032 mInitialized = false;
33 mHasKerning = false;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -070034 mFace = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070035}
36
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080037bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080038 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070039 LOGE("Reinitialization of fonts not supported");
40 return false;
41 }
42
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080043 FT_Error error = 0;
44 if (data != NULL && dataLen > 0) {
45 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
46 } else {
47 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
48 }
49
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080050 if (error) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080051 LOGE("Unable to initialize font %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070052 return false;
53 }
54
55 mFontName = name;
56 mFontSize = fontSize;
57 mDpi = dpi;
58
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080059 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080060 if (error) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080061 LOGE("Unable to set font size on %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070062 return false;
63 }
64
65 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070066
67 mInitialized = true;
68 return true;
69}
70
Jason Sams2e8665d2011-01-27 00:14:13 -080071void Font::preDestroy() const {
72 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
73 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
74 mRSC->mStateFont.mActiveFonts.removeAt(ct);
75 break;
76 }
77 }
78}
79
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080080void Font::invalidateTextureCache() {
81 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070082 mCachedGlyphs.valueAt(i)->mIsValid = false;
83 }
84}
85
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080086void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070087 FontState *state = &mRSC->mStateFont;
88
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070089 int32_t nPenX = x + glyph->mBitmapLeft;
90 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070091
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070092 float u1 = glyph->mBitmapMinU;
93 float u2 = glyph->mBitmapMaxU;
94 float v1 = glyph->mBitmapMinV;
95 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070096
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070097 int32_t width = (int32_t) glyph->mBitmapWidth;
98 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070099
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700100 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
101 nPenX + width, nPenY, 0, u2, v2,
102 nPenX + width, nPenY - height, 0, u2, v1,
103 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700104}
105
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700106void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
107 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
108 int32_t nPenX = x + glyph->mBitmapLeft;
109 int32_t nPenY = y + glyph->mBitmapTop;
110
111 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
112 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
113
114 FontState *state = &mRSC->mStateFont;
115 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
116 const uint8_t* cacheBuffer = state->getTextTextureData();
117
118 uint32_t cacheX = 0, cacheY = 0;
119 int32_t bX = 0, bY = 0;
120 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
121 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
122 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
123 LOGE("Skipping invalid index");
124 continue;
125 }
126 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
127 bitmap[bY * bitmapW + bX] = tempCol;
128 }
129 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700130}
131
132void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
133 int32_t nPenX = x + glyph->mBitmapLeft;
134 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
135
136 int32_t width = (int32_t) glyph->mBitmapWidth;
137 int32_t height = (int32_t) glyph->mBitmapHeight;
138
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800139 // 0, 0 is top left, so bottom is a positive number
140 if (bounds->bottom < nPenY) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700141 bounds->bottom = nPenY;
142 }
143 if (bounds->left > nPenX) {
144 bounds->left = nPenX;
145 }
146 if (bounds->right < nPenX + width) {
147 bounds->right = nPenX + width;
148 }
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800149 if (bounds->top > nPenY - height) {
150 bounds->top = nPenY - height;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700151 }
152}
153
154void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
155 uint32_t start, int32_t numGlyphs,
156 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800157 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
158 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700159 return;
160 }
161
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800162 if (mode == Font::MEASURE) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700163 if (bounds == NULL) {
164 LOGE("No return rectangle provided to measure text");
165 return;
166 }
167 // Reset min and max of the bounding box to something large
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800168 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700169 }
170
171 int32_t penX = x, penY = y;
172 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800173 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700174 glyphsLeft = numGlyphs;
175 }
176
177 size_t index = start;
178 size_t nextIndex = 0;
179
180 while (glyphsLeft > 0) {
181
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800182 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700183
184 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800185 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700186 break;
187 }
188
189 // Move to the next character in the array
190 index = nextIndex;
191
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700192 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700193
194 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800195 if (cachedGlyph->mIsValid) {
196 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700197 case FRAMEBUFFER:
198 drawCachedGlyph(cachedGlyph, penX, penY);
199 break;
200 case BITMAP:
201 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
202 break;
203 case MEASURE:
204 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
205 break;
206 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700207 }
208
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800209 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700210
211 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800212 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700213 glyphsLeft --;
214 }
215 }
216}
217
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700218Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
219
220 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800221 if (cachedGlyph == NULL) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700222 cachedGlyph = cacheGlyph((uint32_t)utfChar);
223 }
224 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800225 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700226 updateGlyphCache(cachedGlyph);
227 }
228
229 return cachedGlyph;
230}
231
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800232void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700233 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800234 if (error) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700235 LOGE("Couldn't load glyph.");
236 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700237 }
238
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800239 glyph->mAdvanceX = mFace->glyph->advance.x;
240 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700241 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
242 glyph->mBitmapTop = mFace->glyph->bitmap_top;
243
244 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
245
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700246 // Now copy the bitmap into the cache texture
247 uint32_t startX = 0;
248 uint32_t startY = 0;
249
250 // Let the font state figure out where to put the bitmap
251 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700252 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700253
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800254 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700255 return;
256 }
257
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700258 uint32_t endX = startX + bitmap->width;
259 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700260
261 glyph->mBitmapMinX = startX;
262 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700263 glyph->mBitmapWidth = bitmap->width;
264 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700265
266 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
267 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
268
269 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
270 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
271 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
272 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
273}
274
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800275Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700276 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
277 mCachedGlyphs.add(glyph, newGlyph);
278
279 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
280 newGlyph->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700281
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700282 updateGlyphCache(newGlyph);
283
284 return newGlyph;
285}
286
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800287Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
288 const void *data, uint32_t dataLen) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700289 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700290 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
291
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800292 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700293 Font *ithFont = activeFonts[i];
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800294 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700295 return ithFont;
296 }
297 }
298
299 Font *newFont = new Font(rsc);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800300 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800301 if (isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700302 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700303 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700304 return newFont;
305 }
306
Jason Sams225afd32010-10-21 14:06:55 -0700307 ObjectBase::checkDelete(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700308 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700309}
310
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800311Font::~Font() {
312 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700313 FT_Done_Face(mFace);
314 }
315
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800316 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700317 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700318 delete glyph;
319 }
320}
321
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800322FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700323 mInitialized = false;
324 mMaxNumberOfQuads = 1024;
325 mCurrentQuadIndex = 0;
326 mRSC = NULL;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700327 mLibrary = NULL;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700328
329 // Get the renderer properties
330 char property[PROPERTY_VALUE_MAX];
331
332 // Get the gamma
333 float gamma = DEFAULT_TEXT_GAMMA;
334 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700335 gamma = atof(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700336 }
337
338 // Get the black gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700339 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700340 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700341 blackThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700342 }
343 mBlackThreshold = (float)(blackThreshold) / 255.0f;
344
345 // Get the white gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700346 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700347 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700348 whiteThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700349 }
350 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
351
352 // Compute the gamma tables
353 mBlackGamma = gamma;
354 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700355
356 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700357}
358
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800359FontState::~FontState() {
360 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700361 delete mCacheLines[i];
362 }
363
364 rsAssert(!mActiveFonts.size());
365}
366
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800367FT_Library FontState::getLib() {
368 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700369 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800370 if (error) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700371 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700372 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700373 }
374 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700375
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700376 return mLibrary;
377}
378
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800379void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700380 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700381}
382
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800383void FontState::flushAllAndInvalidate() {
384 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700385 issueDrawCommand();
386 mCurrentQuadIndex = 0;
387 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800388 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700389 mActiveFonts[i]->invalidateTextureCache();
390 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800391 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700392 mCacheLines[i]->mCurrentCol = 0;
393 }
394}
395
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800396bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700397 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800398 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700399 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
400 return false;
401 }
402
403 // Now copy the bitmap into the cache texture
404 uint32_t startX = 0;
405 uint32_t startY = 0;
406
407 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800408 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700409 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800410 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700411 break;
412 }
413 }
414
415 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800416 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700417 flushAllAndInvalidate();
418
419 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800420 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700421 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800422 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700423 break;
424 }
425 }
426
427 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800428 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700429 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
430 return false;
431 }
432 }
433
434 *retOriginX = startX;
435 *retOriginY = startY;
436
437 uint32_t endX = startX + bitmap->width;
438 uint32_t endY = startY + bitmap->rows;
439
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700440 uint32_t cacheWidth = getCacheTextureType()->getDimX();
441
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700442 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
443 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700444
445 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800446 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
447 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700448 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700449 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
450 }
451 }
452
453 // This will dirty the texture and the shader so next time
454 // we draw it will upload the data
Jason Samseb4fe182011-05-26 16:33:01 -0700455
456 mTextTexture->sendDirty(mRSC);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700457 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700458
459 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800460 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700461 LOGE("Cache Line: H: %u Empty Space: %f",
462 mCacheLines[i]->mMaxHeight,
463 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
464
465 }*/
466
467 return true;
468}
469
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800470void FontState::initRenderState() {
Alex Sakhartchouk7ffcaf22010-10-06 11:15:01 -0700471 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700472 shaderString.append("void main() {\n");
473 shaderString.append(" lowp vec4 col = UNI_Color;\n");
474 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700475 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700476 shaderString.append(" gl_FragColor = col;\n");
477 shaderString.append("}\n");
478
479 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700480 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700481 mRSC->mStateElement.elementBuilderBegin();
482 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700483 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700484 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
485
Jason Samsf0c1df42010-10-26 13:09:17 -0700486 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700487
488 uint32_t tmp[4];
489 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
490 tmp[1] = (uint32_t)inputType;
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800491 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
492 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700493
Jason Samseb4fe182011-05-26 16:33:01 -0700494 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType,
Jason Sams366c9c82010-12-08 16:14:36 -0800495 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700496 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
497 shaderString.length(), tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700498 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700499 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700500
501 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
502 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
503 mFontSampler.set(sampler);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700504 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700505
Jason Sams721acc42011-04-06 11:23:54 -0700506 ProgramStore *fontStore = new ProgramStore(mRSC, true, true, true, true,
507 false, false,
Jason Sams00237f12011-04-06 11:44:47 -0700508 RS_BLEND_SRC_SRC_ALPHA,
509 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
Jason Sams721acc42011-04-06 11:23:54 -0700510 RS_DEPTH_FUNC_ALWAYS);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700511 mFontProgramStore.set(fontStore);
Jason Sams8feea4e2011-03-18 15:03:25 -0700512 mFontProgramStore->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700513}
514
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800515void FontState::initTextTexture() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700516 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
517
518 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsf0c1df42010-10-26 13:09:17 -0700519 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700520
Jason Samseb4fe182011-05-26 16:33:01 -0700521 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType,
522 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700523 mTextTexture.set(cacheAlloc);
Jason Samsb7e83bd2010-12-15 01:41:00 -0800524 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700525
526 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700527 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700528 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
529 nextLine += mCacheLines.top()->mMaxHeight;
530 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
531 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700532 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
533 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700534 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
535 nextLine += mCacheLines.top()->mMaxHeight;
536 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
537 nextLine += mCacheLines.top()->mMaxHeight;
538 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
539 nextLine += mCacheLines.top()->mMaxHeight;
540 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
541}
542
543// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800544void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700545 // Now lets write index data
546 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700547 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsf0c1df42010-10-26 13:09:17 -0700548 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700549
Jason Samseb4fe182011-05-26 16:33:01 -0700550 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType,
551 RS_ALLOCATION_USAGE_SCRIPT |
552 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700553 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
554
555 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800556 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700557 int32_t i6 = i * 6;
558 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700559
560 indexPtr[i6 + 0] = i4 + 0;
561 indexPtr[i6 + 1] = i4 + 1;
562 indexPtr[i6 + 2] = i4 + 2;
563
564 indexPtr[i6 + 3] = i4 + 0;
565 indexPtr[i6 + 4] = i4 + 2;
566 indexPtr[i6 + 5] = i4 + 3;
567 }
568
Jason Samseb4fe182011-05-26 16:33:01 -0700569 indexAlloc->sendDirty(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700570
571 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
572 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
573
Alex Sakhartchouk64cd98e2010-10-18 17:18:50 -0700574 mRSC->mStateElement.elementBuilderBegin();
575 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
576 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
577 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700578
Jason Samsf0c1df42010-10-26 13:09:17 -0700579 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
580 mMaxNumberOfQuads * 4,
581 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700582
Jason Samseb4fe182011-05-26 16:33:01 -0700583 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType,
584 RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700585 mTextMeshPtr = (float*)vertexAlloc->getPtr();
586
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700587 mMesh.set(new Mesh(mRSC, 1, 1));
588 mMesh->setVertexBuffer(vertexAlloc, 0);
589 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
590 mMesh->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700591}
592
593// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800594void FontState::checkInit() {
595 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700596 return;
597 }
598
599 initTextTexture();
600 initRenderState();
601
602 initVertexArrayBuffers();
603
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700604 // We store a string with letters in a rough frequency of occurrence
605 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
606 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
607 mLatinPrecache += String8(",.?!()-+@;:`'");
608 mLatinPrecache += String8("0123456789");
609
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700610 mInitialized = true;
611}
612
613void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800614 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700615
Jason Sams60709252010-11-17 15:29:32 -0800616 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
617 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
618 mRSC->setProgramFragment(mFontShaderF.get());
619 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700620
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800621 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800622 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700623 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700624 }
625
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700626 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700627 return;
628 }
629
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700630 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700631}
632
633void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800634 float u1, float v1,
635 float x2, float y2, float z2,
636 float u2, float v2,
637 float x3, float y3, float z3,
638 float u3, float v3,
639 float x4, float y4, float z4,
640 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700641 const uint32_t vertsPerQuad = 4;
642 const uint32_t floatsPerVert = 5;
643 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
644
645 // Cull things that are off the screen
646 float width = (float)mRSC->getWidth();
647 float height = (float)mRSC->getHeight();
648
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800649 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700650 return;
651 }
652
653 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
654 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
655 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
656 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
657
658 (*currentPos++) = x1;
659 (*currentPos++) = y1;
660 (*currentPos++) = z1;
661 (*currentPos++) = u1;
662 (*currentPos++) = v1;
663
664 (*currentPos++) = x2;
665 (*currentPos++) = y2;
666 (*currentPos++) = z2;
667 (*currentPos++) = u2;
668 (*currentPos++) = v2;
669
670 (*currentPos++) = x3;
671 (*currentPos++) = y3;
672 (*currentPos++) = z3;
673 (*currentPos++) = u3;
674 (*currentPos++) = v3;
675
676 (*currentPos++) = x4;
677 (*currentPos++) = y4;
678 (*currentPos++) = z4;
679 (*currentPos++) = u4;
680 (*currentPos++) = v4;
681
682 mCurrentQuadIndex ++;
683
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800684 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700685 issueDrawCommand();
686 mCurrentQuadIndex = 0;
687 }
688}
689
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700690uint32_t FontState::getRemainingCacheCapacity() {
691 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700692 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800693 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700694 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
695 totalPixels += mCacheLines[i]->mMaxWidth;
696 }
697 remainingCapacity = (remainingCapacity * 100) / totalPixels;
698 return remainingCapacity;
699}
700
701void FontState::precacheLatin(Font *font) {
702 // Remaining capacity is measured in %
703 uint32_t remainingCapacity = getRemainingCacheCapacity();
704 uint32_t precacheIdx = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800705 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700706 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
707 remainingCapacity = getRemainingCacheCapacity();
708 precacheIdx ++;
709 }
710}
711
712
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700713void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
714 uint32_t startIndex, int32_t numGlyphs,
715 Font::RenderMode mode,
716 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800717 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700718 checkInit();
719
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700720 // Render code here
721 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800722 if (!currentFont) {
723 if (!mDefault.get()) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800724 String8 fontsDir("/fonts/DroidSans.ttf");
725 String8 fullPath(getenv("ANDROID_ROOT"));
726 fullPath += fontsDir;
727
Alex Sakhartchouk7b3e9bd2011-03-16 19:28:25 -0700728 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700729 }
730 currentFont = mDefault.get();
731 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800732 if (!currentFont) {
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700733 LOGE("Unable to initialize any fonts");
734 return;
735 }
736
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700737 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
738 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700739
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800740 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700741 issueDrawCommand();
742 mCurrentQuadIndex = 0;
743 }
744}
745
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700746void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
747 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800748 bounds->bottom = - bounds->bottom;
749 bounds->top = - bounds->top;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700750}
751
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700752void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700753 mConstants.mFontColor[0] = r;
754 mConstants.mFontColor[1] = g;
755 mConstants.mFontColor[2] = b;
756 mConstants.mFontColor[3] = a;
757
758 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700759 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700760 if (luminance <= mBlackThreshold) {
761 mConstants.mGamma = mBlackGamma;
762 } else if (luminance >= mWhiteThreshold) {
763 mConstants.mGamma = mWhiteGamma;
764 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700765
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700766 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700767}
768
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700769void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700770 *r = mConstants.mFontColor[0];
771 *g = mConstants.mFontColor[1];
772 *b = mConstants.mFontColor[2];
773 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700774}
775
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800776void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700777 mInitialized = false;
778
Stephen Hines01b7d292010-09-28 15:45:45 -0700779 mFontShaderFConstant.clear();
780
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700781 mMesh.clear();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700782
783 mFontShaderF.clear();
784 mFontSampler.clear();
785 mFontProgramStore.clear();
786
787 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800788 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700789 delete mCacheLines[i];
790 }
791 mCacheLines.clear();
792
793 mDefault.clear();
794
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800795 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700796 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700797 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700798 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700799}
800
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800801bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
802 if ((uint32_t)bitmap->rows > mMaxHeight) {
803 return false;
804 }
805
806 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
807 *retOriginX = mCurrentCol;
808 *retOriginY = mCurrentRow;
809 mCurrentCol += bitmap->width;
810 mDirty = true;
811 return true;
812 }
813
814 return false;
815}
816
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700817namespace android {
818namespace renderscript {
819
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700820RsFont rsi_FontCreateFromFile(Context *rsc,
821 char const *name, size_t name_length,
822 float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700823 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800824 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700825 newFont->incUserRef();
826 }
827 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700828}
829
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700830RsFont rsi_FontCreateFromMemory(Context *rsc,
831 char const *name, size_t name_length,
832 float fontSize, uint32_t dpi,
833 const void *data, size_t data_length) {
834 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800835 if (newFont) {
836 newFont->incUserRef();
837 }
838 return newFont;
839}
840
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700841} // renderscript
842} // android