blob: b625504dc2a04e30bdcafeb53ab816a60f3eabc9 [file] [log] [blame]
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -07001
2/*
3 * Copyright (C) 2009 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070018#include "rsContext.h"
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070019
20#include "rsFont.h"
21#include "rsProgramFragment.h"
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -070022#include <cutils/properties.h>
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -080023
24#include <ft2build.h>
25#include FT_FREETYPE_H
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070026#include FT_BITMAP_H
27
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070028using namespace android;
29using namespace android::renderscript;
30
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080031Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070032 mInitialized = false;
33 mHasKerning = false;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -070034 mFace = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070035}
36
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -080037bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080038 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070039 LOGE("Reinitialization of fonts not supported");
40 return false;
41 }
42
Alex Sakhartchoukb0253ea2011-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 Sakhartchouked9f2102010-11-09 17:00:54 -080050 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080051 LOGE("Unable to initialize font %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070052 return false;
53 }
54
55 mFontName = name;
56 mFontSize = fontSize;
57 mDpi = dpi;
58
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080059 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080060 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080061 LOGE("Unable to set font size on %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070062 return false;
63 }
64
65 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070066
67 mInitialized = true;
68 return true;
69}
70
Jason Sams38f8d9d2011-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 Sakhartchouked9f2102010-11-09 17:00:54 -080080void Font::invalidateTextureCache() {
81 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070082 mCachedGlyphs.valueAt(i)->mIsValid = false;
83 }
84}
85
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080086void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070087 FontState *state = &mRSC->mStateFont;
88
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070089 int32_t nPenX = x + glyph->mBitmapLeft;
90 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070091
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -070096
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070097 int32_t width = (int32_t) glyph->mBitmapWidth;
98 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070099
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700104}
105
Alex Sakhartchouk10825a02010-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 Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800139 // 0, 0 is top left, so bottom is a positive number
140 if (bounds->bottom < nPenY) {
Alex Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800149 if (bounds->top > nPenY - height) {
150 bounds->top = nPenY - height;
Alex Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700159 return;
160 }
161
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800162 if (mode == Font::MEASURE) {
Alex Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800168 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700169 }
170
171 int32_t penX = x, penY = y;
172 int32_t glyphsLeft = 1;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800173 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-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 Root300ba682010-11-09 14:37:23 -0800182 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700183
184 // Reached the end of the string or encountered
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800185 if (utfChar < 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700186 break;
187 }
188
189 // Move to the next character in the array
190 index = nextIndex;
191
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700192 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800195 if (cachedGlyph->mIsValid) {
196 switch (mode) {
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700207 }
208
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800209 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700210
211 // If we were given a specific number of glyphs, decrement
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800212 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700213 glyphsLeft --;
214 }
215 }
216}
217
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700218Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
219
220 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800221 if (cachedGlyph == NULL) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700222 cachedGlyph = cacheGlyph((uint32_t)utfChar);
223 }
224 // Is the glyph still in texture cache?
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800225 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700226 updateGlyphCache(cachedGlyph);
227 }
228
229 return cachedGlyph;
230}
231
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800232void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700233 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800234 if (error) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700235 LOGE("Couldn't load glyph.");
236 return;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700237 }
238
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800239 glyph->mAdvanceX = mFace->glyph->advance.x;
240 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouk071508d2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700252 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700253
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800254 if (!glyph->mIsValid) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700255 return;
256 }
257
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700258 uint32_t endX = startX + bitmap->width;
259 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700260
261 glyph->mBitmapMinX = startX;
262 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700263 glyph->mBitmapWidth = bitmap->width;
264 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800275Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700281
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700282 updateGlyphCache(newGlyph);
283
284 return newGlyph;
285}
286
Alex Sakhartchoukb0253ea2011-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 Sakhartchouk27f50522010-08-18 15:46:43 -0700289 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700290 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
291
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800292 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700293 Font *ithFont = activeFonts[i];
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800294 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700295 return ithFont;
296 }
297 }
298
299 Font *newFont = new Font(rsc);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800300 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800301 if (isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700302 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700303 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700304 return newFont;
305 }
306
Jason Samsb38d5342010-10-21 14:06:55 -0700307 ObjectBase::checkDelete(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700308 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700309}
310
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800311Font::~Font() {
312 if (mFace) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700313 FT_Done_Face(mFace);
314 }
315
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800316 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700317 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700318 delete glyph;
319 }
320}
321
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800322FontState::FontState() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700323 mInitialized = false;
324 mMaxNumberOfQuads = 1024;
325 mCurrentQuadIndex = 0;
326 mRSC = NULL;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700327 mLibrary = NULL;
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700335 gamma = atof(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700336 }
337
338 // Get the black gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700339 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700340 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700341 blackThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700342 }
343 mBlackThreshold = (float)(blackThreshold) / 255.0f;
344
345 // Get the white gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700346 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700347 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700348 whiteThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk960ae152010-10-12 14:15:17 -0700355
356 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700357}
358
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800359FontState::~FontState() {
360 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700361 delete mCacheLines[i];
362 }
363
364 rsAssert(!mActiveFonts.size());
365}
366
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800367FT_Library FontState::getLib() {
368 if (!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700369 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800370 if (error) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700371 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700372 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700373 }
374 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700375
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700376 return mLibrary;
377}
378
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800379void FontState::init(Context *rsc) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700380 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700381}
382
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800383void FontState::flushAllAndInvalidate() {
384 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700385 issueDrawCommand();
386 mCurrentQuadIndex = 0;
387 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800388 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700389 mActiveFonts[i]->invalidateTextureCache();
390 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800391 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700392 mCacheLines[i]->mCurrentCol = 0;
393 }
394}
395
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800396bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700397 // If the glyph is too tall, don't cache it
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800398 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800408 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700409 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800410 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800416 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700417 flushAllAndInvalidate();
418
419 // Try to fit it again
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800420 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700421 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800422 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800428 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700440 uint32_t cacheWidth = getCacheTextureType()->getDimX();
441
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700442 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
443 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700444
445 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchouked9f2102010-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 Sakhartchouk10825a02010-10-05 11:33:27 -0700448 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-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 Sams7e8aae72011-05-26 16:33:01 -0700455
456 mTextTexture->sendDirty(mRSC);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700457 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700458
459 // Some debug code
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800460 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800470void FontState::initRenderState() {
Alex Sakhartchoukd2091632010-10-06 11:15:01 -0700471 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700475 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700480 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700481 mRSC->mStateElement.elementBuilderBegin();
482 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700483 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700484 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
485
Jason Sams31a7e422010-10-26 13:09:17 -0700486 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-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 Sakhartchouk67f2e442010-11-18 15:22:43 -0800491 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
492 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700493
Jason Sams7e8aae72011-05-26 16:33:01 -0700494 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType,
Jason Sams5476b452010-12-08 16:14:36 -0800495 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700496 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
497 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700498 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700499 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-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 Sakhartchoukb89aaac2010-09-23 16:16:33 -0700504 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700505
Jason Sams331bf9b2011-04-06 11:23:54 -0700506 ProgramStore *fontStore = new ProgramStore(mRSC, true, true, true, true,
507 false, false,
Jason Samsbd184c52011-04-06 11:44:47 -0700508 RS_BLEND_SRC_SRC_ALPHA,
509 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
Jason Sams331bf9b2011-04-06 11:23:54 -0700510 RS_DEPTH_FUNC_ALWAYS);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700511 mFontProgramStore.set(fontStore);
Jason Sams48f50562011-03-18 15:03:25 -0700512 mFontProgramStore->init();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700513}
514
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800515void FontState::initTextTexture() {
Alex Sakhartchouk9b949fc2010-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 Sams31a7e422010-10-26 13:09:17 -0700519 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700520
Jason Sams7e8aae72011-05-26 16:33:01 -0700521 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType,
522 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700523 mTextTexture.set(cacheAlloc);
Jason Sams6d8eb262010-12-15 01:41:00 -0800524 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700525
526 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700527 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk94bbccc2010-08-17 11:09:49 -0700532 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
533 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800544void FontState::initVertexArrayBuffers() {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700547 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Sams31a7e422010-10-26 13:09:17 -0700548 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700549
Jason Sams7e8aae72011-05-26 16:33:01 -0700550 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType,
551 RS_ALLOCATION_USAGE_SCRIPT |
552 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700553 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
554
555 // Four verts, two triangles , six indices per quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800556 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700557 int32_t i6 = i * 6;
558 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-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 Sams7e8aae72011-05-26 16:33:01 -0700569 indexAlloc->sendDirty(mRSC);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk98bfe5d2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700578
Jason Sams31a7e422010-10-26 13:09:17 -0700579 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
580 mMaxNumberOfQuads * 4,
581 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700582
Jason Sams7e8aae72011-05-26 16:33:01 -0700583 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType,
584 RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700585 mTextMeshPtr = (float*)vertexAlloc->getPtr();
586
Alex Sakhartchouk4a36b452011-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700591}
592
593// We don't want to allocate anything unless we actually draw text
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800594void FontState::checkInit() {
595 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700596 return;
597 }
598
599 initTextTexture();
600 initRenderState();
601
602 initVertexArrayBuffers();
603
Alex Sakhartchouk27f50522010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700610 mInitialized = true;
611}
612
613void FontState::issueDrawCommand() {
Jason Samsa17af042010-11-17 15:29:32 -0800614 Context::PushState ps(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700615
Jason Samsa17af042010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700620
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800621 if (mConstantsDirty) {
Jason Sams49a05d72010-12-29 14:31:29 -0800622 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700623 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700624 }
625
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700626 if (!mRSC->setupCheck()) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700627 return;
628 }
629
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700630 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700631}
632
633void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchouked9f2102010-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 Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800649 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800684 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700685 issueDrawCommand();
686 mCurrentQuadIndex = 0;
687 }
688}
689
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700690uint32_t FontState::getRemainingCacheCapacity() {
691 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700692 uint32_t totalPixels = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800693 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk94bbccc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800705 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700706 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
707 remainingCapacity = getRemainingCacheCapacity();
708 precacheIdx ++;
709 }
710}
711
712
Alex Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800717 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700718 checkInit();
719
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700720 // Render code here
721 Font *currentFont = mRSC->getFont();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800722 if (!currentFont) {
723 if (!mDefault.get()) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800724 String8 fontsDir("/fonts/DroidSans.ttf");
725 String8 fullPath(getenv("ANDROID_ROOT"));
726 fullPath += fontsDir;
727
Alex Sakhartchouk2c74ad92011-03-16 19:28:25 -0700728 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700729 }
730 currentFont = mDefault.get();
731 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800732 if (!currentFont) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700733 LOGE("Unable to initialize any fonts");
734 return;
735 }
736
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700737 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
738 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700739
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800740 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700741 issueDrawCommand();
742 mCurrentQuadIndex = 0;
743 }
744}
745
Alex Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800748 bounds->bottom = - bounds->bottom;
749 bounds->top = - bounds->top;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700750}
751
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700752void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk76322af2010-10-05 13:23:55 -0700759 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700760 if (luminance <= mBlackThreshold) {
761 mConstants.mGamma = mBlackGamma;
762 } else if (luminance >= mWhiteThreshold) {
763 mConstants.mGamma = mWhiteGamma;
764 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700765
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700766 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700767}
768
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700769void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk55e81982010-08-05 11:24:14 -0700774}
775
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800776void FontState::deinit(Context *rsc) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700777 mInitialized = false;
778
Stephen Hines01f0ad72010-09-28 15:45:45 -0700779 mFontShaderFConstant.clear();
780
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700781 mMesh.clear();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700782
783 mFontShaderF.clear();
784 mFontSampler.clear();
785 mFontProgramStore.clear();
786
787 mTextTexture.clear();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800788 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700789 delete mCacheLines[i];
790 }
791 mCacheLines.clear();
792
793 mDefault.clear();
794
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800795 if (mLibrary) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700796 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700797 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700798 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700799}
800
Alex Sakhartchoukebd65bb2011-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700817namespace android {
818namespace renderscript {
819
Alex Sakhartchouke7c4a752011-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700823 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800824 if (newFont) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700825 newFont->incUserRef();
826 }
827 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700828}
829
Alex Sakhartchouke7c4a752011-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800835 if (newFont) {
836 newFont->incUserRef();
837 }
838 return newFont;
839}
840
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700841} // renderscript
842} // android