blob: 5e47ddb175364c930365b93a7e9dbb6c073b4324 [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
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700455 mTextTexture->deferredUploadToTexture(mRSC);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700456 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700457
458 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800459 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700460 LOGE("Cache Line: H: %u Empty Space: %f",
461 mCacheLines[i]->mMaxHeight,
462 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
463
464 }*/
465
466 return true;
467}
468
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800469void FontState::initRenderState() {
Alex Sakhartchouk7ffcaf22010-10-06 11:15:01 -0700470 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700471 shaderString.append("void main() {\n");
472 shaderString.append(" lowp vec4 col = UNI_Color;\n");
473 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700474 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700475 shaderString.append(" gl_FragColor = col;\n");
476 shaderString.append("}\n");
477
478 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700479 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700480 mRSC->mStateElement.elementBuilderBegin();
481 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700482 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700483 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
484
Jason Samsf0c1df42010-10-26 13:09:17 -0700485 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700486
487 uint32_t tmp[4];
488 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
489 tmp[1] = (uint32_t)inputType;
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800490 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
491 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700492
Jason Sams366c9c82010-12-08 16:14:36 -0800493 mFontShaderFConstant.set(new Allocation(mRSC, inputType,
494 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700495 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
496 shaderString.length(), tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700497 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700498 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700499
500 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
501 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
502 mFontSampler.set(sampler);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700503 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700504
Jason Sams721acc42011-04-06 11:23:54 -0700505 ProgramStore *fontStore = new ProgramStore(mRSC, true, true, true, true,
506 false, false,
Jason Sams00237f12011-04-06 11:44:47 -0700507 RS_BLEND_SRC_SRC_ALPHA,
508 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
Jason Sams721acc42011-04-06 11:23:54 -0700509 RS_DEPTH_FUNC_ALWAYS);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700510 mFontProgramStore.set(fontStore);
Jason Sams8feea4e2011-03-18 15:03:25 -0700511 mFontProgramStore->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700512}
513
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800514void FontState::initTextTexture() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700515 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
516
517 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsf0c1df42010-10-26 13:09:17 -0700518 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700519
Jason Sams366c9c82010-12-08 16:14:36 -0800520 Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700521 mTextTexture.set(cacheAlloc);
Jason Samsb7e83bd2010-12-15 01:41:00 -0800522 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700523
524 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700525 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700526 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
527 nextLine += mCacheLines.top()->mMaxHeight;
528 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
529 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700530 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
531 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700532 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
533 nextLine += mCacheLines.top()->mMaxHeight;
534 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
535 nextLine += mCacheLines.top()->mMaxHeight;
536 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
537 nextLine += mCacheLines.top()->mMaxHeight;
538 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
539}
540
541// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800542void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700543 // Now lets write index data
544 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700545 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsf0c1df42010-10-26 13:09:17 -0700546 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700547
Jason Sams366c9c82010-12-08 16:14:36 -0800548 Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700549 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
550
551 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800552 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700553 int32_t i6 = i * 6;
554 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700555
556 indexPtr[i6 + 0] = i4 + 0;
557 indexPtr[i6 + 1] = i4 + 1;
558 indexPtr[i6 + 2] = i4 + 2;
559
560 indexPtr[i6 + 3] = i4 + 0;
561 indexPtr[i6 + 4] = i4 + 2;
562 indexPtr[i6 + 5] = i4 + 3;
563 }
564
Alex Sakhartchouk7d9c5ff2011-04-01 14:19:01 -0700565 indexAlloc->deferredUploadToBufferObject(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700566
567 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
568 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
569
Alex Sakhartchouk64cd98e2010-10-18 17:18:50 -0700570 mRSC->mStateElement.elementBuilderBegin();
571 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
572 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
573 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700574
Jason Samsf0c1df42010-10-26 13:09:17 -0700575 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
576 mMaxNumberOfQuads * 4,
577 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700578
Jason Sams366c9c82010-12-08 16:14:36 -0800579 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700580 mTextMeshPtr = (float*)vertexAlloc->getPtr();
581
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700582 mMesh.set(new Mesh(mRSC, 1, 1));
583 mMesh->setVertexBuffer(vertexAlloc, 0);
584 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
585 mMesh->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700586}
587
588// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800589void FontState::checkInit() {
590 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700591 return;
592 }
593
594 initTextTexture();
595 initRenderState();
596
597 initVertexArrayBuffers();
598
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700599 // We store a string with letters in a rough frequency of occurrence
600 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
601 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
602 mLatinPrecache += String8(",.?!()-+@;:`'");
603 mLatinPrecache += String8("0123456789");
604
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700605 mInitialized = true;
606}
607
608void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800609 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700610
Jason Sams60709252010-11-17 15:29:32 -0800611 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
612 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
613 mRSC->setProgramFragment(mFontShaderF.get());
614 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700615
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800616 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800617 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700618 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700619 }
620
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700621 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700622 return;
623 }
624
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700625 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700626}
627
628void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800629 float u1, float v1,
630 float x2, float y2, float z2,
631 float u2, float v2,
632 float x3, float y3, float z3,
633 float u3, float v3,
634 float x4, float y4, float z4,
635 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700636 const uint32_t vertsPerQuad = 4;
637 const uint32_t floatsPerVert = 5;
638 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
639
640 // Cull things that are off the screen
641 float width = (float)mRSC->getWidth();
642 float height = (float)mRSC->getHeight();
643
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800644 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700645 return;
646 }
647
648 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
649 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
650 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
651 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
652
653 (*currentPos++) = x1;
654 (*currentPos++) = y1;
655 (*currentPos++) = z1;
656 (*currentPos++) = u1;
657 (*currentPos++) = v1;
658
659 (*currentPos++) = x2;
660 (*currentPos++) = y2;
661 (*currentPos++) = z2;
662 (*currentPos++) = u2;
663 (*currentPos++) = v2;
664
665 (*currentPos++) = x3;
666 (*currentPos++) = y3;
667 (*currentPos++) = z3;
668 (*currentPos++) = u3;
669 (*currentPos++) = v3;
670
671 (*currentPos++) = x4;
672 (*currentPos++) = y4;
673 (*currentPos++) = z4;
674 (*currentPos++) = u4;
675 (*currentPos++) = v4;
676
677 mCurrentQuadIndex ++;
678
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800679 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700680 issueDrawCommand();
681 mCurrentQuadIndex = 0;
682 }
683}
684
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700685uint32_t FontState::getRemainingCacheCapacity() {
686 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700687 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800688 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700689 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
690 totalPixels += mCacheLines[i]->mMaxWidth;
691 }
692 remainingCapacity = (remainingCapacity * 100) / totalPixels;
693 return remainingCapacity;
694}
695
696void FontState::precacheLatin(Font *font) {
697 // Remaining capacity is measured in %
698 uint32_t remainingCapacity = getRemainingCacheCapacity();
699 uint32_t precacheIdx = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800700 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700701 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
702 remainingCapacity = getRemainingCacheCapacity();
703 precacheIdx ++;
704 }
705}
706
707
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700708void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
709 uint32_t startIndex, int32_t numGlyphs,
710 Font::RenderMode mode,
711 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800712 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700713 checkInit();
714
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700715 // Render code here
716 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800717 if (!currentFont) {
718 if (!mDefault.get()) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800719 String8 fontsDir("/fonts/DroidSans.ttf");
720 String8 fullPath(getenv("ANDROID_ROOT"));
721 fullPath += fontsDir;
722
Alex Sakhartchouk7b3e9bd2011-03-16 19:28:25 -0700723 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700724 }
725 currentFont = mDefault.get();
726 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800727 if (!currentFont) {
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700728 LOGE("Unable to initialize any fonts");
729 return;
730 }
731
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700732 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
733 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700734
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800735 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700736 issueDrawCommand();
737 mCurrentQuadIndex = 0;
738 }
739}
740
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700741void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
742 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800743 bounds->bottom = - bounds->bottom;
744 bounds->top = - bounds->top;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700745}
746
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700747void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700748 mConstants.mFontColor[0] = r;
749 mConstants.mFontColor[1] = g;
750 mConstants.mFontColor[2] = b;
751 mConstants.mFontColor[3] = a;
752
753 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700754 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700755 if (luminance <= mBlackThreshold) {
756 mConstants.mGamma = mBlackGamma;
757 } else if (luminance >= mWhiteThreshold) {
758 mConstants.mGamma = mWhiteGamma;
759 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700760
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700761 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700762}
763
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700764void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700765 *r = mConstants.mFontColor[0];
766 *g = mConstants.mFontColor[1];
767 *b = mConstants.mFontColor[2];
768 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700769}
770
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800771void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700772 mInitialized = false;
773
Stephen Hines01b7d292010-09-28 15:45:45 -0700774 mFontShaderFConstant.clear();
775
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700776 mMesh.clear();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700777
778 mFontShaderF.clear();
779 mFontSampler.clear();
780 mFontProgramStore.clear();
781
782 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800783 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700784 delete mCacheLines[i];
785 }
786 mCacheLines.clear();
787
788 mDefault.clear();
789
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800790 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700791 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700792 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700793 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700794}
795
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800796bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
797 if ((uint32_t)bitmap->rows > mMaxHeight) {
798 return false;
799 }
800
801 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
802 *retOriginX = mCurrentCol;
803 *retOriginY = mCurrentRow;
804 mCurrentCol += bitmap->width;
805 mDirty = true;
806 return true;
807 }
808
809 return false;
810}
811
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700812namespace android {
813namespace renderscript {
814
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700815RsFont rsi_FontCreateFromFile(Context *rsc,
816 char const *name, size_t name_length,
817 float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700818 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800819 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700820 newFont->incUserRef();
821 }
822 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700823}
824
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700825RsFont rsi_FontCreateFromMemory(Context *rsc,
826 char const *name, size_t name_length,
827 float fontSize, uint32_t dpi,
828 const void *data, size_t data_length) {
829 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800830 if (newFont) {
831 newFont->incUserRef();
832 }
833 return newFont;
834}
835
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700836} // renderscript
837} // android